'Lập trình viên não Grug' (2022)
(grugbrain.dev)- Bài học lớn nhất lặp đi lặp lại sau thời gian dài làm phát triển phần mềm là độ phức tạp là “kẻ thù vĩnh viễn” của codebase, và nó tạo ra trạng thái mà một thay đổi nhỏ lại làm hỏng những chỗ không liên quan
- Công cụ mạnh nhất để giảm độ phức tạp là nói “no” với tính năng và trừu tượng hóa, nhưng khi cần thỏa hiệp thực tế thì dùng giải pháp 80/20 để mang lại phần lớn giá trị với ít code hơn
- Thiết kế và kiểm thử nên đặt trọng tâm vào việc tìm ra ranh giới tốt sau khi hình dạng hệ thống đã lộ rõ, thay vì trừu tượng hóa quá sớm, và coi trọng kiểm thử tích hợp bền lâu hơn kiểm thử đơn vị
- Công cụ, hệ thống kiểu, logging, debugger, thiết kế API phải giảm gánh nặng nhận thức cho lập trình viên, và giá trị thực dụng lớn nhất của hệ thống kiểu nằm ở IDE tự động hoàn thành
- Những kỹ thuật có tên gọi hay như DRY, tách biệt mối quan tâm, microservice, SPA, generic, hay refactor quá tay cũng có thể trở thành con đường dẫn tới độ phức tạp nếu chúng làm code khó hiểu và khó bảo trì hơn
Độ phức tạp là rủi ro số một của codebase
- Độ phức tạp ban đầu có thể vẫn còn hiểu được, nhưng rồi đột nhiên khiến hệ thống trở nên khó xử lý, và thay đổi ở một chỗ lại làm hỏng chỗ khác tưởng như không liên quan
- Độ phức tạp có thể đi vào qua những lập trình viên hay quản lý dự án có ý tốt, và đôi khi chính độ phức tạp do bản thân mang vào lại là nguyên nhân của vấn đề
- Không có “cây gậy” vạn năng nào để giải quyết độ phức tạp, và cách ứng phó tốt nhất là đừng đưa nó vào ngay từ đầu
“no” và “ok”: từ chối và thỏa hiệp thực tế
- Vũ khí tốt nhất để ngăn độ phức tạp là “no”
- “Không làm tính năng đó”
- “Không tạo trừu tượng hóa đó”
- Tuy vậy, “no” dù là lời khuyên kỹ thuật tốt, lại có thể bất lợi cho phần thưởng nhiều hơn hay thăng tiến
- Khi thực tế buộc phải thỏa hiệp, hãy trả lời “ok” rồi tìm 80/20 solution
- Cách làm hiện thực 80% giá trị mong muốn bằng 20% lượng code
- Có thể không có đủ mọi tính năng trang trí và trông hơi xấu, nhưng vẫn chuyển được phần lớn giá trị trong khi giữ độ phức tạp ở mức thấp
- Vì quản lý dự án đôi khi quên chi tiết yêu cầu, thay đổi chỗ làm hoặc nghỉ việc, nên đôi lúc cách 80/20 lại là lựa chọn tốt hơn
Thiết kế và phân rã code quá sớm là nguy hiểm
- Ở giai đoạn đầu dự án, hình dạng hệ thống vẫn còn mơ hồ như “nước”, nên tránh phân rã quá sớm
- Theo thời gian, những ranh giới tốt sẽ dần lộ ra
- Giao diện với phần còn lại của hệ thống hẹp
- Che giấu độ phức tạp bên trong bằng một số ít hàm hoặc trừu tượng hóa
- Nếu tạo trừu tượng hóa quá sớm thì rất dễ sinh ra trừu tượng hóa sai, nên nghiêng nhiều hơn về phía chờ đợi
- Với những lập trình viên muốn dựng trừu tượng hóa lớn ngay từ đầu, có thể giao cho họ những sản phẩm có thể vứt bỏ như UML, hoặc yêu cầu một bản demo chạy được vào ngày mai
- Prototype ban đầu cho thấy code thực sự chạy và các ràng buộc thực tế nhanh hơn
Kiểm thử không phải “để sau gom lại”, mà là “đi cùng khi hình dạng dần rõ”
- Kiểm thử ngăn được nhiều vấn đề, nhưng tác giả phản đối cách ép buộc test first ngay cả khi chưa hiểu domain
- Tác giả thích viết phần lớn kiểm thử khi code bắt đầu cứng cáp sau giai đoạn prototype
- Thái độ bỏ qua kiểm thử với câu “chạy trên máy tôi” là rất tệ
- Sở thích với từng loại kiểm thử khá rõ ràng
- unit tests: hữu ích ở đầu dự án, nhưng dễ vỡ khi thay đổi triển khai và có thể làm refactor khó hơn
- end to end: cho thấy hành vi toàn hệ thống, nhưng khi vỡ thì khó hiểu nguyên nhân, và nếu vỡ thường xuyên thì dễ bị phớt lờ
- integration tests: đủ cao để thấy tính đúng đắn của hệ thống, nhưng cũng đủ thấp để tìm nguyên nhân bằng debugger, nên gần với điểm tối ưu nhất
- Khi API ở các ranh giới đã ổn định, hãy đầu tư mạnh vào kiểm thử tích hợp quanh chúng
- Hãy giữ kiểm thử end-to-end thành một tập nhỏ, được quản lý tốt, tập trung vào các chức năng UI phổ biến nhất và một số edge case quan trọng
- Chỉ dùng mocking khi thật cần, và nếu có thể thì chỉ ở cấp ranh giới lớn
- Khi phát hiện bug, tác giả thích ngoại lệ theo cách trước tiên tái hiện nó bằng kiểm thử hồi quy rồi mới sửa
Agile, refactor, Chesterton's Fence
- Agile tự nó không phải thứ tệ nhất, và có thể dùng như một cách tổ chức phát triển, nhưng cần cảnh giác với những “agile shaman” dùng nó như công cụ miễn trừ trách nhiệm cho thất bại
- Prototype, công cụ tốt và tuyển được lập trình viên giỏi quan trọng hơn cho thành công phần mềm, và không quy trình nào là silver bullet giải quyết mọi vấn đề
- Refactor hữu ích, đặc biệt khi code đã cứng lại ở giai đoạn sau của dự án, nhưng refactor càng lớn thì xác suất thất bại càng cao
- Chia nhỏ để thực hiện
- Giữ hệ thống ở trạng thái tiếp tục hoạt động càng nhiều càng tốt
- Chỉ sang bước tiếp theo sau khi xong từng bước
- Trừu tượng hóa quá mức có thể dẫn tới thất bại của refactor và cả thất bại hệ thống
- Chesterton's Fence gắn với thái độ rằng ngay cả code xấu xí cũng đừng xóa trước khi hiểu vì sao nó tồn tại
- Code đang chạy, dù không hoàn hảo, vẫn cần được tôn trọng, và hệ thống càng lớn thì càng cần thời gian để hiểu trước
Microservice và công cụ
- Microservice thêm cả network call vào bài toán vốn đã khó là chia hệ thống cho đúng
- Công cụ có thể nâng mạnh năng suất và khả năng hiểu của lập trình viên
- Trong môi trường mới, đáng để dành thời gian học công cụ
- Hai tuần học công cụ có thể khiến tốc độ phát triển nhanh gấp đôi
- Nếu không có tài liệu thì cần hỏi lập trình viên khác và đào sâu tìm hiểu
- Code completion trong IDE giúp không cần nhớ hết API, và với phát triển Java thì gần như thiết yếu
- Một debugger tốt là cực kỳ quan trọng
- breakpoint có điều kiện
- đánh giá biểu thức
- duyệt stack
- Lập trình viên mới nên học sâu debugger sẵn có, vì nó có thể dạy nhiều điều về máy tính hơn cả môn học ở đại học
Hệ thống kiểu, biểu thức, DRY
- Giá trị lớn nhất của hệ thống kiểu nằm ở hỗ trợ công cụ, nơi khi gõ dấu chấm thì hiện ra danh sách thao tác có thể dùng
- Tính chính xác của kiểu cũng tốt, nhưng code completion và điều hướng mới có giá trị thực dụng lớn hơn
- Cần cảnh giác với những lập trình viên dùng hệ thống kiểu theo cách quá trừu tượng
- Generic đặc biệt có thể nguy hiểm
- Trong đa số trường hợp, tác giả thích giới hạn chúng ở mức lớp container
- Thay vì dồn các biểu thức điều kiện ngắn lên một dòng, nên tách ra bằng các biến trung gian có tên có nghĩa để dễ debug và dễ hiểu hơn
- DRY là lời khuyên tốt, nhưng cần cân bằng
- Code lặp đơn giản, rõ ràng đôi khi tốt hơn callback, closure hay object model phức tạp
- Nếu bản thân việc loại bỏ lặp lại làm tăng độ phức tạp thì cái giá phải trả có thể không đáng
Tách biệt mối quan tâm, closure, logging
- Separation of Concern là ý tưởng mạnh, nhưng trên thực tế có thể khiến người ta phải qua lại nhiều file để hiểu hành vi, làm tốn thời gian
- Thay vào đó, tác giả thích locality of behavior
- Đặt code gần “thứ đang hoạt động” thì khi nhìn vào đối tượng đó có thể biết ngay nó làm gì
- Closure phù hợp để trừu tượng hóa các phép toán trên collection, nhưng chỉ cần ít như muối là đủ
- “Callback hell” của JavaScript là ví dụ về độ phức tạp do lạm dụng closure
- Logging cực kỳ quan trọng, nhất là trong môi trường triển khai cloud
- Ghi log ở mỗi nhánh logic chính
- Với request đi qua nhiều máy, hãy kèm request ID để có thể nhóm log lại
- Nếu có thể, điều chỉnh mức log một cách động
- Nếu có thể, điều chỉnh mức log theo từng người dùng để debug vấn đề của người dùng cụ thể
- Thư viện logging có thể phức tạp, nhưng đầu tư xây dựng hạ tầng logging đúng đắn sẽ đem lại phần thưởng lớn về sau
Đồng thời, tối ưu hóa, API
- Concurrent là lĩnh vực đáng sợ, và tác giả thích các mô hình đơn giản nhất có thể
- request handler web không trạng thái
- hàng đợi tác vụ từ xa không phụ thuộc lẫn nhau
- API đơn giản
- Trên web, optimistic concurrency có thể rất phù hợp
- Ngay cả cấu trúc dữ liệu đồng thời như ConcurrentHashMap của Java cũng cần dùng cẩn thận
- Chỉ nên bắt đầu tối ưu hóa sau khi đã xác nhận vấn đề cụ thể bằng hồ sơ hiệu năng thực tế
- Không nên chỉ nhìn CPU
- Truy cập mạng tương đương với rất nhiều chu kỳ CPU, nên nếu có thể thì hãy giảm nó
- Nhìn thấy vòng lặp lồng nhau rồi lập tức lao vào loại bỏ
O(n^2)có thể làm độ phức tạp tăng lên
- API tốt phải khiến lập trình viên không cần suy nghĩ quá nhiều
- Nếu người viết API bị mắc kẹt ở góc nhìn triển khai hoặc góc nhìn domain thì API sẽ khó dùng
- Với trường hợp đơn giản, nên cung cấp API đơn giản; với trường hợp phức tạp, nên cung cấp API phức tạp hơn riêng biệt theo kiểu phân tầng
- Nếu theo hướng hướng đối tượng, thì hành vi nên nằm trên chính đối tượng đó càng nhiều càng tốt
- Ví dụ stream/collector của Java bị phê phán là API khiến các tác vụ phổ biến phải đi đường vòng không cần thiết
Parsing, Visitor Pattern, frontend
- Tác giả cho rằng parser kiểu recursive descent rất thú vị và đẹp
- Parser generator khiến code sinh ra khó hiểu và khó debug, đồng thời che giấu bản chất đệ quy của ngữ pháp
- Hầu hết parser production thực tế đều là recursive descent, và tác giả khuyên đọc Crafting Interpreters
- Visitor pattern được tóm gọn ngắn gọn là “bad”
- Việc tách frontend và backend rồi nối SPA library với GraphQL JSON API qua HTTP gần như là tạo hai ổ phức tạp
- Tác giả cảnh giác với xu hướng dùng thư viện frontend lớn ngay cả cho website đơn giản hay form chỉ cần ghi vào cơ sở dữ liệu
- Để giảm độ phức tạp, tác giả đã tạo ra htmx và hyperscript
- Giữ HTML đơn giản
- Tránh nhiều JavaScript
- React tốt hơn cho việc làm và một số loại ứng dụng, nhưng được xem là một lựa chọn bước vào con đường phức tạp của frontend
Trào lưu, FOLD, impostor syndrome
- Trong phát triển có rất nhiều trào lưu, và điều này đặc biệt rõ ở frontend
- Cần nghi ngờ những cách tiếp cận mới tự xưng là mang tính cách mạng
- Trong ngành máy tính, rất nhiều ý tưởng đã từng được thử ít nhất một lần
- Ý tưởng tệ có thể quay lại với tên mới
- Việc senior công khai nói “cái này quá phức tạp nên khó hiểu” là điều tốt
- FOLD là viết tắt của Fear Of Looking Dumb, tức trạng thái không dám thừa nhận sự phức tạp vì sợ trông ngu ngốc
- Nếu senior nói rằng nó phức tạp, junior cũng sẽ dễ thừa nhận rằng mình không hiểu hơn
- FOLD là nguồn lớn khiến độ phức tạp có thêm sức mạnh, nhất là với lập trình viên trẻ
- Lập trình viên dao động giữa cảm giác mình kiểm soát được mọi thứ và cảm giác chẳng biết gì cả, nên impostor syndrome là chuyện rất phổ biến
- Nếu ai cũng thấy mình như impostor thì chẳng ai là impostor cả, và lập trình viên trẻ vẫn có thể tiếp tục sự nghiệp dù có thất vọng và lo lắng
Đề xuất tài liệu đọc và kết luận
- Tài liệu đọc đề xuất
- Kết luận cuối cùng vẫn giống như lúc đầu: độ phức tạp là thứ rất, rất tệ
1 bình luận
Các ý kiến trên Hacker News
Thật lạ là những người thông minh lại bị độ phức tạp thu hút như thiêu thân lao vào lửa
Mất nhiều năm để học cách chống lại thôi thúc muốn thiết kế quá mức
Một khi đã bắt đầu nhìn ra, nó trở nên khó phớt lờ, và giờ tôi có thể biết ngay mã có bị thiết kế quá mức hay không
Đáng buồn là khoảng 99% mã trông như bị thiết kế quá mức, và các động lực khiến lập trình viên tối đa hóa tính không thể thay thế của bản thân cũng như số giờ tính phí hoạt động rất mạnh
Ngay cả những lập trình viên trông hoàn toàn máy móc và không có cái tôi cũng thường thiết kế quá mức; điều này vận hành trong vô thức
Nhiều lập trình viên không suy nghĩ có ý thức về từng dòng mã họ viết; họ chỉ đặt mục tiêu rồi lôi ra đoạn mã đầu tiên đưa họ tiến gần hơn một chút tới mục tiêu đó, nên không nhận ra rằng ở mỗi bước đều đã có một phương án tốt hơn
Thứ nhất, tôi thích những câu đố thú vị. Đặc biệt mã thương mại, nếu làm đúng, thường khá nhàm chán, nên trong vô thức tôi lại thúc đẩy những tính năng thú vị khi triển khai. Mà thú vị ở đây rốt cuộc có nghĩa là những tính năng làm mọi thứ phức tạp quá mức
Thứ hai, khi đang lập trình một thứ gì đó, mọi lựa chọn tôi đưa ra đều trông hiển nhiên và cần thiết. Chỉ sau này, khi rời xa đoạn mã rồi quay lại cố hiểu nó bằng con mắt mới, tôi mới thấy mình đã làm nó rối tung đến mức nào
Với phần lớn vấn đề, lời giải dễ thấy nhất thường khá phức tạp, còn biết tìm lời giải đơn giản ở đâu thì cần có trí tuệ, kỹ năng và kiến thức miền. Một lời giải đơn giản, gọn gàng hầu như không bao giờ là hiển nhiên
“Chúng ta đang dần triển khai một message queue làm dở dang một nửa. Cứ dùng message queue tiêu chuẩn đi”, “Chúng ta đang tạo một giao thức framing nhị phân tùy biến đầy lỗi. Cứ dùng protobuf/msgpack đi”, “Đừng tạo giao thức RPC tùy biến để lấy dữ liệu; hãy dùng REST trên HTTP. Như vậy có thể đặt nginx ở giữa để cache phản hồi backend và bỏ cả cache tùy biến đi”
Rốt cuộc, nếu có thời gian và được thưởng để làm vậy, ta có thể viết mã hoàn hảo, đơn giản và không lặp lại. Nhưng đa số lại được thưởng vì tung ra thứ gì đó, và vì thể hiện năng lực kỹ thuật qua khối lượng công việc, trí tuệ và năng lực thiết kế đã bỏ vào để phát hành nó
Kết luận tự nhiên là mọi thứ phình to thành một đống giải pháp tạm bợ bị thiết kế quá mức, rồi cứ 3–7 năm lại viết lại
Tôi chưa xem dữ liệu, nhưng có vẻ “chu kỳ bán rã của việc viết lại” có tương quan với tỷ lệ nghỉ việc hoặc thời gian làm việc trung bình. Dù mọi người cố gắng hơn để không thiết kế quá mức thì khả năng cuối cùng vẫn bị viết lại là rất cao
Với một người cầu toàn thì điều này thật khó chịu, nhưng đôi khi tạo ra thứ phức tạp và bị thiết kế quá mức lại được đền đáp tốt hơn là suy nghĩ lâu hơn để tìm ra lời giải đơn giản tốt nhất. Có thể có những tổ chức tốt hơn, nhưng sau 9 năm làm kỹ sư phần mềm tôi vẫn chưa tìm thấy
Dự án nguồn mở là phản ví dụ tốt nhất hiện lên trong đầu, nhưng ngay cả thư viện tốt cũng thường bị viết lại hoặc ra phiên bản mới khi người bảo trì thay đổi. Giữa nguồn mở và mớ linh tinh doanh nghiệp mà nhiều kỹ sư phần mềm toàn thời gian trên HN nhìn thấy có các động lực tài chính rất khác nhau. Nó giống như so sánh một bài báo học thuật được trau chuốt kỹ với một email công việc viết qua loa
Tôi nhớ Casey của Handmade Hero từng gọi phong cách lập trình của mình là “dựa trên nén”. Tức là cứ viết mã trước, rồi dần dần tách những thứ thuộc về nhau ra
Khi có lặp lại thì mới trừu tượng hóa, chứ không chủ ý thiết kế để trừu tượng hóa. Tôi ngày càng dùng cách này nhiều hơn
Bản thân điều đó không nhất thiết có nghĩa là sai, nhưng nếu là việc đánh giá chất lượng công việc của người khác thì có vẻ khả năng cao là có thiên kiến mạnh
Tôi thật sự thích trang này và lúc nào nó cũng làm tôi bật cười. Phần tôi thích nhất đặc biệt là microservice
“grug tự hỏi vì sao big brain lại lấy việc khó nhất, là chia hệ thống cho đúng, rồi còn nhét thêm cả lời gọi mạng vào đó. Với grug, chuyện này trông rất khó hiểu”
“Độ phức tạp là rất, rất xấu”
“Nếu phải chọn giữa độ phức tạp và đấu 1:1 với khủng long bạo chúa, grug sẽ chọn khủng long bạo chúa. Ít nhất grug còn nhìn thấy được khủng long bạo chúa”
Tôi có vài điểm không hài lòng về phần kiểu dữ liệu
grug nói rằng hơn 90% giá trị của hệ thống kiểu nằm ở việc danh sách những thứ có thể làm hiện ra như phép màu khi nhấn dấu chấm trên bàn phím, nhưng các junior ở công ty tôi thường xuyên deploy code bị vỡ trong production vì truy cập null, và Sentry báo cho chúng tôi biết chuyện đó
Trong các giai đoạn phát triển tập trung, trung bình mỗi junior developer có khoảng một bug truy cập null được phát hiện mỗi ngày
Nếu dùng một hệ thống kiểu đúng nghĩa có kiểm tra tĩnh, IDE sẽ báo kiểu “cái này có thể là null đấy, chắc chứ?”, và điều đó có lẽ sẽ cực kỳ hữu ích
Và ngay cả không có kiểu tĩnh thì vẫn có thể tự động hoàn thành
Đoạn “các pháp sư hệ thống kiểu não to nói rằng độ chính xác của kiểu là cốt lõi của hệ thống kiểu, nhưng grug thấy những pháp sư đó không thường xuyên deploy code. Code không được deploy theo một nghĩa nào đó có thể là đúng, nhưng đó không phải là cái đúng mà grug nói tới” là thô lỗ và không cần thiết
Tôi chủ yếu từng deploy code bằng C, PHP, Python, Haskell và Python có type annotation; với các ngôn ngữ có kiểu, tỷ lệ bug lọt tới production thấp hơn hẳn. Đó là một trong những lý do tôi thích kiểu dữ liệu
Ngoài ra, refactoring cũng dễ hơn nhiều. Khi thay đổi thứ được dùng rộng rãi, bạn có thể kiểm tra một cách đáng tin cậy các chỗ gọi bị vỡ trong toàn bộ codebase chỉ trong vài giây, và điều đó giúp ích rất nhiều cho việc cải tiến lặp lại một codebase ngày càng lớn
Thay vào đó, bạn đang chấp nhận một hệ thống kiểu mang tính thỏa hiệp: bắt được một số vấn đề và quan trọng nhất là đem lại phép màu tự động hoàn thành, nhưng không bị sa lầy vào mọi chi tiết cần thiết cho một chứng minh tính đúng đắn hoàn chỉnh
Có vẻ ông ấy thấy kiểu tĩnh ở mức C hoặc Java là ổn hoặc tốt, còn những thứ màu mè hơn như trong Rust hay Scala là lãng phí thời gian. Tôi nghĩ ông ấy hoàn toàn sai, nhưng đời là vậy
Tôi hiểu “pháp sư hệ thống kiểu não to” không nhất thiết là người viết code, mà là người, chẳng hạn, bán khóa học về chủ đề đó và khiến mọi người phấn khích
Ở phần đầu bài, khi nói về Agile cũng dùng từ “pháp sư”; có khá nhiều người làm việc gần với bán khóa học hơn là phát triển phần mềm thực tế
Làm việc với những người ám ảnh với phân cấp kiểu rất khó chịu, và phần biện minh thường ở mãi trong thế giới của “nếu như” và “nhưng cái đó không sound”
Rất nhiều suy giảm chất lượng do hệ thống kiểu gây ra đến từ những người tin rằng nếu nhồi đủ nhiều kiểu thì có thể chặn hoàn toàn bug, nhưng điều đó không đúng
Tôi có cảm giác trong vài tháng tới mọi người sẽ cùng nhảy lên chuyến tàu HTMX, làm đảo lộn đầu óc của nhiều lập trình viên trẻ, tiết kiệm đáng kể năng lượng trên toàn thế giới và khiến nhiều người hạnh phúc
Rồi sau đó, khi những người trẻ tò mò này cứ tiếp tục bấm các liên kết trên htmx.org và phát hiện ra hyperscript, khoảnh khắc đó sẽ giống cảnh ma cà rồng bật ra trong Dusk till Dawn
Một người nào đó chán ngấy độ phức tạp của JavaScript tạo ra một thư viện JavaScript đơn giản, mọi người đổ xô đến vì sự đơn giản đó, rồi thư viện ấy phải hỗ trợ mọi tính năng web nên trở nên phức tạp, và lại có ai đó chán ngấy độ phức tạp đó tạo ra một thư viện JavaScript đơn giản
Tôi bắt đầu với JavaScript thuần, vật lộn vài năm với IE5/6, jQuery đã cứu tất cả, AngularJS thì không ổn nên tôi bỏ qua, và khi bản beta của React xuất hiện tôi thích nó vì lý tưởng lập trình hàm. Giờ thì tôi đang phải lội qua transpiling, hot reload, Typescript và một đống thư viện React nặng nề
Tôi cũng đã làm vài dự án bằng Intercooler và HTMX. Nhìn chung HTMX khá vững, nhưng đây không phải chuyến tàu đầu tiên đi qua thị trấn này
Tôi muốn thấy một phê bình thật sự về htmx
Cá nhân tôi nghĩ bài toán dai dẳng lớn của web là tìm cách cập nhật trang cho tốt, và chúng ta đã liên tục thử đủ thứ. Vì vậy mới sinh ra mệt mỏi, và một số ý tưởng trở nên cực đoan hoặc theo thời gian thành một mớ linh tinh
Htmx trông giống một phản ứng ngược kiểu grug: làm ít hơn, kiên quyết YAGNI
Tương lai thì bất định, nhưng những công việc như signals vẫn trông như một việc thiêng liêng. Có rất nhiều thử nghiệm từ nhiều hướng, và chúng ta vẫn đang khai phá mặt trận này cùng những mặt trận khác
MobX, Svelte và những thứ khác cũng đã đi một chặng đường dài. Tôi muốn tin rằng hành trình chưa kết thúc, và việc tiếp tục vướng vào con quái vật phức tạp không hẳn là dấu hiệu của sự yếu kém — dù lối nghĩ bảo thủ hay kiểu grug có thể nhìn như vậy — mà là nỗ lực xứng đáng để đi đến thứ vừa đơn giản vừa tốt, chứ không chỉ là một cách tiếp cận đơn giản
_="on load wait 5s then transition opacity to 0 then remove me"Ôi, đừng
_="on htmx:error(errorInfo) fetch /errors {method:'POST', body:{errorInfo:errorInfo} as JSON} "Ôi, đừng mà!
Tôi đã làm developer 30 năm, và thừa nhận rằng thời đầu tôi kiêu ngạo, nghĩ mình thông minh hơn người khác. Khi đó tôi thuộc phe “não to”, thích mọi con quỷ phức tạp
Mười năm sau, tôi đã gần với developer “Grug brain” hơn, và giờ tôi tập trung vào giải pháp đơn giản nhất có thể hoạt động được, dù biết rằng nó có thể không hoàn hảo. Nhưng điều đó vẫn ổn, vì nó đưa ta đến gần hơn với cái đúng và cho phép cải tiến lặp lại
Việc tốt nhất bạn có thể làm với tư cách developer là xóa code. Hiện giờ có một yêu cầu mà chúng tôi đã duy trì suốt 2 năm bỗng không còn là yêu cầu nữa, và tôi thật sự phấn khích với việc sắp bóc bỏ rất nhiều code. Vì mọi thứ sẽ đơn giản hơn
Như thể cơ thể cảm nhận được không gian đang được giải phóng
Grug cũng đã được nhắc đến trong phần bình luận của bài Philosophy of Software Design một tuần trước, và tôi thấy cuộc thảo luận khi đó khá hay. https://news.ycombinator.com/item?id=38011938
“Tôi cũng có cảm giác y hệt về grug. Tôi không nghĩ mọi người thực sự đồng thuận về cái gì là đơn giản, nên việc giả vờ rằng ‘sự đơn giản’ của mình là điều hiển nhiên đến mức người nguyên thủy cũng đồng ý nghe giống khoe mẽ”
Đơn giản thường là một trong những thứ phức tạp nhất để tìm ra. Tôi đã thấy nhiều người tin chắc rằng mọi thứ xung quanh họ, trừ đúng việc họ đang làm, đều phức tạp và cần được uốn về sự đơn giản. Cảm giác đó giống một thái độ yếu ớt nguy hiểm, bám víu vào thẩm quyền
Triết lý grug brain là chọn sự đơn giản bằng mọi giá, trừ khi tuyệt đối không thể tránh được
Triết lý bộ não lớn theo cách grug nhìn nhận là chọn khả năng tái sử dụng bằng mọi giá, trừ khi tuyệt đối không thể tránh được
Vấn đề của triết lý này là nó đóng đinh các lựa chọn thiết kế thế hệ đầu và khiến việc cải tiến lặp lại khó hơn
Đúng là khó tìm ra sự đơn giản, nhưng chìa khóa để tìm ra sự đơn giản là cải tiến lặp lại
Điểm cực tiểu cục bộ dịch chuyển theo độ phức tạp của thứ đang được xây dựng, nên có chỗ cho nhiều quan điểm khá thông minh cùng đúng một lúc
Không phải chỉ số hoàn hảo, nhưng hướng đi là đúng, và trên thang log thì hoạt động rất tốt
Tôi đã dùng và giải thích khái niệm hàng rào Chesterton vô số lần, nên thật vui khi biết tên của nó
Đây là chuyện xảy ra rất thường xuyên khi làm việc với các lập trình viên mới. Khi thấy “đống rác legacy cũ kỹ”, phản ứng đầu tiên của họ là muốn tháo bỏ hoặc vứt hết đi rồi làm lại từ đầu
Trong một số trường hợp, để họ tự thử cũng có thể là một bài học, nhưng nên nhớ rằng những người đi trước chúng ta không phải ai cũng hoàn toàn ngốc nghếch, và thường là họ có lý do để làm như vậy
Đôi khi đó thật sự là đoạn code cũ bẩn thỉu cần thay thế, nhưng ngay cả khi đó, nó thường chứa một bản ghi chép phải trả giá mới có được về tất cả những ngóc ngách và trường hợp biên cần hiểu và xử lý để xây dựng thứ gì đó trong domain ấy
Phần về kiểm thử thật sự hay. Nó khớp chính xác với những gì tôi đã học được trong nhiều năm
Integration test là điểm phù hợp để tìm bug
Mock object có xu hướng làm mọi thứ phức tạp quá mức, và dù đôi khi tôi vẫn dùng, tôi tránh dùng chúng một cách có hệ thống
Unit test quá mong manh trước refactoring, trong khi integration test lại giúp refactoring
Unit test khó viết và bảo trì hơn, nhưng khi thất bại thì dễ hiểu và debug hơn nhiều, nên về dài hạn trụ vững tốt hơn rất nhiều
Loại test tệ nhất là integration test âm thầm phụ thuộc vào việc một integration test khác đã chạy trước đó. Đúng 99%, rồi ngay khi thứ tự thay đổi vì một thay đổi nào đó, nó vỡ
Nếu đội có code đơn giản, test sẽ giúp ích lớn. Nhưng nếu đội không có code đơn giản, mà thường là không có, thì tốt hơn nên dành thời gian làm code đơn giản hơn thay vì dành thời gian viết test
Nếu lấy một hàm lá làm đơn vị thì thường là ở mức quá thấp, nhưng một module lớn hơn với interface tương đối ổn định có thể là một đơn vị tốt và hiệu quả để test
“Độ phức tạp rất, rất tệ”
“Vũ khí tốt nhất chống lại ác quỷ linh hồn phức tạp là từ ma thuật ‘không’”
“Buồn nhưng thật: sau khi học nói ‘có’ rồi thất bại, học cách đổ lỗi cho grug khác là lời khuyên sự nghiệp lý tưởng”
Đó là trí tuệ phức tạp của grug
Thời điểm đó cũng đã có thảo luận
The Grug Brained Developer - https://news.ycombinator.com/item?id=31840331 - tháng 6 năm 2022, 374 bình luận