2 điểm bởi GN⁺ 2024-04-22 | 1 bình luận | Chia sẻ qua WhatsApp
  • Racket là một ngôn ngữ trưởng thành đặt lập trình hướng ngôn ngữ ở trung tâm, xử lý cả phát triển ứng dụng thông thường lẫn tạo ngôn ngữ mới trong cùng một hệ sinh thái
  • Cốt lõi là macro và #lang, cho phép tạo cú pháp mới, ngôn ngữ chuyên biệt theo miền và cú pháp bề mặt hiện có như thư viện, rồi dùng theo đơn vị mô-đun
  • Thư viện chuẩn bao gồm từ web server, cơ sở dữ liệu, toán học·thống kê, GUI đến mô phỏng khoa học, cùng hàng nghìn package mở rộng phạm vi phát triển đa mục đích
  • Typed Racket, contract, hệ thống đối tượng và IDE DrRacket được cung cấp cùng nhau, cho phép kết hợp mã hàm, thành phần hướng đối tượng và kiểu dần dần tùy nhu cầu
  • Racket không chỉ là một ngôn ngữ họ Lisp đơn thuần, mà gần với một môi trường phát triển nhằm tạo ngôn ngữ phù hợp cho từng lĩnh vực vấn đề và kết nối cả chạy, chỉnh sửa lẫn hỗ trợ công cụ

Racket cho lập trình hướng ngôn ngữ

  • Racket là một ngôn ngữ lập trình đồng thời nhấn mạnh “Racket, the Programming Language” và “Racket, the Language-Oriented Programming Language”
  • Racket version 9.2 hiện đã có thể sử dụng
  • Đây là một sản phẩm trưởng thành đã hỗ trợ lập trình đồ họa đa nền tảng trên Windows, macOS và Linux từ rất sớm
  • Các chức năng phát triển cơ bản bao gồm quản lý package, GUI, binary thực thi độc lập và giao diện với bên ngoài

Phạm vi phát triển ứng dụng thông thường

  • Racket có bộ thư viện bao phủ từ ứng dụng web server đến toán học và phần mềm mô phỏng khoa học
  • Các tài liệu và phạm vi thư viện tiêu biểu như sau
  • Bộ công cụ GUI đa nền tảngweb server được đưa vào hệ sinh thái cơ bản
  • Có thể cài đặt hàng nghìn package bổ sung chỉ bằng một lệnh
    • Ví dụ gồm 3D graphics, Bluetooth socket connector, color maps, data structures, educational software, games, quantum-random number generator, scientific simulations, web script testing, v.v.
  • Ví dụ #lang racket/gui triển khai một trò chơi đoán số nhỏ bằng phương ngữ GUI và sử dụng nhiều tính năng ngôn ngữ cùng lúc

Ngôn ngữ được mở rộng bằng macro

  • Lập trình viên Racket có thể dùng macro để định nghĩa vòng lặp riêng và cú pháp mới
  • Cú pháp mới được thêm vào như procedure, method và class; chỉ cần tạo quy tắc viết lại cú pháp tùy chỉnh thành biểu thức hoặc định nghĩa Racket
  • Macro nhỏ giúp loại bỏ mã lặp vốn khó xử lý bằng các tính năng khác
    • Có thể định nghĩa cú pháp time-it để đo thời gian thực thi tác vụ
    • Có thể tránh việc dùng lambda lặp đi lặp lại
    • Macro được export từ mô-đun như hàm thông thường
  • Toàn bộ hệ thống macro cũng có thể tạo cấu trúc trong đó nhiều macro phối hợp với nhau
  • Racket là ngôn ngữ hàm, nhưng ngay từ đầu đã cung cấp ngôn ngữ con cho classes and objects, mixins and traits
  • Hệ thống class tương tự Java được triển khai dưới dạng thư viện dựa trên macro, hoạt động mà không cần hỗ trợ riêng từ ngôn ngữ lõi

#lang và ngôn ngữ chuyên biệt theo miền

  • Racket hướng tới vai trò ngôn ngữ để tạo ngôn ngữ, cho phép lập trình viên viết từng mô-đun bằng ngôn ngữ phù hợp
  • Ví dụ #lang typed/racket sử dụng union type của StringNumber, occurrence typing và lọc danh sách
  • Ví dụ #lang scribble/base xử lý ngôn ngữ tài liệu tạo tài liệu PDF hoặc HTML
  • Ví dụ #lang datalog dùng cú pháp Datalog để định nghĩa và truy vấn quan hệ parentancestor
  • Có thể tạo ngôn ngữ mới trong một cửa sổ IDE và chạy mô-đun của ngôn ngữ đó trong cửa sổ IDE khác, không cần thiết lập, file dự án hay công cụ bên ngoài
  • Người dùng Racket chủ yếu dùng cú pháp ngoặc, nhưng cũng có thể tạo cú pháp bề mặt hiện có cần dấu phẩy và dấu ngoặc nhọn như Datalog
  • Khi dùng parsing packages, có thể ánh xạ ngữ pháp tùy ý sang ngôn ngữ dựa trên ngoặc và biên dịch thành Racket thông thường bằng hệ thống macro của Racket

DrRacket và hệ sinh thái phát triển

  • Racket cung cấp IDE riêng là DrRacket, có tính năng vẽ mũi tên tới vị trí định nghĩa khi di chuột lên định danh
  • Ngay cả khi dùng ngôn ngữ thay thế như Typed Racket, vẫn có thể tận dụng hỗ trợ chỉnh sửa của DrRacket
  • Macro của Racket ghi lại và truyền đủ thông tin nguồn ngay cả trong các macro phức tạp hoặc macro tạo ngôn ngữ mới, để DrRacket có thể hoạt động như thể hiểu các tính năng của ngôn ngữ mới
  • Các hỗ trợ phát triển chính như sau
  • Tài nguyên hệ sinh thái bao gồm tải xuống, mã nguồn, báo cáo lỗi, nightly snapshot builds và kho package
  • Tài liệu học tập và tài liệu tham khảo gồm Quick Introduction, The Racket Guide, The Racket Reference, All Documentation
  • Các kênh cộng đồng gồm Discourse, Discord, Slack, Reddit, mailing lists, Mastodon, Twitter, Blog, Wiki, YouTube; ngoài ra còn có tài liệu Team và Contributing

1 bình luận

 
GN⁺ 2024-04-22
Các ý kiến trên Hacker News
  • Rất vui khi thấy Racket lên trang nhất. Từ năm 1982, tôi chủ yếu dùng Common Lisp cho lập trình nghiên cứu, nhưng dạo này lại tìm đến Racket thường xuyên hơn
    Cũng có những điểm tôi không thích ở Racket; gần như là mọi thứ, ngoại trừ trình biên dịch, hệ thống quản lý gói, GUI IDE, binding cho Emacs, và việc nó là một ngôn ngữ viết rất vui
    Tôi không mấy quan tâm đến hệ sinh thái nghiên cứu ngôn ngữ lập trình, có lẽ đó là phần mà các giáo sư khoa học máy tính dẫn dắt dự án coi trọng nhất. Dù vậy, tôi vẫn mong họ thành công
    Vì thế tôi cũng có cảm giác như đang đi nhờ không trả tiền trên dự án Racket. Tôi chỉ tận hưởng những phần nhỏ mình thích, bỏ qua phần còn lại, và hầu như không đóng góp gì. Có lẽ ngoại lệ chỉ là cuốn sách nhỏ về Racket mà tôi đã viết

    • Tôi gần như đồng ý với toàn bộ ý này. Nhờ hệ thống quản lý gói, GUI IDE có trình gỡ lỗi theo từng bước, khả năng viết IDE đa nền tảng do chính đội ngũ cốt lõi của Racket duy trì, và tính năng dễ dàng tạo binary thực thi, Racket là Lisp yêu thích nhất của tôi
      Những tính năng này thật sự hữu ích và quan trọng. Tôi thích Lisp, nhưng ở nơi làm việc tôi chỉ dùng ngôn ngữ đó khi nó là công cụ phù hợp nhất cho việc cần làm. Nhờ các tính năng này, Racket là Lisp duy nhất mà tôi từng có thể biện minh để sử dụng trong thực tế
      Nhờ cộng đồng, công cụ và tài liệu học tập, với cá nhân tôi Racket là ngôn ngữ dễ giới thiệu cho người khác. Tôi cũng đã dùng CL và Clojure khá nhiều và có những điểm thích ở chúng, nhưng mỗi ngôn ngữ đều có nhược điểm lớn nên tôi không giới thiệu cho người khác
      Tôi cũng không hợp lắm với phần nghiên cứu của ngôn ngữ hay tính năng lang, và cũng khá không thích HtDP. Nhưng tôi xem đó chỉ là những dự án tôi không quan tâm được xây trên ngôn ngữ mình thích, chứ không phải nhược điểm của bản thân ngôn ngữ. Vì trong thực tế gần như tôi không phải va chạm với chúng
    • https://leanpub.com/racket-ai/read
      Như thế này có thể xem là đóng góp rất lớn rồi :)
    • Tôi dùng CL hằng ngày, nhưng không thuộc lĩnh vực nghiên cứu hay nghiên cứu ngôn ngữ lập trình. Tôi vẫn chưa dùng Racket, nên tò mò liệu bạn có thể nói rõ hơn những điểm không thích ở Racket so với CL không
    • Tôi tò mò hệ sinh thái nghiên cứu ngôn ngữ lập trình chính xác nghĩa là gì. Trong bản phân phối Racket, thứ duy nhất tôi thấy có thể gọi hẳn là nghiên cứu ngôn ngữ lập trình chỉ là Redex
      Bản thân ngôn ngữ có các tính năng metaprogramming, nhưng các ngôn ngữ hiện đại đều có metaprogramming
      Trải nghiệm của tôi trong cộng đồng phần lớn là những người nói về các vấn đề thực tế
      Vì Racket được dùng trong nghiên cứu ngôn ngữ lập trình hoặc các nghiên cứu khác nên nó được nhắc đến trong các bài báo và bài thuyết trình hội nghị liên quan, nhưng không chi phối các cuộc thảo luận
      Ví dụ: https://racket.discourse.group/t/levin-tree-search-with-cont...
    • Tôi từng dùng Racket trong một môn về hệ sinh thái ngôn ngữ lập trình ở đại học, và ở khía cạnh đó tôi cũng không thấy thú vị lắm. Dù vậy Racket dễ bắt đầu và chắc chắn làm tốt vai trò của nó. Nếu bước chân vào Lisp thì cá nhân tôi nghĩ Racket là một điểm khởi đầu tốt
      Tuy nhiên Clojure có cộng đồng lớn hơn và vững hơn. Đổi lại, vì dùng JVM nên việc thiết lập hơi phiền hơn, và cũng có nhiều điểm tinh tế cần để ý hơn
  • Racket là một ngôn ngữ rất thực dụng. Nếu nó trông chỉ như một sở thích học thuật kỳ lạ, bạn nên xem Bogdan Popa đang làm gì với Racket: https://defn.io/
    Cá nhân tôi dùng Racket khi cần binary có GUI native. Nó cũng khá tốt để parse những thứ như JSON, XML, các định dạng tệp văn bản
    Cuốn sách đọc kèm How to Design Programs, https://htdp.org/2023-8-14/Book/index.html cũng hay. Đây không hẳn là sách dạy Racket, mà dùng một vài ngôn ngữ giáo dục được triển khai bằng Racket, nhưng thỉnh thoảng có những ý tưởng đáng để ngẫm lại
    Hệ thống macro có thể trông kỳ lạ với người đến từ những nơi như CL, nhưng sau khi quen thì tôi thấy dễ giữ được sự tỉnh táo tương đối khi làm metaprogramming
    Còn vài tài liệu hữu ích nữa:
    https://www.greghendershott.com/fear-of-macros/
    https://beautifulracket.com/

    • Có điều gì ở phía Bogdan đặc biệt nổi bật không? Tôi chỉ lướt qua thì chưa thấy gì thật sự gây ấn tượng
  • Tôi rất thích ngôn ngữ Racket, nhưng quy trình làm việc bị áp đặt thì khó chấp nhận. Khi viết code bằng Python, tôi viết code trong trình soạn thảo rồi chạy trong shell
    Racket có thời gian khởi động quá lâu nên cách đó không hiệu quả lắm. Thay vào đó, người ta nói nên tương tác với một máy ảo chạy dài hạn và REPL
    Nhưng như vậy thì code đang làm không bắt đầu từ một trạng thái sạch, mà bắt đầu từ trạng thái mà máy ảo đang có tại thời điểm đó. Với những thứ như Jupyter Notebook thì đây là luồng rất tuyệt, nhưng tôi cho là không phù hợp với các chương trình lớn

    • Cách viết code trong trình soạn thảo rồi chạy trong shell cũng hoàn toàn hợp lệ trong Racket. Theo kinh nghiệm của tôi, thời gian khởi động khá giống Python. Có chậm, nhưng không đến mức chết người, và đặc biệt ổn nếu biên dịch trước. Nó hữu ích với các tệp đã hoàn tất công việc ở thời điểm hiện tại
      Dùng racket/base làm #lang thay vì racket cũng tạo ra khác biệt lớn. Chi tiết có tại https://docs.racket-lang.org/style/Language_and_Performance....
      Chuyện không bắt đầu từ “trạng thái sạch” có vẻ giống REPL kiểu Common Lisp hơn là Racket. Trong Racket, khi nạp lại tệp hoặc module, thường phải khởi động lại Racket nên sẽ có môi trường mới. Mọi người phàn nàn về điều đó, nhưng tôi thích cách trạng thái sạch của Racket hơn CL
    • Phần nói không bắt đầu từ “trạng thái sạch” thì theo tài liệu, có vẻ người dùng có thể chủ động từ chối lưu tệp sao lưu
      https://docs.racket-lang.org/drracket/drracket-files.html#(p...
      Có lẽ cũng có thể từ chối đề xuất khôi phục
      “Khi DrRacket khởi động lần đầu, nó kiểm tra xem có tệp sao lưu nào còn lại không, và nếu có thì đề nghị khôi phục tệp sao lưu”
    • Cứ thử dùng Smalltalk một lần là được :-))
    • Guile có thể sẽ thú vị. Đặc biệt khi gỡ lỗi, tôi nghĩ nó gần với kiểu nhập vai hơn Racket, và cũng giống Common Lisp (SBCL) hơn
    • Chào mừng đến với thế giới Smalltalk và Lisp Machines. Ngay cả IDE hiện đại cũng vẫn chưa hỗ trợ đầy đủ hot reload, lưu trạng thái làm việc, và kiểm soát toàn bộ stack phát triển bằng một ngôn ngữ duy nhất
  • Khi học tại University of British Columbia, môn nhập môn khoa học máy tính dạy Racket. Tôi nghĩ đó là một ngôn ngữ tuyệt vời, và vì ngay cả những sinh viên đã có kinh nghiệm lập trình trước đó cũng hầu như chưa từng dùng Lisp, nó đưa tất cả về cùng một vạch xuất phát
    Các thư viện giúp dễ dàng tạo game đơn giản hoặc trực quan hóa cũng rất ấn tượng

    • Tôi cũng học lớp đó ở UBC, nhưng có ấn tượng hoàn toàn khác. Nó tệ hại, và tôi cho là đã chuẩn bị rất kém cho sinh viên nhập môn trước các lớp cấu trúc dữ liệu và thuật toán sau đó vốn dùng ngôn ngữ mệnh lệnh
      Khi làm trợ giảng, khá nhiều sinh viên lên năm hai vẫn chưa biết viết vòng lặp for, và tụt hậu đáng kể ở các thuật toán cơ bản
      Sự appreciation sâu hơn của tôi đối với ngôn ngữ hàm chỉ xuất hiện sau lớp lý thuyết tính toán năm tư
  • Tôi không biết nên tích hợp tất cả các “ngôn ngữ” này của Racket vào một ứng dụng như thế nào. Tôi thấy các ngôn ngữ như typed/racket, racket/gui, scribble/base, nhưng không hình dung được nếu muốn tạo ứng dụng GUI bằng code có kiểu đồng thời sinh PDF thì phải làm ra sao
    Tôi đã làm theo các tutorial Racket nhiều lần, nhưng vẫn bối rối không biết ghép các “ngôn ngữ” trông có vẻ không liên quan với nhau như thế nào
    Cá nhân tôi có cảm giác mỗi chương của tutorial chỉ giải thích những “ngôn ngữ” không liên quan, và không bao giờ cho thấy chúng hoạt động cùng nhau. Một chương nói về web server nhưng không nói về hệ thống class, chương khác nói về một “ngôn ngữ” khác hỗ trợ class nhưng lại không viết web server trong đó

    • Có thể nghĩ dòng #lang như một loại chỉ thị compiler áp dụng trong phạm vi tệp đó. Thực tế còn nhiều hơn thế, nhưng đây là điểm khởi đầu ổn. Nếu muốn thêm kiểu vào ứng dụng, chiến lược tốt là làm từng tệp một
      Ngoài dòng #lang, bạn cũng có thể dùng require để nhập thư viện, nên có thể đặt code GUI và code web server chung trong một tệp. #lang cũng không nhất thiết bị giới hạn chỉ một ngôn ngữ mỗi lần; nếu không xung đột thì có thể thêm nhiều thứ vào dòng đó
    • Tôi nghĩ đây là một câu hỏi hợp lý. Nếu phát triển một ứng dụng lớn, rất có khả năng gần như toàn bộ code sẽ được viết bằng ngôn ngữ "racket". Nếu rất quan tâm đến kiểu, một phần đáng kể có thể là "typed/racket"
      Đúng là mọi ngôn ngữ đều chia sẻ một nền tảng chung và có khả năng tương tác ở mức nào đó, nhưng hoàn toàn không có khả năng chương trình sẽ được chia đều thành năm mảnh, mỗi mảnh dùng một ngôn ngữ khác nhau. Tài liệu có lẽ sẽ được viết bằng scribble
      Dùng các ngôn ngữ khác nhau có thể đem lại các mô hình lập trình về cơ bản khác nhau, và đó cũng là bối cảnh khiến những phát triển như Typed Racket trở nên khả thi, nhưng nó không nên trở thành rào cản lúc bắt đầu
      Tóm lại, cứ dùng Racket là được. Nếu thực sự cảm thấy cần tính năng hoặc phong cách lập trình khác, lúc đó hãy tìm xem đã có ngôn ngữ nào cung cấp chưa. Tất nhiên tất cả chỉ là ý kiến của tôi
    • Theo tôi biết, mỗi module có thể chọn ngôn ngữ của module đó
  • Website này, Hacker News, được viết bằng Arc và chạy trên Racket: https://en.wikipedia.org/wiki/Arc_(programming_language)

  • Vấn đề lớn nhất của Racket không phải là ngôn ngữ hay hệ sinh thái: https://news.ycombinator.com/item?id=27531508

    • Tôi từng là học viên của Racket school năm 2018 được nhắc đến trong liên kết. Tất cả giảng viên, bao gồm Felleisen và Butterick, đều thực sự hữu ích và thân thiện cả trong lẫn ngoài lớp học
      Ngay cả nếu cứ hiểu hoàn toàn theo nghĩa đen từ liên kết đó rằng Felleisen cư xử tệ kiểu Torvalds trong một số tương tác cá nhân cụ thể, thì các công trình của ông ấy, bao gồm How To Design Programs, đã có ảnh hưởng rất tích cực đến cuộc sống của tôi và của những người khác. Vì vậy tôi sẽ không bảo mọi người đừng tận dụng chúng
    • Đó là một xung đột rất cá nhân giữa các thành viên nổi tiếng trong cộng đồng. Cộng đồng Racket rộng hơn, bao gồm cả đội ngũ lõi, rất thân thiện
    • Felleisen là một người khó chịu đựng, nhưng cũng dễ tránh. Tôi xem đó là một triệu chứng gần với bệnh lý của giới học thuật hơn là của bản thân Racket
      Trong cộng đồng cũng có những “nerd kỳ quặc” với quan điểm mạnh, nên vì họ hiện diện nổi bật hơn nên có thể càng gây khó chịu hơn. Nhưng cũng như nhiều không gian xã hội không có tiền bạc giữ trật tự, đại loại là vậy thôi
  • Racket là ngôn ngữ tôi thích nhất. Nó nhanh, thực dụng, có nền tảng vững chắc và mô hình concurrency cũng rất tốt. Nó dựa trên các ý tưởng vay mượn và mở rộng từ Concurrent ML
    Hệ thống tài liệu cũng xuất sắc và được tích hợp với hệ sinh thái package, nên phần lớn package có tài liệu chất lượng cao với tham chiếu chéo. Tính tương thích ngược cũng tuyệt vời; tôi thấy tốt hơn nhiều so với Python mà tôi đang dùng trong công việc chính hiện nay
    Vì vậy, tôi cảm thấy những người nói Racket quá hàn lâm hoặc không thực dụng có lẽ chưa đào đủ sâu, hoặc trước đây là những sinh viên chỉ từng tiếp xúc với các ngôn ngữ phục vụ giáo dục
    Dĩ nhiên nó không hoàn hảo. Cộng đồng nhỏ, mức dùng bộ nhớ mặc định của runtime cao, và nếu muốn xử lý song song thì phải khởi chạy một Racket VM cho mỗi system thread, cùng các vấn đề khác. Dù vậy, những điều này sẽ dần cải thiện theo thời gian
    Những thứ tôi đã làm bằng Racket trong vài năm qua: trang thương mại điện tử[1], ứng dụng thông báo native cho macOS/iOS đã lên App Store[2, 3, 4], desktop client đa nền tảng cho Apache Kafka[5, 6, 7], #lang cho Lua[8]. Ngoài ra còn nhiều thứ khác[9][10][11]. Tôi nghĩ chúng khá thực dụng
    [1]: https://defn.io/2019/08/20/racket-ecommerce/
    [2]: https://defn.io/2020/01/02/ann-remember/
    [3]: https://defn.io/2024/04/09/ann-remember-for-ios/
    [4]: https://github.com/bogdanp/remember
    [5]: https://defn.io/2022/11/20/ann-franz/
    [6]: https://defn.io/2023/10/15/ann-franz-for-windows/
    [7]: https://defn.io/2023/08/10/ann-franz-source-available/
    [8]: https://defn.io/2022/11/12/ann-racket-lua/
    [9]: https://docs.racket-lang.org/http-easy/index.html
    [10]: https://docs.racket-lang.org/deta/index.html
    [11]: https://docs.racket-lang.org/gui-easy/index.html

    • Bogdan cũng là tác giả của gui-easyhttp-easy, hai thư viện không thể thiếu trong hệ sinh thái Racket
      Anh ấy cũng rất tích cực trên diễn đàn cộng đồng và đã đưa ra rất nhiều câu trả lời cực kỳ hữu ích
      Tôi nghĩ anh ấy là người hùng thầm lặng của ngôn ngữ này nên nhất định muốn nhắc đến. Có thể nói các thư viện của bạn đang vận hành những đoạn code giúp cuộc sống của những người dùng chẳng biết gì trở nên dễ dàng hơn nhiều :)
      https://docs.racket-lang.org/http-easy/index.html
      https://docs.racket-lang.org/gui-easy/index.html
      https://racket.discourse.group
    • Tôi nghĩ tương thích ngược là một điểm thật sự quan trọng. Tôi đã dùng Python chuyên sâu trong vài năm, nhưng khi thấy các lập trình viên lõi và cộng đồng ít quan tâm đến tương thích ngược như thế nào trong quá trình chuyển đổi 2/3, tôi đã rất thất vọng, và sau đó cũng không khá hơn
      Có thể là do các lĩnh vực mà Python chủ yếu được dùng ngày nay. Đợt chuyển đổi Numeric/Numpy khoảng năm 2000 thì hoàn toàn khác
      Việc bị phá vỡ vài năm một lần có thể chấp nhận được với các startup kỳ lân hoặc các công ty di chuyển nhanh và, theo đúng nghĩa đen, phá vỡ thứ gì đó. Nhưng cũng có rất nhiều chương trình có giá trị đối với những người và tổ chức không có dư nguồn lực để viết lại các thuật toán đã trưởng thành vài năm một lần, hoặc không xem việc đó là ưu tiên
  • Thỉnh thoảng tôi dùng Racket và thích nó. Tuy nhiên, tôi nhận ra rằng một số Lisp, đặc biệt là Common Lisp và có lẽ cả Guile, cũng đang bị đánh giá thấp hơn so với thực tế
    Muốn hỏi những người hiểu rõ hơn: có tính năng nào của Racket ban đầu trông không thực dụng, không liên quan hoặc không hữu ích, nhưng khi dùng rồi lại hữu ích một cách bất ngờ cho việc lập trình không?

  • Khoảng 20 năm trước, trước khi MzScheme trở thành PLT Scheme, tôi từng làm việc trên phần mềm thương mại về bảo mật email dùng nó làm ngôn ngữ nền tảng. Mã chạy đa nền tảng trên Solaris, Linux, HP-UX, và phần mã riêng cho từng hệ điều hành chỉ khoảng 1.000 dòng C
    Các quy tắc lọc được biên dịch thành chính Scheme. Toàn bộ mã, bao gồm cả UI nền web, khoảng 30.000 dòng, và chỉ có 5–6 lập trình viên
    Sau này, sau khi di cư, tôi vào một công ty có sản phẩm tương tự nhưng ít tính năng hơn; sản phẩm đó viết bằng C++ với hàng trăm nghìn dòng mã và cũng có nhiều lập trình viên hơn