1 điểm bởi GN⁺ 2026-01-09 | 1 bình luận | Chia sẻ qua WhatsApp
  • Cốt lõi của năng suất lập trình nằm ở hệ sinh thái thư viện phong phú hơn là bản thân ngôn ngữ
  • Những framework tận dụng các tính năng cao cấp của ngôn ngữ như Ruby on Rails mang lại năng suất cao ngay cả cho người không chuyên
  • Tuy nhiên, do những giới hạn mang tính cấu trúc của ngôn ngữ, rất khó triển khai một framework ở cấp độ Rails bằng Java hay C
  • Thiết kế ngôn ngữ trực tiếp quyết định hình thức và độ phức tạp của các thư viện có thể được viết ra, và đó chính là mục đích cốt lõi của sự phát triển ngôn ngữ
  • Từ góc nhìn này, ngôn ngữ Stanza cho thấy tầm quan trọng của thiết kế ngôn ngữ trong việc cho phép tạo ra các thư viện mạnh mẽ và dễ dùng

Mối quan hệ giữa ngôn ngữ lập trình và thư viện

  • Hầu hết các ngôn ngữ lập trình đều có những thành phần cơ bản tương tự như biến, mảng, vòng lặp và hàm
    • Một số ngôn ngữ cung cấp các tính năng nâng cao như hàm hạng nhất hoặc coroutine, nhưng người không chuyên thường không sử dụng tốt chúng
  • Với nhiều nhà phát triển, yếu tố giúp tăng năng suất là thư viện hơn là ngôn ngữ
    • Ví dụ, Ruby on Rails giúp xây dựng ứng dụng web dựa trên cơ sở dữ liệu một cách dễ dàng
    • Nhờ Rails, mức độ ưa chuộng framework còn cao hơn cả bản thân ngôn ngữ Ruby

Sự tương tác giữa Ruby on Rails và các tính năng ngôn ngữ

  • Rails tận dụng nhiều tính năng của Ruby như metaprogramming, đánh giá lúc chạy, hàm hạng nhất, garbage collection
    • Ví dụ: ActiveRecords dùng metaprogramming, còn hệ thống template dùng đánh giá lúc chạy
    • Xử lý sự kiện được triển khai bằng cách truyền hàm hạng nhất làm callback
  • Trong Java hay C, do thiếu các tính năng này nên không thể triển khai một framework ở cấp độ Rails
    • Metaprogramming của Java không đủ mạnh để triển khai ActiveRecords
  • Vì vậy, Rails tồn tại được nhờ cấu trúc của ngôn ngữ Ruby, và thiết kế ngôn ngữ quyết định khả năng của thư viện

Thiết kế ngôn ngữ quyết định hình thức của thư viện

  • Ngôn ngữ C chỉ hỗ trợ tái sử dụng thông qua khai báo và gọi hàm, nên phần lớn thư viện C có dạng tập hợp các hàm
  • Ruby hỗ trợ hàm hạng nhất nên có thể diễn đạt ngắn gọn kiểu “hành động sẽ chạy khi nút được bấm”
    • Ngược lại, trong Java phải định nghĩa lớp handler, nên mã trở nên phức tạp hơn
  • Năng lực biểu đạt của ngôn ngữ trực tiếp quy định cấu trúc và tính dễ dùng của thư viện

Phần mềm tương tác và sự xuất hiện của framework có thể mở rộng

  • Trong thời kỳ điện toán xử lý theo lô của thập niên 1970, thư viện xoay quanh hàm là đủ dùng
  • Trong phần mềm tương tác hiện đại, cần đến thư viện có thể mở rộng
    • Trong GUI hay hệ thống dựa trên sự kiện, cần một cấu trúc kiểu “khi người dùng bấm thì chạy mã của tôi”
  • Java và C++ hỗ trợ mở rộng bằng kế thừa và ghi đè phương thức, và cấu trúc đó đã phát triển thành framework

Bối cảnh thiết kế Stanza và giới hạn của ngôn ngữ

  • Động lực thiết kế Stanza bắt đầu từ khó khăn khi viết thư viện lập trình game dễ dùng trong Java
    • Trong Java, tính đồng thời phải được biểu diễn như máy trạng thái (state machine)
    • Scheme hỗ trợ continuation nên có thể triển khai trực quan hơn
  • Tuy nhiên, Scheme không hỗ trợ kiểm tra kiểu tĩnh nên hiệu quả debug thấp
    • Hiện nay, phần lớn ngôn ngữ vẫn không thể mở rộng hệ thống kiểu bằng thư viện
  • Stanza cung cấp hệ thống kiểu tùy chọn, garbage collection, hệ thống đối tượng dựa trên multimethod
    • Nhưng không thể viết mới hoàn toàn một hệ thống đối tượng do người dùng định nghĩa

Mục đích của ngôn ngữ và hướng nghiên cứu

  • Mục tiêu của ngôn ngữ lập trình đa dụng là hỗ trợ tạo ra các thư viện mạnh mẽ và dễ dùng
    • Ngôn ngữ càng mạnh thì việc dùng thư viện càng ngắn gọn
  • Khi mã sử dụng một thư viện được thiết kế tốt, nó có sự tự nhiên như đang đọc một câu lệnh giao việc cho đồng nghiệp
  • Racket, Shen và các nghiên cứu về meta object protocol đang khám phá hệ thống kiểu và hệ thống đối tượng có thể mở rộng
  • Cuối cùng, các ngôn ngữ được phân biệt bởi “có thể dùng loại thư viện nào, và không thể dùng loại thư viện nào
  • Đằng sau một thư viện thanh lịch là hàng chục năm nghiên cứu và nỗ lực thiết kế ngôn ngữ

1 bình luận

 
GN⁺ 2026-01-09
Ý kiến trên Hacker News
  • Ví dụ điển hình nhất là Prolog. Nó thường được gọi là ngôn ngữ tiêu biểu của lập trình logic, nhưng thực ra về cơ bản chỉ là một tập hợp các thuật toán, và có thể được triển khai như thư viện trong từng ngôn ngữ. Tôi nghĩ chỉ cần cung cấp cách biểu đạt cú pháp của Prolog sao cho phù hợp với cú pháp của từng ngôn ngữ là đủ

    • Cốt lõi của Prolog không phải là thuật toán mà là cách biểu diễn các quy tắc logic theo kiểu khai báo. Ví dụ, nếu định nghĩa quy tắc “ông bà là cha mẹ của cha mẹ”, thì từ đó có thể tìm ông bà hoặc suy ra ngược lại quan hệ cha mẹ. Kiểu suy luận hai chiều này chính là sức hấp dẫn của Prolog. Tất nhiên, nếu muốn bắt chước tính năng đó bằng ngôn ngữ thông thường thì cần code không có side effect và một DSL bị giới hạn. Gọi chéo giữa các ngôn ngữ cũng khả thi, như PyTorch hay TensorFlow chạy CUDA từ Python, nên tôi nghĩ một cấu trúc không phụ thuộc vào ngôn ngữ hoàn toàn là điều có thể làm được
    • Cú pháp của Prolog là tập con của First Order Logic (logic vị từ bậc nhất), trong đó biến không được gán giá trị cố định mà sẽ tìm kiếm trên tập các giá trị khả dĩ cho đến khi thỏa điều kiện. Engine Prolog làm nhiều hơn là chỉ gọi thư viện đơn thuần — ví dụ như biểu diễn nén không gian nghiệm, thực thi song song, tự động cắt tỉa nhánh, v.v. Vì thế người ta thường đặt Prolog làm backend service hoặc tích hợp bằng cách sinh mã. Prolog đặc biệt mạnh trong lập kế hoạch, giải ràng buộc, chứng minh định lý, kiểm thử tổ hợp, mô hình hóa giá. Vì vậy, tôi nghĩ sẽ hơi gượng ép nếu xem Prolog chỉ là “một ngôn ngữ mà thư viện là đủ”
    • Theo cùng logic đó, cũng có thể nói các tính năng hướng đối tượng không thực sự cần trong ngôn ngữ vì có thể bắt chước bằng closure. Nhưng sức biểu đạt mà cú pháp rõ ràng mang lại có những lợi thế riêng
    • Nếu muốn triển khai lập trình quan hệ kiểu Prolog dưới dạng thư viện, thì ngôn ngữ đó phải hỗ trợ thao tác symbol và biến như các đối tượng hạng nhất. Các ngôn ngữ họ Lisp còn có chút khả năng này, nhưng với ngôn ngữ thông thường thì tính tiện dụng giảm hẳn. Khi tôi nói chuyện với Bob Harper, ông ấy bảo “cứ tạo ngôn ngữ mới đi”, và tôi thấy câu đó khá thuyết phục
    • Tôi muốn học Prolog, nhưng rất khó tìm được tài liệu ở mức trung cấp nằm giữa tutorial nhập môn và ví dụ nâng cao. Tôi đang thử giải các biến thể Sudoku bằng Prolog, nhưng các ví dụ hiện có tối ưu hóa quá mạnh nên khó học được cách định nghĩa quan hệ một cách tổng quát. Tôi đặc biệt muốn biết cách mô hình hóa những tình huống mà một số quy tắc có thể sai. Tham khảo hiện tại là ví dụ Sudoku của SWI-Prolog
  • Mười năm trước tôi là fan của Scala. Khái niệm “Scalable Language” rất hấp dẫn vì có thể tạo DSL bên trong hệ thống kiểu. Nhưng rồi tôi mất hứng khi cộng đồng bắt đầu dùng nó như một kiểu Haskell chạy trên JVM. Gần đây tôi kỳ vọng các công nghệ như WASM hay Graal sẽ tăng tính linh hoạt trong việc chọn ngôn ngữ. Nhiều trường hợp chỉ cần JS là đủ, nhưng thật tốt khi có thêm lựa chọn dùng ngôn ngữ cấp thấp như Rust lúc cần thiết

    • Tôi cũng nghĩ vấn đề lớn nhất của Scala là lạm dụng DSL. Không chỉ bản thân ngôn ngữ mà ngay cả framework kiểm thử cũng cho cảm giác phải học thêm một ngôn ngữ khác. Đúng là có thể viết Hadoop MapReduce trong một dòng trông rất ấn tượng, nhưng với phần lớn công việc thì như vậy là quá tay. Hơn nữa, các lập trình viên Scala thường ghét viết “code nhàm chán”. Tôi đã thấy nhiều người cố làm cho ngầu rồi để lại địa ngục bảo trì trước khi rời đi
    • Không phải cả cộng đồng Scala đều thiên về Haskell. Chỉ một số phù thủy kiểu dữ liệu có xu hướng như vậy thôi. Scala vẫn rất tuyệt nếu chỉ dùng như “Java tốt hơn”. Bạn có thể tận hưởng lợi ích của lập trình hàm mà không thấy quá nặng nề
    • Haskell vốn dĩ thường được dùng như ngôn ngữ để tạo DSL. Haxl của Meta hay TidalCycles, DSL dành cho âm nhạc, là những ví dụ hay. Tuy nhiên, các thư viện dựa trên kiểu bậc cao thường suy giảm hiệu năng đáng kể và phức tạp không cần thiết
    • Bạn đã thử Clojure(Script) chưa? Đúng chất họ Lisp, nó cho phép lập trình bottom-up bằng cách mở rộng ngôn ngữ cho phù hợp với bài toán. Paul Graham cũng nhấn mạnh cách tiếp cận này trong On Lisp. Tôi cũng gợi ý bài nói Bottom Up vs Top Down Design in Clojure
    • Gần đây tôi mới bắt đầu học Scala và thấy nó thực sự rất thích, kể cả ở khía cạnh lập trình hàm. Tôi nghĩ nó đủ đa dụng để dùng theo nhiều cách khác nhau ngoài việc tạo DSL. Tôi muốn hỏi liệu bạn có cảm thấy Scala còn thiếu điểm gì không
  • Sẽ thật tuyệt nếu có thể thay bash bằng một ngôn ngữ script có kiểu. Tôi đã thử viết một script parser JSON đơn giản bằng Elixir và thấy khá ổn

    • Bạn đã thử Nushell chưa? Nó có thể xử lý bằng một dòng những việc trước đây phải dùng “ngôn ngữ thật”. Ví dụ, bạn có thể viết một pipeline đơn giản để sắp xếp danh sách file rồi xuất ra JSON
    • Thật ra, dùng shebang thì có thể viết script bằng nhiều ngôn ngữ khác nhau. Ví dụ, C#, Java, Go đều làm được. Nếu dùng Scriptisto thì gần như có thể tạo shebang script bằng mọi ngôn ngữ
    • OCaml cũng có thể dùng như script. Chạy trực tiếp với #!/usr/bin/env ocaml là được. Tuy nhiên, nó không có khả năng tự động cài dependency ngoài trong một file đơn
    • Go cũng có mẹo để giả lập shebang. Xem thảo luận liên quan ở đây
    • Với scripting hằng ngày thì Python hay PowerShell cũng là lựa chọn tốt
  • Ngôn ngữ và thư viện không loại trừ lẫn nhau. Có những thư viện thực chất hoạt động như một ngôn ngữ, và ngược lại cũng có ngôn ngữ được thiết kế để phục vụ một thư viện cụ thể. Ví dụ, Julia là một trường hợp cân bằng tốt giữa hiệu năng và tính tiện dụng. Bạn có thể viết trực tiếp code hiệu năng cao bằng Julia và nhận được việc thực thi tối ưu nhờ biên dịch chuyên biệt theo kiểu ở mức JIT. Mô hình gọi hàm nhìn thì đơn giản nhưng bên trong vận hành rất tinh vi

    • Đúng vậy, rốt cuộc ý chính vẫn là cần cả ngôn ngữ lẫn thư viện
  • Raku được thiết kế theo cấu trúc kết hợp nhiều tiểu ngôn ngữ (slang). Ví dụ, regex, PEG, quoting, v.v. đều được xử lý như những mini-language riêng, và có thể dễ dàng thêm DSL của riêng mình bằng Slangify

    • Nhưng cá nhân tôi không thích cú pháp đặt kiểu ở sau tên biến, nên không chuộng Raku
  • Trước đây có một lập trình viên senior từng nói “cứ thấy Rails trong CV là tôi loại ngay”. Điều đó lại khiến tôi càng thấy rõ việc đánh giá con người qua ngôn ngữ là ngớ ngẩn đến mức nào

    • Sự trỗi dậy của Rails và sự suy tàn của J2EE diễn ra cùng lúc không phải ngẫu nhiên. Rails cho thấy backend code có thể đơn giản và có chính kiến, và từ ảnh hưởng đó mới xuất hiện các framework Java như DropWizard, Javalin, Spring Boot
    • Tôi tò mò không biết stack công nghệ của vị senior đó là gì
    • Tôi còn muốn đi nhặt thùng rác của kiểu đồng nghiệp như vậy. Lập trình viên Rails giỏi rất khó kiếm. Tôi cũng có kinh nghiệm với RoR và vẫn rất thích nó
    • Tất nhiên, nếu bạn đang tuyển Java developer thì lọc CV Rails có thể cũng là một cách hiệu quả
    • Tiêu chí đánh giá con người rốt cuộc vẫn phụ thuộc vào độ phù hợp văn hóa của tổ chứcphong cách cộng tác. Không có cách lọc nào là hoàn hảo
  • Ngôn ngữ hay thư viện cuối cùng đều là công cụ giao tiếp với cả máy lẫn con người. Máy giao tiếp bằng bit và điện áp, còn con người giao tiếp bằng ý định và khái niệm. Vì thế, nếu một ngôn ngữ hay thư viện giúp con người diễn đạt rõ ràng và nhanh chóng thì việc nó là ngôn ngữ hay thư viện không còn quan trọng. Rails hay Stanza đều vậy, miễn là phù hợp với mục tiêu và cả nhóm dễ hiểu thì đó là lựa chọn đúng

  • Tôi nghĩ “thư viện chính là ngôn ngữ cuối cùng”. Ví dụ, Ruby on Rails là một ngôn ngữ tuyệt vời để viết dịch vụ web dựa trên Ruby. Ruby và Rails đã cùng tiến hóa vì nhau. Rốt cuộc, tôi xem lập trình là một quá trình dịch liên tục giữa các ngôn ngữ

    • C# và ASP.NET Core cũng đã phát triển cùng nhau theo cách tương tự. Cú pháp thân thiện với người dùng và tối ưu hóa ở cấp hệ thống diễn ra song song
  • Câu “ngôn ngữ càng mạnh thì càng dễ dùng thư viện” là đúng. Ngày xưa với Java cũ thì khó mà tạo ra framework kiểu Express

    • Tôi không rõ Express là gì, nhưng tôi nghĩ Java đã trở thành ngôn ngữ cho doanh nghiệp chính nhờ khả năng tận dụng thư viện
    • Minimal API của ASP.NET Core là một ví dụ gần như triển khai Express nguyên xi. Điều này chỉ có thể xảy ra khi ngôn ngữ và framework cùng phát triển với nhau
    • Trong Java cũng có framework tương tự Express như Javalin. Vấn đề là cộng đồng không muốn sự đơn giản
  • Nếu nói về web framework cho ngôn ngữ C, chẳng phải đã có PHP rồi sao? ;)

    • Nghe giống một trò đùa mở rộng khái niệm thư viện quá mức hơn đấy