2 điểm bởi GN⁺ 2024-11-29 | 1 bình luận | Chia sẻ qua WhatsApp
  • Janet for Mortals là một cuốn sách trực tuyến miễn phí về ngôn ngữ lập trình Janet, nhưng trọng tâm của bài hồi tưởng nằm ở quá trình tạo ra một tài liệu kỹ thuật bao gồm cả web REPL và các dự án ví dụ, hơn là bản thân cuốn sách
  • Toàn bộ công việc mất 20 tuần, vượt quá ước tính 12 tuần cho riêng phần viết thuần túy, vì phát sinh thêm các việc phụ như website, binding C++, demo trên trình duyệt, parser CLI và công cụ kiểm thử
  • Website của sách cung cấp REPL tích hợp dùng CodeMirror và cú pháp Lezer; tính năng tự động hoàn thành truy vấn môi trường Janet qua WebAssembly, còn (report) lưu phản hồi vào SQLite
  • cmd, judge, to do, Toodle.Studio được dùng làm các ví dụ nền tảng cho thấy Janet có thể được dùng cho scripting, công cụ CLI, kiểm thử, chạy trong trình duyệt và tương tác với JavaScript
  • Ngay sau khi ra mắt, chỉ nhờ đăng lên Hacker News và Lobsters, website có 30.025 khách truy cập duy nhất vào thứ Sáu, 9.568 vào thứ Bảy và 3.777 vào Chủ nhật, nhưng số IP duy nhất đọc từ 5 chương trở lên được ước tính là 387

Phạm vi cuốn sách và khối lượng công việc thực tế

  • Janet for Mortals là một cuốn sách trực tuyến miễn phí về ngôn ngữ lập trình Janet
  • Tổng thời gian thực hiện là 20 tuần, tính theo thời gian rảnh
    • Ước tính ban đầu là 12 tuần, và nếu chỉ xét thời gian viết phần nội dung tiếng Anh thì không sai lệch quá nhiều
    • Lịch trình thực tế bao gồm một phần lớn là các dự án lập trình xung quanh cuốn sách
  • Dung lượng cuối cùng là 44.000 từ văn xuôi tiếng Anh, không tính các đoạn mã
    • The Great Gatsby được đưa ra làm đối chiếu có 47.000 từ
    • Ngắn hơn chưa tới một nửa so với loạt bài trước đó về Nix
  • Trong 5 tháng, cùng với cuốn sách, các việc sau cũng được thực hiện
    • Website của sách
    • jimmy: binding cho thư viện cấu trúc dữ liệu bền vững C++
    • Toodle.Studio: sân chơi turtle graphics tương tác
    • cmd: thư viện phân tích đối số dòng lệnh
    • judge: framework kiểm thử snapshot inline
    • to do: trình quản lý danh sách việc cần làm trên dòng lệnh

Website và REPL tích hợp

  • Thiết bị cốt lõi của website Janet for MortalsREPL tích hợp
    • Người dùng có thể mở REPL bất cứ lúc nào bằng phím Escape
    • REPL được cố định ở cuối trang nên không che nhiều nội dung chính
  • Trình soạn thảo dùng CodeMirror
    • CodeMirror mặc định không hỗ trợ Janet
    • Nó dựa trên phần hỗ trợ ngôn ngữ Janet đã làm trước đó cho Bauble
    • Những cú pháp Janet như chuỗi multi`backtick`quoted, vốn không quan trọng trong Bauble DSL, lại cần thiết trong sách
  • Khi bổ sung cú pháp Lezer mà CodeMirror sử dụng, cùng một cú pháp cũng được tái sử dụng cho tô sáng cú pháp trong các đoạn mã của sách
    • Không tìm thấy static site generator quen thuộc nào hỗ trợ tô sáng mã Janet
    • Ban đầu cuốn sách chỉ có đen trắng, nhưng màu sắc được thêm vào để cú pháp Janet xa lạ trông thân thiện hơn
  • Static site generator được tự viết bằng redo
    • Phần lõi của generator được viết bằng JavaScript nên có thể gắn cú pháp Lezer vào
    • Toàn bộ cấu hình là một cấu trúc mong manh được nối với nhau bằng shell
  • Remark được dùng cả để phân tích bản thảo sách lẫn trong REPL phía client
    • Một extension đơn giản được thêm vào để gắn nhãn cho code block
    • Docstring trong thư viện chuẩn Janet được viết bằng Markdown, nên được render tức thời thành HTML trong tự động hoàn thành của REPL

Tự động hoàn thành và phản hồi một chiều

  • Tự động hoàn thành trong REPL được xem là quan trọng cho độc giả mới làm quen với Janet
    • Khi REPL khởi động, môi trường Janet được truy vấn động qua WebAssembly
    • Dù người dùng định nghĩa một symbol mới có docstring, nó cũng không xuất hiện trong kết quả tự động hoàn thành
    • Có thể tạo lại tự động hoàn thành sau mỗi lần chạy lệnh, nhưng được đánh giá là không đáng
  • Hàm (report) nhận một chuỗi rồi POST lên một web server đơn giản, và server lưu nó vào cơ sở dữ liệu SQLite
    • Tương tự một hộp bình luận, nhưng điểm đặc trưng là gửi trực tiếp từ REPL
    • Nhờ chức năng này, tác giả đọc phản hồi và sửa nhiều lỗi
    • Không triển khai cách trả lời
  • Backend report không phải Janet mà là một ứng dụng Haskell nhỏ
    • Nó chỉ có nhiệm vụ nhận yêu cầu POST và đưa vào cơ sở dữ liệu SQLite
  • Web server không được viết bằng Janet
    • Yếu tố quan trọng nhất của web server được xem là bảo mật
    • Janet và thư viện HTTP của Janet chưa được xem là đủ kiểm chứng để kết nối trực tiếp với Internet

jimmy: thử nghiệm tương tác C++

  • jimmy là binding Janet cho immer
    • immer là thư viện cấu trúc dữ liệu bền vững
  • Binding chưa hoàn thiện, và có khả năng sẽ không hoàn thiện cho tới khi phát sinh nhu cầu sử dụng
  • Dù vậy, nó vẫn được xem là một ví dụ thành công cho cách tương tác với mã C++ từ Janet

Toodle.Studio và Janet trong trình duyệt

  • Bauble là một sân chơi nghệ thuật nhỏ đã được tạo trước đó, và là trải nghiệm đầu tiên nhúng Janet vào trình duyệt
    • Khi đó không có nhiều tài liệu về nhúng Janet
    • Độ khó cao vì phải dùng WebAssembly, Emscripten và TypeScript cùng nhau trong trình duyệt
  • Kết quả cuối cùng của Bauble là một website có logic ứng dụng được viết bằng Janet
    • UI dùng nhiều JavaScript, nhưng logic cốt lõi do Janet đảm nhiệm
  • Một trong những động lực quan trọng để viết sách là muốn làm cho kỹ thuật dùng Janet trong trình duyệt trở nên dễ tiếp cận hơn
  • Trong sách, Toodle.Studio được tạo làm ví dụ thay cho Bauble
    • Bauble không có trạng thái và gần giống một hàm thuần biến chuỗi thành chuỗi, nên khá đơn giản xét từ góc độ tương tác
    • Toodle.Studio rõ ràng là một fork của Bauble, nhưng tương tác giữa JavaScript và Janet phức tạp hơn
  • Toodle.Studio có các yếu tố kỹ thuật phù hợp hơn cho ví dụ trong sách
    • Phải chạy bất đồng bộ một chương trình Janet chạy lâu theo thời gian
    • Vì mã JavaScript giữ cùng một giá trị Janet bằng nhiều tham chiếu, cần cân nhắc quản lý bộ nhớ
    • Phải trao đổi các cấu trúc dữ liệu lồng nhau phức tạp với Janet thông qua C++
  • Logo của Toodle.Studio là một chú rùa hoạt hình tạo bằng Bauble
    • Được thêm vào sau phản hồi rằng đây là demo turtle graphics nhưng lại không có rùa
    • Mắt của rùa được làm để nhìn theo chuột

cmd: parser đối số CLI cho Janet

  • cmd là thư viện phân tích đối số dòng lệnh
    • Trong sách nó chỉ xuất hiện khoảng ba đoạn, nhưng cần thiết để cho thấy rõ Janet là một ngôn ngữ scripting tốt
  • cmd chịu ảnh hưởng mạnh từ Core.Command của OCaml
    • Core.Command được xem là thư viện phân tích đối số dòng lệnh tốt nhất mà tác giả từng dùng
    • Tác giả cố tái hiện trải nghiệm đó trong Janet
  • cmd không tốt bằng Core.Command
    • Tác giả cho rằng mọi thứ sẽ dễ hơn rất nhiều nếu có kiểu
    • Dù vậy, nó có 95% các tính năng được xem là quan trọng, và nhờ ký pháp ngắn gọn nên tiện hơn cho các script ad-hoc
  • Vẫn còn thiếu chức năng sinh hàm tự động hoàn thành cho Bash
    • Core.Command tự động sinh phần này
    • API của cmd được thiết kế để sau này có thể thêm chức năng đó

judge: framework kiểm thử snapshot inline

  • judge là một trong những thứ đầu tiên được tác giả tạo bằng Janet vào năm 2021
  • Sau khi hiểu Janet hơn, tác giả đã viết lại từ đầu
    • API trở nên dễ dùng hơn
    • Phần triển khai cũng đơn giản hơn nhiều và dễ thay đổi hơn
  • Khác biệt chính giữa Judge v1 và v2 nằm ở vị trí test và helper
    • Test có thể nằm không chỉ trong thư mục test/ mà cả trong file nguồn thông thường
    • Thêm các helper test-macrotest-stdout
  • Cách làm tương ứng của OCaml cho test-stdout được nói là gần như cách duy nhất tác giả dùng khi viết test trong công việc
    • OCaml không có cách thật sự tiện để nhúng dữ liệu tùy ý vào mã nguồn, nên tiếp cận bằng cách biến mọi thứ thành chuỗi
  • Sau khi sách ra mắt, chế độ --interactive được thêm vào Judge

to do: công cụ việc cần làm viết bằng Janet thay vì Bash

  • to do được chọn làm ví dụ cho chương scripting
    • Đây là một công cụ không tầm thường tác giả từng viết bằng Bash, và phần triển khai Bash rất đau đớn
  • Những phần đặc biệt khó trong Bash là phân tích văn bản và xử lý ngày tháng
    • Phân tích văn bản nhiều dòng bằng Sed không hề dễ chịu
    • Thao tác date hoạt động giống nhau trên macOS và Linux được xem là gần như bất khả thi
  • Trong Janet, nhờ dùng PEG, shcmd, tác giả có thể tạo nhiều tính năng hơn, nhanh hơn so với danh sách việc cần làm Bash ban đầu
    • Ví dụ, thêm tính năng chọn nhiều bằng fzf
    • Việc tạo chuỗi null-terminated trong Bash được xem là khó
  • Sách chỉ đề cập phiên bản đơn giản hóa
    • Không có chức năng lên lịch việc trong tương lai
    • Không có khái niệm “bỏ qua” một việc
    • Chức năng cốt lõi là thêm mục vào danh sách và đánh dấu hoàn thành
  • Khi dùng cùng zsh-autoquoter, nó được xem là một ứng dụng hữu ích một cách bất ngờ

Công việc code và bảo trì trong quá trình viết

  • Trong 20 tuần làm sách, việc viết code chiếm gần một nửa
    • 8 tuần dành cho code, và trong một số giai đoạn tác giả vừa viết vừa code song song
  • Ban đầu, tác giả chỉ dự kiến cải tiến Judge và viết parser đối số
    • Việc triển khai parser đối số khó hơn dự kiến rất nhiều
    • Tác giả không ngờ Bauble lại quá đơn giản đến mức phải làm thêm một sân chơi nghệ thuật mới
  • Phần viết thực tế được thực hiện bằng Markdown trong Sublime Text
    • Sublime Text là editor tác giả ưa dùng để viết văn xuôi dài
  • Trong lúc viết, Janet có 2 phiên bản mới
    • Các chương về debug và native module phải được cập nhật theo thay đổi của ngôn ngữ
    • Tác giả dự định duy trì cuốn sách theo các bản phát hành Janet mới nhất

Phản ứng khi ra mắt và mức độ được đọc

  • Việc quảng bá sách chỉ gồm đăng lên Hacker News, đăng lên Lobsters và tweet
    • Trên Hacker News, nó nằm trên trang đầu cả ngày và có một thời gian đứng hạng 1
  • Theo log truy cập Nginx, số khách truy cập duy nhất như sau
    • Thứ Sáu: 30.025 người
    • Thứ Bảy: 9.568 người
    • Chủ nhật: 3.777 người
  • Các con số này gần với số người bấm vào liên kết; số người thực sự đọc sách được cho là ít hơn nhiều
  • Website không có phân tích theo dõi hành vi phía client
    • Chỉ có thể ước tính sơ bộ bằng log truy cập
  • Luồng truy cập các chương cho thấy tỷ lệ giữ chân không tốt
    • Chương 1: 22% số người vào trang chủ
    • Chương 2: 20% số người vào chương 1
    • Chương 3: 69% số người vào chương 2
    • Chương 4 “Pegular Expressions” và chương 9 “Xenofunctions” có lượng truy cập nhiều hơn chương 3
  • Tính đến cuối tuần ra mắt, ước tính tốt nhất về số độc giả thực sự là 387 người
    • Dựa trên số IP duy nhất đã tải từ 5 chương khác nhau trở lên

Nguồn gốc tên gọi và những giới hạn bộc lộ qua phản hồi

  • Tên ngôn ngữ Janet bắt nguồn từ Janet, thực thể bất tử trong The Good Place
    • Thực thể này giúp những mortals di chuyển trong thế giới sau khi chết, nên cũng liên hệ với tiêu đề cuốn sách
  • Chương có ít lượt truy cập nhất là “Testing and Debugging”
    • Đây là chương thứ ba từ cuối sách
    • Tác giả cho rằng ba chương cuối là phần thú vị nhất của sách
    • Phương pháp kiểm thử trong chương đó được xem là một trong những cải thiện năng suất lớn nhất trong sự nghiệp kỹ sư cá nhân của tác giả
  • Tác giả nhận được 494 phản hồi qua chức năng report của REPL tích hợp
    • Nhiều phản hồi là “sách hay” hoặc tin nhắn thử nghiệm
    • Hàng chục phản hồi là báo lỗi chính tả, yêu cầu giải thích hoặc bình luận hữu ích
  • Một số người dùng gửi câu hỏi mà không để lại thông tin liên hệ, và vì không có chức năng trả lời nên tác giả không thể phản hồi
    • Chức năng report được triển khai như một tính năng phản hồi một chiều rất thô sơ

1 bình luận

 
GN⁺ 2024-11-29
Ý kiến trên Hacker News
  • Cũng không thể bỏ qua https://bauble.studio/ của cùng tác giả
    Nó không chạy trên trình duyệt của chiếc máy tính cũ của tôi, nhưng khi học ở thư viện và muốn nghỉ một chút, tôi thường nghịch bauble khoảng 30 phút trên máy tính của thư viện
    Chỉ cần thay đổi các con số qua lại mà đã tạo được đồ họa rất ấn tượng, và tôi mong Janet sẽ tồn tại lâu dài

    • Trên MacBook Pro M1 Max đời 2021, MacOs 15.1.1, nó chạy trên Chrome nhưng trên Firefox thì gặp lỗi biên dịch unknown symbol twist
      error: script:16:1: compile error: unknown symbol twist
      in evaluate [lib/evaluator.janet] on line 81, column 7
      in bauble-evaluator/evaluate [lib/init.janet] on line 8, column 12
  • So sánh Janet với GNU Guile khá thú vị
    Điểm mạnh ban đầu của Guile là nó được tạo ra để dễ dùng song song với C, nhưng vì là một ngôn ngữ lâu đời nên có vẻ vẫn chưa tiếp nhận cảm giác hiện đại kiểu đưa trình quản lý gói vào mặc định trong toolchain của ngôn ngữ
    Điều tôi thích ở Guile là họ đã bỏ nhiều công sức để giải thích tính tương thích với chuẩn RNRS
    Tôi không rõ Janet thực sự giống Scheme đến mức nào, nhưng cũng thấy tò mò

    • Janet hoàn toàn không giống Scheme
      Nó gần với việc ai đó tạo ra Clojure trên nền Lua hơn
  • Cuốn sách ở https://janet.guide/, còn ngôn ngữ ở https://janet-lang.org/

  • Tôi thích cách tiếp cận thực dụng của cuốn sách này, và đó là lý do lớn khiến hiện tôi đang học bằng cách giải Everybody Codes bằng Janet
    https://everybody.codes

  • Cách diễn đạt “con rùa là một ẩn dụ” hơi đáng tiếc
    Con rùa không phải ẩn dụ mà là có thật: http://classicacorn.computinghistory.org.uk/8bit_focus/logo/...
    Tất nhiên nó đúng với định nghĩa ẩn dụ là “một thứ đại diện cho thứ khác, một biểu tượng”, nhưng nghe giống như trò đùa về việc hiểu nhầm biểu tượng lưu bằng đĩa mềm là tủ lạnh
    Cảm giác như thiếu mất bối cảnh rằng ngày xưa thực sự từng có những con rùa phần cứng thú vị và dễ thương

    • Có vẻ khó coi thứ hiện trên trang đó là con rùa “thật”
  • Chỉ nhìn tiêu đề, tôi tưởng đây là một trợ lý AI khác lấy cảm hứng từ Janet trong The Good Place, nên khá bất ngờ một cách dễ chịu khi hóa ra nó là một ngôn ngữ lập trình
    Ngôn ngữ Janet được đặt tên theo Janet, thực thể bất tử trong The Good Place giúp con người vượt qua thế giới bên kia, nên tiêu đề cũng là một trò đùa khéo léo phù hợp với điều đó
    Việc nó đi kèm PEG (ngữ pháp biểu thức phân tích cú pháp) thay vì một engine regex mặc định cũng khá bất ngờ
    Tôi luôn mong rằng nếu một ngôn ngữ cung cấp thư viện regex mặc định thì cũng nên đưa vào một PEG tử tế

    • GNU Guile cũng có thư viện PEG trong thư viện chuẩn
      Xem <https://www.gnu.org/software/guile/manual/html_node/PEG-Pars...>
    • Module spork của Janet có vị trí giống một kiểu libc, và cũng có tiểu module regex nên nhiều khả năng đã được cài đặt
      Tôi lần đầu tiếp xúc với PEG qua Janet, và thích việc nó mạnh mẽ mà dễ dùng
      Tôi đã đụng đến regex lắt nhắt hơn 20 năm, vậy mà chỉ sau vài tháng tôi đã hiểu PEG tốt hơn
      Trong cộng đồng Janet cũng có nhiều callback liên quan đến The Good Place, và nhiều module bên thứ ba được đặt theo tên các nhân vật
    • Elm cũng có cách tiếp cận tương tự
      elm/regexelm/parser không được tích hợp sẵn, nhưng elm/regex khuyên dùng elm/parser thay thế
      Tôi thích nguồn gốc cái tên, nhưng với một ngôn ngữ tên Janet thì có vẻ nó cũng có nghĩa vụ ưu tiên khả năng điều khiển
  • Tôi đã đọc cuốn sách, và vì nó khá thú vị, có cảm giác nghịch ngợm, nên việc học Janet trở nên vui hơn nhiều
    Tuy nhiên tài liệu ngôn ngữ còn thiếu sót ở nhiều điểm
    Các hàm hoặc lệnh thường chỉ được liệt kê, không có ví dụ hay giải thích, hoặc thiếu phần mô tả chúng làm gì
    Có nhiều lúc tôi thấy một tính năng trong sách nhưng không tìm được trong tài liệu, và đó là một trong những lý do khiến tôi dừng học dù vẫn thích Janet
    Tôi thích việc nó có nhiều giá trị mặc định hợp lý và có những điểm giống các ngôn ngữ mainstream hơn là cố bám vào các quy ước Lisp cũ kỹ
    Rốt cuộc vì không phải là cons list nên thực ra nó không phải Lisp, nhưng điều đó không sao
    Vấn đề là ngôn ngữ này chưa được ghi tài liệu đầy đủ

    • Tôi tò mò không biết bạn có nhớ hàm hoặc lệnh nào chưa được ghi tài liệu không
      Tôi đang hoạt động ở mức nào đó trong cộng đồng Janet, nên nếu biết phần nào còn thiếu, tôi có thể góp phần cải thiện tài liệu
    • Tôi cũng có trải nghiệm y hệt, chỉ khác là chưa đọc cuốn sách
      Thường chỉ có chữ ký hàm mà hoàn toàn không có giải thích thêm
      Tôi hiểu việc tạo tài liệu bao quát tốn nhiều thời gian và công sức, nhưng chuyện này xảy ra quá thường xuyên nên tôi đã bỏ xuống và bắt đầu tìm một Lisp khác có thể biên dịch thành binary
  • Tôi không thích nghi được với Janet cho lắm, nhưng không biết đó có phải vấn đề của tôi không
    Lisp duy nhất khác mà tôi từng dùng lâu là Emacs Lisp, còn Janet thì vừa đủ giống nhưng lại khác ở những điểm tinh tế, khiến tôi liên tục mắc lỗi nhỏ
    Tính năng PEG trên tài liệu trông hấp dẫn, nhưng cú pháp khó xử lý và dễ gây nhầm lẫn
    Tài liệu đầy đủ theo nghĩa là có mô tả mọi hàm, nhưng rất súc tích và thiếu ví dụ hoặc thông tin sử dụng hữu ích
    Có vẻ ngay cả các chức năng cơ bản như phân tích JSON cũng không được bao gồm
    Nếu với một ngôn ngữ dùng để viết script nhanh mà trước tiên phải tự viết parser JSON hoặc XML, thì công việc đó đã thất bại rồi
    Đây là chuyện khoảng 4 năm trước nên hệ sinh thái có thể đã tốt hơn, và có thể chính tiêu chí đánh giá Janet cho mục đích viết script của tôi đã sai
    Dù vậy, bài viết này khiến tôi muốn cài lại để thử

    • Những thứ như JSON và regex được đưa vào module spork, vốn có vị trí giống một kiểu libc
      Có xu hướng nội bộ khá mạnh là giữ phần lõi nhẹ
      Nhiều dự án phụ thuộc vào spork nên khả năng cao nó sẽ được cài đặt từ sớm
      Tôi nghĩ tài liệu khá ổn, nhưng đồng ý rằng vẫn còn khoảng trống về các ví dụ thực tế
      Phần này đang được https://janetdocs.com bổ sung, với liên kết tới “ví dụ cộng đồng” cho từng hàm
  • Hơi lạc đề, nhưng nhờ một bài blog khác của tác giả gốc mà tôi đã bắt đầu dùng bàn phím cơ tách đôi
    Tôi bị đau vai và cổ tay trong vài năm và nó đã giúp ích, tôi rất khuyến nghị xem thêm các bài viết khác của Ian

  • Cách nhấn Esc bất cứ lúc nào để mở REPL tích hợp gắn ở phía dưới có thể không phải là quyết định hay
    Trình duyệt đã có phím tắt mặc định cho Esc, và Firefox sẽ thoát khỏi chế độ toàn màn hình khi nhấn Esc