Niềm vui khi tạo ra phần mềm đồ chơi
(blog.jsbarretto.com)- Việc tạo ra phần mềm đồ chơi là một cách để khôi phục niềm vui và sự sáng tạo cốt lõi của phát triển phần mềm
- Trong thời đại mà niềm vui thuần khiết của việc phát triển phần mềm đang dần biến mất vì AI và quá trình công nghiệp hóa, việc tự làm những chương trình đồ chơi đơn giản như một dự án cá nhân có thể trở thành cơ hội để đạt được kiến thức hữu ích cho công việc thực tế cùng sự hiểu biết sâu sắc hơn
- Phần mềm đồ chơi tuân theo quy tắc 80:20, hiện thực hóa tối đa chức năng với lượng mã tối thiểu, và điều cốt lõi là tránh thiết kế quá mức hoặc ám ảnh về độ hoàn thiện
- Chính trải nghiệm tự mình va chạm và xây dựng, thay vì phụ thuộc vào các công cụ AI như LLM, mới là niềm vui cốt lõi của học hỏi và trưởng thành
Vì sao nên tạo nhiều chương trình đồ chơi hơn
- Câu nói nổi tiếng của Richard Feynman: “Điều gì tôi không thể tạo ra thì tôi không thể hiểu được” → trải nghiệm tự tay làm ra thứ gì đó dẫn đến sự hiểu biết sâu sắc
- Trái với lời khuyên quen thuộc là “đừng phát minh lại bánh xe”, trải nghiệm tự làm ra bánh xe dạy cho bạn nhiều điều hơn so với đọc sách hay học lý thuyết
- Gần đây, AI và quá trình công nghiệp hóa phần mềm đang đe dọa niềm vui và tinh thần thủ công trong phát triển
- Việc tạo phần mềm đồ chơi giúp khôi phục lại niềm vui giản dị khiến bạn say mê máy tính một lần nữa
Nguyên tắc của chương trình đồ chơi: Keep it simple
- Phần mềm đồ chơi tuân theo nguyên tắc 80:20: đạt 80% chức năng với 20% công sức
- Mục tiêu không phải là sản phẩm cuối cùng, mà là sự đơn giản và việc tự tay hiện thực các nguyên lý chính
- Nhấn mạnh cách làm chỉ viết đúng phần mã thực sự cần thiết, đồng thời cảnh giác với thiết kế cấu trúc quá đà (over-engineering)
- Khuyến khích cách tiếp cận để mọi đường đi trong mã vẫn ở trạng thái chưa được hiện thực, rồi mở rộng dần mỗi khi cần
- Ngay cả những hệ thống trông nhỏ bé cũng thường cho bạn trải nghiệm rằng khi thật sự bắt tay làm, chúng lại dễ tạo ra hơn tưởng tượng
Lợi ích bổ sung của phần mềm đồ chơi
- Kiến thức thu được từ các dự án đồ chơi thường hữu ích hơn mong đợi trong công việc thực tế, như truy vết vấn đề, sửa lỗi và ngăn ngừa sai sót
- Việc tự mình va chạm để trải nghiệm các ràng buộc mang lại cái nhìn sâu sắc về bản chất của phần mềm, và đôi khi còn giúp tìm ra những cách giải quyết mang tính đổi mới
Ví dụ: danh sách nhiều dự án phần mềm đồ chơi khác nhau
Trong 15 năm qua, tác giả đã tự hiện thực nhiều loại dự án đồ chơi và sắp xếp chúng theo độ khó cùng thời gian ước tính. Mỗi dự án đi kèm mô tả ngắn và tài liệu tham khảo bổ sung
- Regex engine (độ khó 4/10, 5 ngày) : Phân tích regex kiểu POSIX và xác định chuỗi khớp, giúp hiểu sâu cách regex hoạt động bên trong
- x86 OS kernel (độ khó 7/10, 2 tháng) : Bao gồm CLI, driver đơn giản, bộ quản lý bộ nhớ..., có thể mở rộng thêm với hệ thống tệp trong bộ nhớ, tệp thực thi ELF, GUI, cách ly tiến trình
- GameBoy/NES emulator (độ khó 6/10, 3 tuần) : Hiểu tập lệnh đơn giản và phần cứng, hiện thực PPU, PSG và các định dạng cartridge đặc biệt
- GameBoy Advance game (độ khó 3/10, 2 tuần) : Trò chơi đơn giản dựa trên sprite, cộng đồng phát triển GBA rất sôi động, cấu trúc hệ thống đủ để một người tự nắm bắt
- 2D physics engine (độ khó 5/10, 1 tuần) : Cơ học Newton cơ bản và xử lý va chạm đơn giản, có thể mở rộng sang hình học phức tạp, quán tính, thuật toán giải, soft body/tương tác phức hợp
- Trình thông dịch động (độ khó 4/10, 1~2 tuần) : Trình thông dịch tree-walking, việc tạo ngôn ngữ của riêng mình mang lại niềm vui cả về kỹ thuật lẫn sáng tạo
- Trình biên dịch họ C (độ khó 8/10, 3 tháng) : Thiết kế hệ thống kiểu đơn giản và môi trường đích, kiến trúc hỗ trợ nhiều tối ưu hóa và nhiều backend khác nhau
- Trình soạn thảo văn bản (độ khó 5/10, 2~4 tuần) : Bắt đầu từ nhập/xuất tệp đơn giản, có thể dùng UI toolkit (QT/GTK, v.v.), ưu tiên nền tảng console, bổ sung unicode, syntax highlighting, multi-buffer, LSP...
- Async runtime (độ khó 6/10, 1 tuần) : Với Rust, hiện thực xử lý tác vụ
impl Futurevà tính đồng thời, thêm I/O waking - Hash Map (độ khó 4/10, 3~5 ngày) : Hiểu nguyên lý hoạt động bên trong, học closed/open addressing và quy tắc Robin Hood, nắm được hiệu năng và thời điểm sử dụng phù hợp
- Rasteriser / Texture Mapper (độ khó 6/10, 2 tuần) : Học cấu trúc pipeline đồ họa 3D, toán vector, Z-buffer, có thể đào sâu tới texture mapping và thuật toán shading
- Signed Distance Field rendering (độ khó 5/10, 3 ngày) : Biểu diễn không gian bằng toán học, trực quan hóa đơn giản, hiểu hơn về shader và toán vector
- Voxel engine (độ khó 5/10, 2 tuần) : Nếu có kinh nghiệm đồ họa 3D hoặc phát triển game thì sẽ dễ nắm bắt, có thể thử thêm texture, sinh thủ tục, mạng...
- Threaded Virtual Machine (độ khó 6/10, 1 tuần) : Trình thông dịch nhanh, hiện thực interpreter tối ưu mà không cần sinh mã riêng cho từng kiến trúc, có thể đạt cảm nhận hiệu năng ngang compiler
- GUI toolkit (độ khó 6/10, 2~3 tuần) : Sau khi trải nghiệm viết công cụ UI cơ bản, có thể tự hiện thực thêm các tính năng nâng cao như layout engine, text shaping, accessibility
- Bộ mô phỏng cơ học quỹ đạo (độ khó 6/10, 1 tuần) : Hiện thực đơn giản mô hình hấp dẫn Newton, mở rộng sang tương tác nhiều thiên thể, thuật toán tích phân và trực quan hóa, thậm chí áp dụng dữ liệu NASA
- Bitwise Challenge (độ khó 3/10, 2~3 ngày) : Trò chơi có thể tái hiện chỉ với trạng thái 64-bit, rèn luyện quản lý trạng thái sáng tạo, có thể xem quy tắc chi tiết trên GitHub
- Khung ECS (độ khó 4/10, 1~2 tuần) : Tự hiện thực cấu trúc Entity-Component-System, tích hợp với hệ thống kiểu của ngôn ngữ, tinh chỉnh cho hiệu năng cao và các ràng buộc cụ thể
- CHIP-8 emulator (độ khó 3/10, 3~6 ngày) : Máy ảo đơn giản từ thập niên 1970, có thể hiện thực rất nhanh, quan sát và chạy nhiều fan game khác nhau
- Chess engine (độ khó 5/10, 2~5 ngày) : Bắt đầu từ luật chơi rồi dần phát triển, trải nghiệm bị chính engine mình tạo ra đánh bại là một cột mốc trưởng thành của lập trình viên
- POSIX Shell (độ khó 4/10, 3~5 ngày) : Hiểu nguyên lý và giới hạn của shell dựa trên POSIX, đạt hiểu biết sâu sắc và trải nghiệm vô số thủ thuật khi hiện thực khả năng tương thích với ngôn ngữ Shell thực tế
Lời khuyên về việc sử dụng công cụ như LLM
- Các công cụ tiên tiến như LLM cũng hữu ích, nhưng việc học thực sự sẽ sâu sắc hơn khi bạn tự mình khám phá trực tiếp
- Thay vì nhìn vào các giải pháp sẵn có, bạn có thể đạt cảm giác thành tựu sâu hơn trong quá trình khám phá vùng chưa biết và tìm ra lời giải của riêng mình
- Khi thực hiện dự án đồ chơi mà không dùng LLM, ban đầu có thể khá khó vì chưa quen, nhưng theo thời gian bạn sẽ cảm nhận được niềm vui kỹ thuật riêng biệt và cảm giác thành tựu rất lớn
- Di chuyển bằng ô tô thì không thể cảm nhận “runner’s high” của người chạy bộ → niềm vui sâu sắc đến từ trải nghiệm trực tiếp, không phải đường tắt
3 bình luận
Mình cũng đồng cảm với ý là nên thử làm mà không dùng LLM. Nếu không cần phát triển quá nhanh thì tự mình hiểu và làm từng thứ một có vẻ thú vị và đáng giá hơn.
À ra là đang nói về dự án đồ chơi nhỉ. Chỉ nhìn tiêu đề thôi nên tôi đã tưởng là đang nói đến việc làm phần mềm cho đồ chơi. Haha
Ý kiến Hacker News
Tôi tò mò không biết có ai dùng LLM như công cụ tìm kiếm không. Trước đây tôi hay lên Google tìm kiểu “pros cons mysql mongodb”, rồi đọc tài liệu chính thức, diễn đàn, blog, cả Stack Overflow nên tốn khá nhiều thời gian. Nhưng bản thân khoảng thời gian đọc và học đó thì lúc nào tôi cũng chào đón. Bây giờ tôi dùng prompt cụ thể hơn với LLM, kiểu “ưu nhược điểm của mysql vs mongodb khi lưu ảnh, cho kèm link tham khảo”. Nhờ vậy có thể nhanh chóng nắm được ý chính, lại có cả link nên không cần phụ thuộc vào ảo giác của mô hình. Thỉnh thoảng tôi cũng hỏi cụ thể như “hãy thiết kế data schema để lưu metadata ảnh bằng postgres, tôi muốn tách X sang bảng khác”, nhưng việc này chỉ dùng khi tôi biết rất rõ mình cần đầu ra như thế nào. Nói chung chỉ là khi tôi tiếc thời gian gõ, hoặc tạm quên tên kiểu dữ liệu cụ thể như
intvớiinteger/src/foovà giải thíchbarFeatuređược triển khai như thế nào. Giờ hãy xem dự án/src/bazvà giải thích vì sao cách tiếp cận của foo khó áp dụng vào baz”. Tôi không bắt nó làm thứ mới, mà dùng nó để chuyển dịch từ các dự án sẵn có sang ý tưởng của tôi. Còn những phần phát triển thật sự mới mẻ và nhiều thách thức thì tôi vẫn muốn tự code vì như thế mới vuiMột trong những quyết định tốt nhất cho sự nghiệp của tôi là dành 6 tháng nghỉ giữa hai công việc để làm dự án cá nhân. Ban đầu tôi có rất nhiều dự án muốn bắt tay vào, nhưng vì không có ràng buộc nên phạm vi cứ phình ra và cuối cùng thường không hoàn thành được. Vì vậy tôi quyết định mỗi dự án chỉ đầu tư 1 tuần. Trong 1 tuần thì làm được đến đâu hay đến đó. Kinh nghiệm bắt đầu từ số 0 rồi chỉ trong 1 tuần tạo ra được thứ gì đó dùng được bằng ngôn ngữ, framework mới hoặc trong một lĩnh vực xa lạ đã giúp tôi tích lũy sự tự tin rất lớn. Nó cũng khiến tôi nhớ lại vì sao mình vốn thích lập trình. Nếu bạn có vài tháng nghỉ giữa hai công việc, thay vì ôn phỏng vấn kiểu Silicon Valley, hãy thử làm toy project; bạn sẽ ngạc nhiên vì bản thân thật ra đã biết được nhiều đến mức nào
Phát triển phần mềm toy giống như bảo dưỡng xe đạp, ô tô hay thuyền vậy. Rất vui. Nhưng sửa chiếc xe đạp để đi làm thì lại căng thẳng. Làm phần mềm toy thì vui, nhưng đến lúc muốn thật sự dùng nó cho bản thân thì sẽ bắt đầu phát hiện ra đủ loại bug, trong khi lại không có thời gian sửa; đó là một thế tiến thoái lưỡng nan
Tôi ngạc nhiên vì có quá nhiều ý kiến tiêu cực về LLM. LLM đút thông tin tận miệng cho bạn. Khi bắt đầu dự án mới, hiển nhiên không ai đã biết hết mọi thứ từ đầu. Cố hết sức rồi thất bại, sau đó học, hiểu tại sao thất bại, rồi điều chỉnh bằng cách khác mới là học thật sự. Nếu cứ tưởng mình biết hết rồi làm theo tutorial, bạn sẽ không trải nghiệm được giới hạn của từng cách làm hay ưu nhược điểm thật sự. Ví dụ, nếu thử làm parser bằng regular expression rồi tự mình phát hiện ra không xử lý được biểu thức đệ quy, thì bạn sẽ học được rất cụ thể về cấu trúc phức tạp hơn hay vấn đề độ phức tạp thời gian. Khi tự tay hiện thực một compiler tối ưu hóa và vật lộn với đủ loại mẹo tối ưu, bạn sẽ hiểu vì sao compiler thật được thiết kế như vậy. Tự viết layout engine thì mới cảm được ngay cả khái niệm
widthcũng có thể khó nhằn đến đâu. Không có trải nghiệm nào tốt hơn việc học qua thử và sai. Tôi không muốn vì LLM ngăn bớt sai lầm mà người ta lại bỏ lỡ luôn những cơ hội học tập quan trọngTôi cũng đã dành nhiều năm, cả cuối tuần lẫn thức đêm, làm vô số dự án kỳ quặc để học computer graphics. Tôi không kiếm được đồng nào từ đó, nhưng chính nhờ vậy tôi có được công việc mơ ước. Một vài sản phẩm tiêu biểu:
Tôi thấy tinh thần “niềm vui của lập trình” mà bài này đưa ra thực sự rất cần thiết. Trong thời đại coding bằng AI agent thì lại càng quý giá hơn. Tuy nhiên tôi thấy thời lượng dự kiến mà tác giả đưa ra cho các toy project là quá ngắn. Tôi cũng không phải người làm chậm hơn trung bình, nhưng tôi vẫn nghĩ đa số các mục trong danh sách đó, nếu giả sử chỉ làm 2–3 tiếng mỗi ngày, thì không phải loại dự án xong trong vài ngày. Chỉ riêng khâu nghiên cứu trước khi bắt đầu cũng đã tốn đáng kể. Ví dụ, gần đây tôi thay blog Pelican của mình bằng một Odin static site generator tự làm; dù chỉ dành 2–3 tiếng mỗi ngày thì cũng mất 2 tuần. Mà đó còn là việc dễ hơn nhiều dự án khác trong danh sách
Tôi cũng đồng ý với lời khuyên “đừng dùng LLM cho kiểu dự án này”, nhưng tôi không muốn hiểu nó một cách quá cực đoan. Điều thú vị là lời khuyên về cách nhận trợ giúp từ AI lại tạo cảm giác khác với việc nhờ người khác giúp. Nếu dưới cuối bài blog ghi “nếu bạn có một người bạn giỏi lập trình thì tuyệt đối đừng nhờ họ giúp”, nghe sẽ rất kỳ. Một người bạn là chuyên gia sẽ hiểu ngữ cảnh và giúp bạn tự giải quyết. Tôi nghĩ gần như chẳng ai thật sự yêu cầu AI kiểu “đừng giải hộ bài toán, hãy hướng dẫn tôi như một người bạn chuyên gia”. Dĩ nhiên hiện tại nó có thể chưa làm được hoặc làm chưa tốt, nhưng biết đâu trong 1–2 năm nữa kiểu hướng dẫn như vậy sẽ trở nên rất tự nhiên. Vì thế tôi nghĩ nên tập thói quen “truyền đạt rõ mình muốn kiểu trợ giúp nào”. Không cần phải mang định kiến rằng LLM lúc nào cũng chỉ đưa ra đáp án sai nhưng nghe hợp lý
Nhờ vibe coding với Claude mà lần đầu sau rất lâu tôi mới lại bắt đầu một side project thú vị. Sau khi quen công cụ và quy trình, chỉ trong vài tuần tôi đã nhanh chóng tạo ra đủ loại ứng dụng như dashboard lịch/giao diện thời tiết cho gia đình, app đọc Bluesky (ẩn các bài đã xem), dashboard PM trong công ty có gamification, tiện ích Chrome ẩn bài Reddit sau một khoảng thời gian nhất định, ứng dụng thay thế cho plugin WordPress không còn được bảo trì, v.v. Ban đầu tôi giao cho Claude khá nhiều việc như cải thiện UI, nhưng giờ tôi đã học được cách hài lòng với mức hoàn thiện 90% và tập trung vào tính năng của ứng dụng mới thay vì cứ mài giũa thêm
Danh sách này thực sự ấn tượng. Nhiều dự án mà tác giả thấy dễ thì với tôi có lẽ là mức độ khó tăng vọt. Nhưng nó chắc chắn có tác dụng khích lệ khiến tôi muốn quay lại với toy project của mình. Tuy nhiên, kết luận về việc dùng LLM để học thì tinh tế hơn nhiều. Dùng thế nào tạo ra khác biệt hoàn toàn. Chẳng hạn, yêu cầu kiểu “cứ triển khai hộ tôi bài toán này” là cách tệ nhất để học, còn kiểu “hãy giải thích cấu trúc của ELF ở mức trừu tượng cao nhất, tập trung vào ‘vì sao’” thì ngược lại có thể là chất xúc tác học tập cực mạnh. Việc không còn phải tự nghiên cứu mọi thứ mỗi lần có thể là nhược điểm, nhưng nếu bạn thật sự giữ thái độ suy nghĩ nghiêm túc, thì việc lúc nào cũng có thể nhận được hỏi đáp kiểu Socrates là một cú tăng tốc học tập đáng kể
Các dự án được giới thiệu ở đây đúng là ý tưởng hay, nhưng với tôi thì chẳng có cái nào thú vị cả. Mỗi lúc như vậy tôi lại tự hỏi liệu mình có thật sự từng yêu thích lập trình không