Ada: Ngôn ngữ "kẻ khổng lồ thầm lặng" và nền tảng cho lập trình hiện đại

17 tháng 4, 2026·11 phút đọc

Ada là ngôn ngữ lập trình do Bộ Quốc phòng Mỹ xây dựng, từng bị ngành công nghệ chối bỏ nhưng lại sở hữu những tính năng an toàn tiên phong. Mọi ngôn ngữ lập trình hiện đại từ Rust, Go đến Python đang dần hội tụ về các thiết kế cốt lõi mà Ada đã tiên phong từ những năm 1980.

Ada là một ngôn ngữ đặc biệt. Nó đã đưa generics (generic programming) trở thành tính năng chuẩn của một ngôn ngữ hệ thống phổ biến, chính thức hóa khái niệm package, tích hợp đồng thời hóa (concurrency) vào đặc tả kỹ thuật thay vì thư viện, bắt buộc tách biệt giao diện khỏi mã triển khai, và giới thiệu các kiểu dữ liệu bị giới hạn phạm vi, discriminated unions và mô hình truyền thông task mà Go mới chỉ đạt được ba mươi năm sau đó.

Các phiên bản sau này còn bổ sung thêm protected objects, loại trừ null tại thời điểm biên dịch và các hợp đồng ở cấp độ ngôn ngữ. Đây là ngôn ngữ mà Rust đã dành một thập kỷ để tiến hóa theo hướng của nó từ một phía, trong khi Python lại tiến hóa từ phía khác, và C# đã dần dần mô phỏng tính chất này trong suốt hai thập kỷ qua. Tuy nhiên, ngành công nghiệp phần mềm thường mô tả Ada là rườm rà, bí ẩn và không còn phù hợp. Nhưng thực tế, với một sự trực tiếp khiến câu chuyện về tiến trình phần mềm thông thường trở nên lu mờ, Ada chính là ngôn ngữ đã dự đoán — với độ chính xác bất thường — các tính năng an toàn mà mọi ngôn ngữ hiện đại ngày nay đang cố gắng sở hữu.

Ada không nổi tiếng. Nó không phải là chủ đề của các bài thuyết trình hào hứng hay các bài blog nhiệt thành. Nó không có một người sáng lập đầy uy tín thuyết trình về triết lý lập trình, và không có một cộng đồng viết các framework hay xuất bản các package với những cái tên thông minh. Những gì Ada có là một tiêu chuẩn chính thức đã được sửa đổi bốn lần kể từ năm 1983; sự hiện diện trong phần mềm của nhiều máy bay thương mại lớn và hệ thống hàng không; một tập hợp các quyết định thiết kế được thực hiện theo hợp đồng chính phủ vào cuối những năm 1970 mà phần còn lại của ngành công nghiệp đã dành bốn mươi năm để tự mình khám phá lại; và danh tiếng, trong số những lập trình viên biết về nó, là ngôn ngữ biết nói "không" — ngôn ngữ mà trình biên dịch của nó thực thi tính hợp pháp, khả năng hiển thị, kiểu dữ liệu và mức độ kiểm tra an toàn mà hầu hết các ngôn ngữ khác để lại theo quy ước hoặc công cụ bên ngoài.

Cuộc khủng hoảng phần mềm và sự ra đời của Ada

Để hiểu tại sao Ada tồn tại, cần hiểu cuộc khủng hoảng cụ thể đã sinh ra nó — một cuộc khủng hoảng không phải của khoa học máy tính mà là của mua sắm (procurement), mà Bộ Quốc phòng Hoa Kỳ gặp phải vào đầu những năm 1970. Khi khảo sát phần mềm chạy các hệ thống vũ khí, cơ sở hạ tầng hậu cần và bộ máy chỉ huy và kiểm soát, họ phát hiện ra sự hỗn loạn. Hơn 450 ngôn ngữ lập trình và phương ngữ khác nhau đang được sử dụng tích cực, mỗi ngôn ngữ gắn liền với một nhà thầu hoặc một thời kỳ phát triển cụ thể, không có ngôn ngữ nào có thể tương tác với ngôn ngữ nào, và phần lớn trong số đó không thể bảo trì bởi bất kỳ ai ngoại trừ tác giả gốc.

Phản ứng của Bộ Quốc phòng là vô cùng tinh tế. Thay vì đơn giản bắt buộc sử dụng một ngôn ngữ hiện có, họ đã tiến hành một quy trình yêu cầu kéo dài năm năm, tạo ra một loạt tài liệu với độ chính xác ngày càng cao: Strawman, Woodenman, Tinman, Ironman và cuối cùng là Steelman. Tài liệu Steelman được ban hành năm 1978 là một tác phẩm đáng kể về yêu cầu kỹ thuật: nó không chỉ định một ngôn ngữ, mà mô tả các thuộc tính mà một ngôn ngữ phải có — các thuộc tính được rút ra từ các chế độ thất bại thực tế của hệ thống phần mềm hiện hữu. Nó yêu cầu hệ thống module có sự tách biệt rõ ràng giữa giao diện và triển khai; kiểu tĩnh mạnh (strong static typing) không có chuyển đổi ngầm định; hỗ trợ tích hợp cho các tác vụ đồng thời; cơ chế xử lý ngoại lệ nhất quán; và yêu cầu ngôn ngữ phải độc lập với máy móc.

Kiến trúc gói (Package) và tính đóng gói

Trung tâm của kiến trúc Ada là package: một đơn vị biên dịch bao gồm một đặc tả (specification) và một phần thân (body), được tách biệt về mặt vật lý, với mối quan hệ giữa chúng được trình biên dịch thực thi. Đặc tả là hợp đồng — nó khai báo những gì package cung cấp. Phần thân là triển khai — nó cung cấp mã để thực hiện hợp đồng. Đặc tả là những gì mã khách hàng nhìn thấy. Phần thân vô hình đối với mã khách hàng và có thể được biên dịch độc lập.

Đây là hệ thống module mà mọi ngôn ngữ ra đời sau Ada đều cố gắng xây dựng. Các package của Java không giống như vậy; chúng là cơ chế không gian tên với bộ công cụ sửa đổi quyền truy cập, nhưng phần triển khai vẫn hiển thị với reflection. Các module của Python chỉ là các tệp, không có sự tách biệt hình thức. Trong Ada, phần triển khai của một kiểu private không chỉ là không thể truy cập, mà còn vắng mặt về mặt cú pháp khỏi góc nhìn của khách hàng. Không có gì để truy cập, phản chiếu hay lách luật.

Cơ chế kiểu private của Ada mang lại cho nó điều mà mọi ngôn ngữ khác mất hàng thập kỷ để đạt được. Một kiểu được khai báo private trong đặc tả package của Ada có thể nhìn thấy theo tên — mã khách hàng có thể khai báo biến của kiểu đó, truyền chúng cho chương trình con — nhưng cách biểu diễn của nó hoàn toàn mờ. Khách hàng không biết kiểu đó là bản ghi (record), mảng, số nguyên hay con trỏ. Thiết kế của package quyết định các thao tác nào tồn tại trên kiểu đó, và phần còn lại của thế giới chỉ sử dụng những thao tác đó.

Hệ thống kiểu dữ liệu vượt thời đại

Hệ thống kiểu của Ada vào năm 1983 khác với bất cứ thứ gì khác đang được sử dụng trong sản xuất. Sự phân biệt tổ chức nó là giữa kiểu và kiểu con (subtype) — không theo nghĩa hướng đối tượng mà là theo nghĩa toán học của một tập hợp bị ràng buộc. Một lập trình viên Ada cần một kiểu đại diện cho tuổi của một người sẽ không dùng int và thêm vào một bình luận. Họ sẽ viết type Age is range 0 .. 150. Trình biên dịch sẽ tạo ra một kiểu có các giá trị phải nằm trong phạm vi đó, và các phép toán số học sẽ được kiểm tra đối với phạm vi này tại thời gian chạy.

Đây không phải là một bước tiến nhỏ. Trong bối cảnh năm 1983, C có int, shortlong, phân biệt theo kích thước và dấu, không phải theo ý nghĩa. Ada's range types cho phép lập trình viên mã hóa ý nghĩa trực tiếp vào hệ thống kiểu. Các enum có data của Rust hay TypeScript chính là discriminated union (kiểu tổng), được triển khai với các đảm bảo của trình biên dịch giống như Ada cung cấp vào năm 1983.

Generics của Ada có lẽ là đóng góp có ảnh hưởng trực tiếp nhất nhưng ít được thừa nhận nhất. Một generic trong Ada là một package hoặc chương trình con được tham số hóa — một khuôn mẫu có thể được khởi tạo với các kiểu hoặc giá trị cụ thể để tạo ra một package hoặc chương trình con cụ thể. Ada có tính năng này vào năm 1983. C++ có templates từ khoảng năm 1990. Java không có generics cho đến năm 2004 — 21 năm sau Ada. Go hoàn toàn không có generics cho đến phiên bản 1.18 vào năm 2022 — 39 năm sau Ada.

Mô hình đồng thời (Concurrency) và an toàn

Mô hình đồng thời của Ada là nơi khoảng cách giữa những gì Ada thiết kế và những gì ngành công nghiệp chấp nhận trở nên quan trọng nhất. Bế tắc về đồng thời của những năm 2000 và 2010 — trạng thái có thể thay đổi chung (shared mutable state) bị thảm họa bởi bộ vi xử lý đa nhân, đồng bộ hóa dựa trên khóa gây ra deadlock và điều kiện tranh chấp — thực ra đã được dự báo trước.

Các tác vụ (tasks) của Ada là cấu trúc ở cấp độ ngôn ngữ, được lập lịch bởi thời gian chạy của Ada và giao tiếp thông qua rendezvous hoặc protected objects. Rendezvous là một điểm giao tiếp đồng bộ hóa. Các tác vụ không bao giờ chia sẻ bộ nhớ một cách ngầm định. Đây là truyền thông tin điệp — không theo nghĩa một giá trị được tuần tự hóa và gửi qua socket, mà theo nghĩa thiết kế của giao tiếp ngăn chặn việc truy cập trạng thái chung theo cấu trúc. Các kênh (channels) của Go là sự hiện thực hóa trực tiếp của ý tưởng này với cú pháp khác.

Các protected objects của Ada 95 giải quyết các trường hợp mà trạng thái chia sẻ thực sự cần thiết. Thời gian chạy thực hiện loại trừ lẫn nhau cho các thủ tục mà không cần lập trình viên viết khóa. Ada tạo ra các lỗi này trở nên không thể có về mặt cấu trúc thay vì chỉ khuyến khích tránh chúng.

Tại sao Ada bị lãng quên?

Có vẻ có một nghịch lý: mọi ngôn ngữ hiện đại đều đang hướng về các thiết kế của Ada, nhưng chính Ada lại bị mô tả là không liên quan. Câu trả lời đầu tiên là về thể chế: Ada là một ngôn ngữ của chính phủ, được mua sắm thông qua một quy trình mà Thung lũng Silicon không theo dõi và sẽ không tôn trọng nếu có.

Câu trả lời thứ hai là về thẩm mỹ. Cú pháp của Ada rất dài dòng theo cách mà các lập trình viên nền tảng C thấy khó chịu. if X then Y; end if; thay vì if (x) { y; }. Sự dài dòng này là có chủ đích — Ichbiah muốn chương trình có thể đọc được bởi những người khác ngoài tác giả — nhưng nó lại bị trải nghiệm như quan liêu và thiếu "hacker".

Câu trả lời thứ ba là lĩnh vực triển khai của Ada khiến những thành công của nó trở nên vô hình. Một dự án phần mềm biên dịch không có lỗi, chạy không có điều kiện tranh chấp và đã được xác minh chính thức để thỏa mãn đặc tả kỹ thuật thì không tạo ra báo cáo sự cố hay các bài thuyết trình về những gì đã sai. Ada tạo ra phần mềm đáng tin cậy, và phần mềm đáng tin cậy không tạo ra sự tranh luận.

Tuy nhiên, quỹ đạo của thiết kế ngôn ngữ hiện đại, nếu được truy cẩn thận, là một quỹ đạo hướng tới các vị trí mà Ada đã chiếm lĩnh từ sớm. Các tính năng hệ thống kiểu mà Rust, Haskell, TypeScript và Swift được ca ngợi — sum types, parametric polymorphism, generics dựa trên ràng buộc — mỗi cái giải quyết một vấn đề mà Ada đã xác định vào năm 1983. Các mô hình đồng thời mà Go channels và Rust ownership được tin tưởng là phát minh thực sự thuộc về dòng dõi CSP và truyền thông tin điệp giống như mô hình rendezvous và protected object của Ada.

Ada chứng minh rằng các vấn đề mà thiết kế ngôn ngữ hiện đại đang giải quyết là những vấn đề cũ, và các giải pháp mà các ngôn ngữ hiện đại đang phát hiện ra là những giải pháp cũ. Ngành công nghiệp đã dành bốn mươi năm để xây dựng các ngôn ngữ có các tính năng tốt nhất hội tụ độc lập về các vị trí mà Ada đã thiết lập từ nhiều thập kỷ trước. Trong khi đó, Ada — đang được triển khai trong các máy bay trên đầu, trong tín hiệu đường sắt, trong các hệ thống dẫn đạo tàu vũ trụ — vẫn bận rùng chạy đúng đắn mà không cần bận tâm liệu nó có được đánh giá cao hay không.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗