10 điểm bởi GN⁺ 2025-08-31 | 1 bình luận | Chia sẻ qua WhatsApp
  • Dự án mã nguồn mở này hệ thống hóa nhiều phương pháp và ví dụ khác nhau nhằm giảm tải nhận thức trong phát triển phần mềm
  • Mã nguồn, cấu trúc, và sự trừu tượng hóa phức tạp không cần thiết làm giảm năng suất của lập trình viên và tăng chi phí bảo trì
  • Thay vì các mô-đun “nhỏ và nông”, cấu trúc sâu với giao diện đơn giản và chức năng mạnh mẽ sẽ phù hợp hơn
  • Trừu tượng hóa quá mức, phụ thuộc framework, lạm dụng nguyên tắc DRY lại chính là nguyên nhân làm tăng tải nhận thức
  • Kiến trúc tốt nhất là codebase đơn giản, giúp cả lập trình viên mới cũng có thể hiểu nhanh

Tóm tắt dự án và ý nghĩa

Tài liệu mã nguồn mở trên GitHub này tập trung vào ‘tải nhận thức (cognitive load)’ như một trong những nguyên tắc cốt lõi của phát triển phần mềm. Điểm nổi bật lớn nhất của repository này là nó sắp xếp lại nguồn gốc của sự phức tạp mà lập trình viên thực sự gặp phải, cùng với nhiều ví dụ và cách giải quyết, bất kể quy mô đội ngũ hay xu hướng công nghệ. Khác với các tài liệu thiên về best practice khác, tài liệu này còn tính đến cả gánh nặng tâm lý và nhận thức, nhờ đó có thế mạnh thực tế trong bảo trì và onboarding thành viên mới.

Giới thiệu

  • Những khái niệm thời thượng hay best practice mà chúng ta thường nghe trong môi trường phát triển thực tế nhiều khi lại thất bại
  • Nguyên nhân cốt lõi của sự hỗn loạn trong công việc thực tế, cùng tổn thất về thời gian/chi phí do nó gây ra, là tải nhận thức cao
  • Lập trình viên dành nhiều thời gian để đọc và hiểu mã hơn là viết mã
  • Nội dung này tập trung vào các cách thực tiễn để giảm tải nhận thức phát sinh không cần thiết (Extraneous Cognitive Load)

Tải nhận thức là gì

  • Tải nhận thức là lượng thông tin mà lập trình viên phải giữ trong đầu để hoàn thành công việc
  • Trung bình, con người chỉ có thể giữ khoảng 4 “khối thông tin” cùng lúc trong trí nhớ ngắn hạn (điều kiện, giá trị biến, v.v.)
  • Khi tải nhận thức chạm ngưỡng tới hạn, khả năng hiểu và tốc độ phát triển sẽ suy giảm mạnh

Các loại tải nhận thức

  • Tải nhận thức nội tại (Intrinsic): bắt nguồn từ độ khó vốn có của chính công việc. Không thể giảm
  • Tải nhận thức không cần thiết (Extraneous): bắt nguồn từ cách trình bày thông tin, thiết kế cấu trúc, các pattern không cần thiết và sự phức tạp nhân tạo. Có thể chủ động giảm

Ví dụ thực tế và cách cải thiện

Câu lệnh điều kiện phức tạp

  • Mã có nhiều điều kiện lồng nhau làm tăng lượng nội dung phải ghi nhớ ở từng bước, từ đó tăng tải nhận thức
  • Cách giải quyết: đưa vào các biến trung gian có ý nghĩa để tách bạch rõ mục đích của từng điều kiện

if lồng nhau vs Early Return

  • So với if lồng nhau, pattern Early Return giúp giảm gánh nặng phải nhớ các điều kiện tiên quyết
  • Nó giải phóng bộ nhớ làm việc bằng cách khiến bạn chỉ cần nhớ ‘happy path’

Tác dụng phụ của cấu trúc kế thừa

  • Hệ thống kế thừa sâu (ví dụ: lớp A → lớp B → lớp C …) buộc người đọc phải nhớ nhiều tầng thông tin cùng lúc để hiểu mã, khiến tải nhận thức tăng vọt
  • Cách giải quyết: ưu tiên composition, dùng cách kết hợp thay cho kế thừa không cần thiết

Quá nhiều mô-đun/hàm nông

  • So với 80 class nhỏ và nông, một vài deep module với giao diện mạnh mẽ nhưng đơn giản sẽ dễ bảo trì hơn
  • Ví dụ được đưa ra là giao diện đơn giản của UNIX I/O (open, read, write, lseek, close)

Hiểu sai nguyên tắc 'Single Responsibility Principle'

  • Cách hiểu mơ hồ kiểu ‘chỉ làm một việc’ lại tạo ra hàng loạt lớp trừu tượng nông và thiếu rõ ràng
  • Trên thực tế, nên hiểu là ‘chịu trách nhiệm trước một stakeholder duy nhất’ để giảm tải nhận thức và giúp hiểu rõ hơn mối liên hệ với nghiệp vụ

Lạm dụng microservices

  • Quá nhiều microservice nông khiến người phát triển phải liên tục giữ trong đầu quan hệ và thông tin tích hợp giữa các dịch vụ, làm tăng tải nhận thức cũng như chi phí debug/ra mắt
  • Ở giai đoạn đầu, cấu trúc monolithic hoàn thiện đôi khi lại có lợi hơn cho bảo trì

Quá nhiều tính năng/tùy chọn của ngôn ngữ

  • Quá nhiều tính năng mới của ngôn ngữ (đặc biệt là C++ v.v.) khiến người đọc phải lần theo ‘vì sao lại được triển khai như vậy’, làm tích lũy gánh nặng ghi nhớ
  • Đây là dạng tải nhận thức phụ phát sinh không liên quan đến nghiệp vụ

Ánh xạ mã trạng thái HTTP và logic nghiệp vụ

  • Việc ánh xạ tùy tiện giữa mã trạng thái HTTP (401, 403, 418, v.v.) và ý nghĩa nghiệp vụ nội bộ là thứ mọi thành viên trong nhóm đều phải học thuộc
  • Cải thiện: truyền đạt nhất quán bằng mã chuỗi tự mô tả (ví dụ: "jwt_has_expired")

Lạm dụng nguyên tắc DRY (Do not repeat yourself)

  • Trong codebase phức tạp, nếu cố ép loại bỏ trùng lặp bằng mọi giá thì sẽ tạo ra phụ thuộc chặt, từ đó làm tăng tải nhận thức và chi phí thay đổi
  • Bài viết trích dẫn câu nói nổi tiếng của Rob Pike rằng đôi khi ‘một chút copy cục bộ’ lại tốt hơn

Tác hại của phụ thuộc framework và Layered Architecture

  • Khi phụ thuộc quá sâu vào cấu trúc ‘ma thuật’ của framework, lập trình viên mới sẽ mất rất nhiều thời gian để nắm được logic bên trong
  • Sự tích lũy các lớp trừu tượng khiến tải nhận thức bùng nổ đúng lúc cần lần theo vấn đề thực tế
  • Cần tập trung vào các nguyên lý nền tảng (Dependency Inversion, Info Hiding, kiểm soát Cognitive Load)

Hiểu sai Domain-Driven Design (DDD)

  • Cốt lõi của DDD là phân tích miền vấn đề; còn việc quá bám vào cấu trúc thư mục/pattern lại dễ gây ra diễn giải chủ quan và tải nhận thức
  • Những framework như Team Topologies hiệu quả hơn trong việc phân chia tải nhận thức

Sự quen thuộc vs sự đơn giản

  • Quen thuộc không đồng nghĩa với đơn giản. Ta cảm thấy nhẹ nhàng hơn vì đã quen, chứ không có nghĩa cấu trúc đó thực sự dễ
  • Nếu một người mới vào công ty vẫn thấy rối sau hơn 40 phút, đó là tín hiệu cần cải thiện mã nguồn

Các ví dụ thành công/thất bại thực tế

  • Như Instagram, kiến trúc monolithic đơn giản vẫn có thể mang lại khả năng mở rộng và trải nghiệm bảo trì rất tốt
  • Các công ty nơi “những lập trình viên thật sự thông minh” tạo ra cấu trúc quá phức tạp lại thường có nhiều trải nghiệm thất bại hơn
  • Một cấu trúc mà mọi lập trình viên đều có thể đọc dễ dàng và onboard nhanh đóng vai trò then chốt trong việc nâng cao năng suất

Kết luận

  • Tải nhận thức không cần thiết vượt ra ngoài bản thân công việc cốt lõi là có hại cho mọi chủ thể tham gia phát triển
  • Mã tốt nhất là mã mà bản thân bạn và những lập trình viên khác trong tương lai có thể hiểu nhanh nhất có thể
  • So với những cấu trúc “trông có vẻ thông minh”, giải pháp bình thường và trực diện có lợi hơn về lâu dài cho bảo trì và năng suất đội ngũ

Tham khảo/cảm nhận

  • Bài viết cũng trích dẫn ý kiến của Rob Pike, Andrej Karpathy, Elon Musk, Addy Osmani, antirez (tác giả Redis) và nhiều lập trình viên nổi tiếng khác
  • Các hàm ý được đưa ra cũng phù hợp với những ví dụ quy mô lớn ngoài thực tế như Chromium, Redis, Instagram
  • Sự đơn giản, rõ ràng và việc giảm tải nhận thức chính là cốt lõi của tính bền vững trong phần mềm

Giá trị của dự án mã nguồn mở này

  • Tài liệu tập trung vào trải nghiệm phát triển thực tế và các ví dụ mang tính thực hành mà nhiều sách thiết kế phần mềm hay pattern thường bỏ sót
  • Mang lại giá trị thực tiễn ngay lập tức cho nhiều đội ngũ trong onboarding lập trình viên, review kiến trúc, và bảo trì dài hạn
  • Có thể đóng vai trò như một checklist để nhìn lại code thông qua một khung tư duy rõ ràng là ‘tải nhận thức’

1 bình luận

 
GN⁺ 2025-08-31
Ý kiến trên Hacker News
  • Tôi có lẽ đã có được bước ngoặt nhận thức lớn nhất từ cuốn A Philosophy Of Software Design của John Ousterhout; đây là cuốn sách hay nhất về chủ đề này, và tôi khuyên mọi lập trình viên nên đọc. Điểm cốt lõi là trong thiết kế phần mềm, mục tiêu phải là giảm thiểu độ phức tạp, trong đó độ phức tạp được định nghĩa là “khó thay đổi đến mức nào”, và “độ khó” này được quyết định bởi gánh nặng nhận thức cần bỏ ra để hiểu mã

    • Vấn đề là rốt cuộc không có quy tắc nào có thể thay thế được năng lực phán đoán, kinh nghiệm và trực giác. Mọi quy tắc đều có thể trở thành công cụ để tranh cãi, và trong các cuộc tranh luận về kiến trúc thì bạn sẽ không bao giờ thắng. Lý do bài viết này hay là vì những người không cần nó thì đã biết rồi, còn những người thực sự cần thì sẽ không hiểu được. Cuối cùng đây không phải vấn đề kỹ thuật mà là vấn đề con người và văn hóa. Kiến trúc rốt cuộc là thứ đi theo con người và văn hóa. Cũng như vì có Rob Pike và Google nên mới có Go; không phải cứ đọc một cuốn sách là sẽ sinh ra được một ngôn ngữ như Go

    • Tôi nghĩ nguyên tắc DRY (đừng lặp lại chính mình) thực ra chỉ nên được cân nhắc sau khi bạn đã hiểu ứng dụng đủ sâu và đã làm qua vài phiên bản. Ban đầu ngược lại nên lặp lại để hiểu không gian vấn đề trước, rồi đến phiên bản thứ hai mới suy nghĩ về khả năng bảo trì. Phải đến khoảng phiên bản thứ ba thì mới thực sự nên áp dụng DRY

    • Khó kinh khủng để kiếm được cuốn sách này mà không phải đưa tiền cho Jeff Bezos. Nếu ai đó biết tác giả John thì mong hãy báo cho ông ấy về vấn đề này. Hiệu sách trong trường không có, hiệu sách địa phương hay cả Powell’s cũng không kiếm được

    • Tôi đã từ bỏ việc tìm kiếm một lời giải phần mềm hoàn hảo từ lâu. Có vẻ chẳng ai là người đã sắp xếp mọi thứ một cách hoàn hảo cả. Cuối cùng vũ khí tốt nhất chúng ta có là trí tuệ và kinh nghiệm của con người. Bối cảnh, ngành nghề và đội ngũ khác nhau quá nhiều nên không thể đóng khung gọn gàng bằng con số hay quy luật. Vì thế trong thiết kế tôi đặt mục tiêu tìm sự cân bằng giữa “bừa bộn” và “đẹp đẽ”. Điều khó nhất là kinh doanh thì bất định còn phần mềm thì mang tính xác định, nên yêu cầu kinh doanh luôn thay đổi và rất khó ép chúng vào sự cứng nhắc của hệ thống máy tính. Dạo này tôi chỉ thử refactor khi cảm thấy khó chịu thật sự mỗi lần định sửa mã. Mà kể cả khi đó cũng chỉ dọn dẹp ở mức tối thiểu. Khi lặp lại kiểu refactor từng chút như vậy nhiều lần, các mẫu mới sẽ xuất hiện và rồi có thể tách chúng thành abstraction

    • Cuốn sách này đúng là tốt nhất về chủ đề đó. Bài viết kia cũng được truyền cảm hứng từ cuốn sách này. Tôi cũng đã trao đổi với tác giả John một hai ý về nội dung bài viết

  • Khả năng viết ra mã giúp giảm gánh nặng nhận thức cho người khác là một kỹ năng rất hiếm và rất khó. Ngay cả khi có năng lực, nó vẫn đòi hỏi nỗ lực bền bỉ. Rốt cuộc công việc của lập trình viên là nén các ý tưởng cốt lõi để chỉ lộ ra bản chất, và chỉ phơi bày phần phức tạp thực sự cần thiết. Thực tế tôi rất hiếm khi thấy ai làm tốt việc này

    • Mã được làm cực tốt cuối cùng sẽ khiến mọi người ảo tưởng rằng “ủa, đây vốn là vấn đề dễ à?”. Ngược lại, loại mã “nhà bài” nơi sự phức tạp lộ rõ lại được công nhận như dấu vết của nỗ lực và thậm chí còn dẫn tới thăng tiến

    • Điều này cũng đúng y hệt với interface hay thiết kế UX/tương tác. Lập trình viên chịu được gánh nặng nhận thức tốt hơn người bình thường rất nhiều, nhưng để tạo ra thứ mà người không phải dân kỹ thuật dùng tốt thì lại phải thoát khỏi trực giác của chính mình, nên độ khó cực cao. Thiết kế công cụ để người dùng phổ thông có thể giải quyết vấn đề phức tạp một cách trực quan là việc thật sự rất khó

    • Phần lớn abstraction không sống sót được khi yêu cầu thay đổi. Những framework tôi thích đều hiểu rằng không thể tạo ra một lớp abstraction hoàn hảo mãi mãi nên cố ý chừa “lối thoát”. (Ví dụ: framework WebUI cho phép lấy direct reference tới HTML element) Sự khôn ngoan ở đây là hiểu rằng ta không thể dự đoán tương lai một cách hoàn hảo

    • Trên thực tế, kỹ năng này ở nhiều công ty không hẳn là thứ bắt buộc mà chỉ là điểm cộng. Chỉ cần nhìn vào các codebase chủ lực là thấy

  • Tôi tự xem mình là một trong những “lập trình viên thông minh kiểu lập dị”. Tôi thích xây abstraction. Gần đây tôi thấy vừa lạ vừa lo khi ngành này đang quay về với “kiến trúc đống if”. Tôi hiểu vì sao nhiều người thích nó: trông đơn giản, dễ hiểu và chỉ cần đóng ticket được giao. Phần lớn quy trình phát triển đều dựa vào những đống if, và cách này thực sự hoạt động tốt với số lượng case nhất định. Thậm chí kể cả khi xảy ra những vụ như rò rỉ dữ liệu cá nhân quy mô lớn thì cũng chẳng mấy ai chịu trách nhiệm. Nhưng vấn đề là tôi không biết có phương án nào tốt hơn không. Những abstraction hào nhoáng hay kiến trúc đẹp mắt dường như cũng không thật sự cải thiện tính nhất quán của mã. Đặc biệt trong môi trường doanh nghiệp, những người sở hữu business logic hầu như không quan tâm đến logic đó nên không thể cẩn thận xây abstraction đẹp đẽ được. Cuối cùng kiểu yêu cầu như “đơn hàng chỉ giao đến một địa chỉ” lại đột nhiên đổi thành “khách lớn yêu cầu giao đến nhiều địa chỉ”, và trong kiểu hỗn loạn này thì abstraction không lỗi gần như không thể tồn tại. Đôi lúc tôi còn nghĩ trong phần mềm doanh nghiệp, đống if có lẽ là lựa chọn tốt nhất ngoài thực tế

    • Với câu hỏi “liệu kiểu ‘đống if’ có phải là tốt nhất không?”, tôi khuyên đọc bài luận Big Ball of Mudbài tóm tắt này về kiến trúc phần mềm lớn ngoài đời thực. Hệ thống thực tế luôn tiến hóa; ban đầu bắt đầu như một “cục bùn”, rồi cải thiện từng phần, nhưng khi thay đổi lại đến thì những abstraction từng đẹp đẽ cũng sụp đổ. Điều cốt lõi là làm hệ thống lớn lên bằng sự kết hợp giữa domain modeling, abstraction vừa đủ và những thay đổi phá hủy cần thiết, giống như một thị trấn nhỏ phát triển thành thành phố

    • Ngay cả trong loại phần mềm này bạn vẫn có thể tạo ra abstraction đẹp, nhưng từ khoảnh khắc business logic can thiệp thì rất khó duy trì. Những phần abstraction còn đứng vững thường là các yếu tố thiên về sản phẩm như xác thực, phân quyền, log, cơ sở dữ liệu, middleware, hạ tầng... Một khi logic nội bộ của doanh nghiệp bắt đầu ảnh hưởng đến abstraction thì cuối cùng mọi thứ lại thành bừa bộn. Có nơi thậm chí để chính người làm kinh doanh tự quản lý logic, và kết quả là vừa khó test, vừa không thể hiểu nổi, thậm chí không mô phỏng được. Rồi cuối cùng lại cần người vận hành, dẫn đến cảnh lập trình viên junior viết mã qua công cụ đồ họa. Dù rewrite nhiều lần thì sau 2–3 năm mọi thứ vẫn luôn thành mớ hỗn độn

    • Người làm kinh doanh không bao giờ có thể giải thích hoàn hảo business logic cho người triển khai. Dù họ tự hiểu đi nữa thì họ cũng không thể biểu đạt nó theo góc nhìn lập trình. Ngược lại, ít nhất phải có một người triển khai thực sự trải nghiệm người dùng đến tận xương tủy thì mới hiểu đúng. Nhưng ngoài đời doanh nghiệp lại ép tách phòng ban, và “business logic” trở thành vùng không ai thực sự để tâm, nên cuối cùng chỉ còn thao tác với các câu lệnh if

    • Điểm mấu chốt là bản thân hiện thực, tức chính việc kinh doanh, đã là một đống if rồi. Nếu vấn đề hay domain đủ rõ ràng về mặt kỹ thuật hoặc có thể khái quát hóa thì ta có thể dùng abstraction để giảm if, nhưng nếu bản thân domain đã hỗn loạn thì abstraction rốt cuộc cũng buộc phải đưa “tính linh hoạt” vào làm mặc định. Mâu thuẫn thậm chí còn có thể trở thành một tính năng

    • Nếu nghịch thử với các công cụ như Codex CLI, bạn sẽ thấy khi gặp bug, công cụ này luôn tạo ra một bản vá if cho đúng case đó. Trừ khi bạn chỉ rõ pattern và yêu cầu abstraction mới, nếu không nó sẽ cứ tiếp tục thêm các câu lệnh if mà nó gọi là “heuristic”. Với 10 bug cùng một loại sẽ có 10 bản vá, và khi bug thứ 11 tương tự xuất hiện thì đương nhiên không chạy được. Lời giải mà Codex đưa ra là một tập hợp của việc lặp lại if

  • Tôi băn khoăn không biết tình huống được yêu cầu sửa trong một dự án hoàn toàn xa lạ thực tế phổ biến đến mức nào. Nếu bạn không chuyển dự án quá thường xuyên thì chắc khoảng hai năm mới gặp một lần. Tôi nghĩ tốt hơn là tập trung vào những vấn đề thực sự khó thay vì vào thứ chỉ phản ánh thiếu kinh nghiệm

  • Trong 8 năm làm ở tổ chức phát triển của Microsoft, mô hình hóa kiểu kỹ sư giai đoạn đầu cực kỳ hữu ích. Có ba persona, về sau được thay bằng framework phức tạp hơn. Dù vậy, các persona ban đầu vẫn giúp ích lớn cho tôi đến tận bây giờ trong việc giao tiếp hiệu quả với các kỹ sư khác trong sự nghiệp.

    • Mort: kỹ sư thực dụng, kết quả kinh doanh là ưu tiên số một. Kể cả là đống if, chỉ cần chạy nhanh là đủ.
    • Elvis: ưu tiên đổi mới, dùng công nghệ mới nhất, muốn sự thiên tài của mình được biết đến. Bị ám ảnh bởi việc đưa framework mới vào, mã thiếu ổn định, sự hiện diện và đổi mới.
    • Einstein: ám ảnh với hiệu năng, sự tao nhã và tính chính xác kỹ thuật. Coi trọng tính nhất quán của mã và độ hoàn thiện kỹ thuật hơn. Trong thực tế mọi kỹ sư đều là sự pha trộn của cả ba. Chỉ cần vài lần review PR và review thiết kế là có thể đoán được xu hướng chủ đạo
    • Tôi nghĩ phải có thêm kiểu kỹ sư tên Amanda nữa. Sau 20 năm review cả mã lộn xộn của mình lẫn của người khác, giờ đây cô ấy đã thấm rằng trên hết mã là để con người đọc. Tôi muốn lập đội chỉ toàn những Amanda như thế

    • Mort là người thực dụng, Einstein là người cầu toàn, còn Elvis thì... tôi thật sự cho rằng gần như là có hại cho dự án. Cũng có phần tạo động lực, nhưng đội lý tưởng là pha trộn tốt giữa Mort và Einstein. Phải làm cho đơn giản vừa đủ mà vẫn đủ chính xác để việc bảo trì không trở thành cực hình. Ngược lại, nếu để Mort làm dự án dài hạn thì đến một lúc nào đó họ cũng sẽ bắt đầu quan tâm như Einstein. Nói ngoài lề, các coding agent tự động gần đây lại quá thiên về kiểu Mort, đến mức tôi phải đứng ở vai Mort để quản lý chúng

    • Persona là công cụ tốt. Theo kinh nghiệm của tôi, theo thời gian nó dễ bị biến chất thành những lối tắt sai lầm. Elvis thực ra là một thuật ngữ phục vụ chính trị nội bộ, và giống như định luật Goodhart, vì nó trông có vẻ đúng về mặt logic nên ai cũng muốn dùng trong tranh luận, làm giảm tính hữu ích. Ngày xưa Alan Cooper đã đưa khái niệm persona vào cùng với phát triển Visual Basic. Điều quan trọng là hiểu rằng những góc nhìn khác mình, ví dụ nhà khoa học và lập trình viên firmware, có hệ giá trị khác nhau. Sách liên quan

    • Tôi cho rằng kỹ sư giỏi nhất là người có thể điều chỉnh cả ba xu hướng này theo dự án, tình huống và mục tiêu cá nhân. Tỷ trọng cần thiết khác nhau tùy vai trò. Ví dụ tối ưu hóa compiler thì cần Einstein và Mort hơn, còn mã như game engine thì tỷ lệ lại khác. Có thể tranh cãi về độ chính xác của từng đặc tính, nhưng điều cốt lõi là ai cũng phải vận hành khác nhau theo thời gian

    • Tôi nghĩ cách này cần có ranh giới. Nếu phân loại con người quá đơn giản, nó có thể trở thành sự dán nhãn bất công và lâu dài. Theo kinh nghiệm của tôi, chính quản lý mới là người thích Mort hơn Elvis. Tôi cho rằng lời giải thực sự nằm ở leadership và management. Nếu đưa tiêu chuẩn chất lượng mã vào phần yêu cầu với Mort, họ vẫn có thể tạo ra kết quả khá tốt dù chậm hơn đôi chút. Elvis thì cần ràng buộc, còn Einstein thì phải được nêu rõ điều kiện chốt hạ theo hướng thực dụng. Cách này có giới hạn là bỏ qua sự phức tạp của con người

  • Tôi lo AI sẽ gây hại cho ngành phần mềm. AI không có giới hạn của con người nên có thể viết ra mã cực kỳ phức tạp, khó đọc nhưng vẫn chạy, rồi đến lúc cuối cùng nó hỏng thì sẽ chẳng ai sửa nổi. Vì thế tôi khuyên các kỹ sư junior đừng chỉ dựa vào AI mà hãy học các đặc tính của codebase. Nếu không, họ sẽ mất khả năng tự viết mã

    • Tôi thấy lập luận này không thuyết phục vì kể cả AI có ngừng hoạt động thì vẫn có thể sửa lại tiếp

    • Theo kinh nghiệm của tôi, tôi luôn yêu cầu AI tiếp tục đơn giản hóa cho đến khi tôi chắc chắn có thể hiểu được mã của nó. Nếu nó làm theo cách phức tạp thì tôi bảo làm cho dễ hơn, nếu dùng thư viện ngoài không cần thiết thì yêu cầu bỏ đi và giải bằng stdlib hoặc chỉ dùng những dependency sẵn có. AI viết mã thay tôi, chứ không phải cho chính nó

    • Ngược lại, tôi nghĩ nhờ AI mà gánh nặng nhận thức dành cho thiết kế cấp thấp giảm đi, nên ta có thể tập trung hơn vào suy nghĩ kiến trúc cấp cao, từ đó chất lượng phần mềm còn có thể tăng lên

  • Về “thói quen đặc trưng của lập trình viên thông minh” được nhắc trong bài, có vẻ tác giả muốn nói rằng anh ta chỉ hiểu được mã do chính mình viết hoặc mã viết theo đúng phong cách của mình. Nhưng bí quyết thực sự để giảm gánh nặng nhận thức là tối thiểu hóa lượng mã mà bạn không cần đọc. Ranh giới mạnh và API rõ ràng giúp việc thay đổi trở nên dễ dàng, và điều cốt lõi là bạn chỉ cần để tâm đến phần phức tạp phát sinh từ interface được định nghĩa tốt chứ không phải toàn bộ mã. Điểm “kỳ quặc” của “lập trình viên thông minh” thực ra lại là vấn đề bề mặt

    • Đây chính là lợi ích lớn nhất của khái niệm microservices. Nếu hai đội chỉ giao tiếp qua API, và dùng các công cụ như schema để định nghĩa ranh giới thật chặt, họ sẽ trở nên cực kỳ bảo thủ với thay đổi và phải suy nghĩ rất sâu từ trước. Tôi xem đó là hiệu ứng chèn ma sát một cách có chủ đích về mặt kỹ thuật vào đúng những chỗ bạn không muốn thay đổi

    • Khi debug tôi thường cảm nhận rõ rằng nếu có những phần được tối ưu hóa quá mức nằm ngay trên call stack mà mình phải debug trực tiếp thì rất mệt. Vì thế nếu tách riêng một số phần thành function và chia commit ra, bạn có thể dễ rollback những thay đổi mã không mong muốn và độ tập trung vào mã cũng cao hơn. Dù trên PR chúng vẫn lên cùng lúc, nhưng ranh giới rõ ràng thì vẫn tốt hơn nhiều

    • Lập trình viên nhìn chung không giỏi suy nghĩ bằng “hợp đồng và interface”. Cần buộc họ chỉ nhìn vào lời hứa lộ ra bên ngoài chứ không phải implementation nội bộ. Mục tiêu là có thể hiểu mà không cần đọc mã. Nếu tôi buộc người khác phải soi vào mã của mình để hiểu thì đó là thất bại

    • Dù API có rõ ràng đến đâu thì mã bên trong vẫn có thể không dễ hiểu. Bề ngoài có vẻ hoạt động tốt, nhưng rất nhiều lúc bạn vẫn phải đào vào tận bên trong

  • Tôi rất thích vì bài này tóm tắt trải nghiệm của tôi quá chính xác. Hầu hết các phương pháp lập trình mà tôi từng được học bài bản đều phản tác dụng ngay khi người khác phải đọc mã của tôi. Những kiểu mã che giấu phức tạp như Rust và C++ rất vất vả, còn khi nhìn vào kiểu cấu trúc như C, nơi không thể giấu mã sau 6 lớp template, tôi lại thấy yên tâm hơn

    • Rất vui khi thấy nó đồng điệu với trải nghiệm của bạn. Tôi cũng thích C vì lý do đó, và gần đây chuyển sang Golang thì càng thích sự đơn giản bên này
  • Tôi thật sự đồng cảm với ý rằng phải coi tính dễ tiếp cận của mã như công dân hạng nhất. Hãy dùng quy tắc như guideline, còn người thực sự giỏi là người có khả năng tùy ngữ cảnh mà quyết định khi nào nên phá vỡ hoặc bổ sung quy tắc để mã dễ đọc hơn. Cuối cùng năng lực quan trọng là trực giác được gánh nặng nhận thức và các đánh đổi của mã. Dù là trùng lặp hay abstraction thì bạn luôn phải nghĩ đến người tiếp theo, bao gồm cả chính mình sau 6 tháng. Còn với yêu cầu “hãy tạo thêm một quy tắc”, đó bản thân nó lại là sự lặp lại của một vấn đề khác. Sau các guideline cơ bản, điều còn lại là tacit knowledge, tức tri thức ngầm đến từ kinh nghiệm. Khi thời gian tích lũy, bạn sẽ tự cảm được đoạn mã nào tốt hay xấu. Cuối cùng thì phải tự cảm nhận lấy

    • Tôi đồng ý với bản chất của tính dễ tiếp cận mã, nhưng tiếc là tác giả đã bỏ qua germane overhead (mức tiêu hao tài nguyên nhận thức của người tiếp nhận). Rốt cuộc để tăng tính dễ tiếp cận của mã, phải cân nhắc cả ba loại overhead: intrinsic, extraneous và germane
  • Người ta hay nói hãy ghi lại “tại sao”, nhưng tôi thấy khó tách “tại sao” và “cái gì”, nên tôi ghi cả hai. Loại comment tệ nhất là

    x = 4 // gán 4 cho x 
    

    kiểu như vậy. Trộn mã và chú thích làm nó vừa khó đọc vừa gây chuyển ngữ cảnh mạnh. Thay vào đó

    // tại sao làm việc này, và sắp làm điều gì
    setup();
    t = setupThing();
    t.useThing(42);
    t.theWidget(need=true);
    ...
    

    tôi thích tách rõ comment và mã như thế này hơn. Dù vậy, ngay cả ghi “cái gì” thôi cũng vẫn tốt hơn rất nhiều so với không có gì, và giúp giảm gánh nặng nhận thức

    • Loại comment theo kiểu này đa phần rất khó duy trì, mà implementation thì một năm thay đổi đến 5 lần, nên chúng nhanh chóng lỗi thời và gây rối. Trong các dự án gần đây tôi xóa hầu hết comment, chỉ giữ lại logic thật sự khó và tài liệu cấp cao nhất

    • Tôi nghĩ có lúc cần ghi cả hai thứ (why/what). Có khi phải làm rõ lý do, có khi phải làm rõ hành vi. Gần đây tôi thấy giá trị của comment đang bị đánh giá thấp. Không cần comment mọi dòng, nhưng phần lớn cái gọi là “mã tự tài liệu hóa” cũng không hẳn là dễ đọc đến vậy

    • Gần đây tôi thấy điều khó nhất là quyết định nội dung nào nên để lại trong mã, còn nội dung nào nên để trong tài liệu thiết kế/tài liệu kỹ thuật. Kết luận của tôi là comment trong mã nên dùng để giải thích những ý định không trực quan hoặc bị che khuất. Ví dụ: “memoize cái này vì lý do X”

    • Tôi bật cười với kiểu comment x=4 phong cách ChatGPT. Nhưng nhược điểm của cách được đề xuất là comment có nguy cơ cũ đi và lệch khỏi mã. Khi sửa mã thì nhất định cũng phải cập nhật comment

    • Tôi không phải lập trình viên được đào tạo bài bản mà là nhà vật lý, nên mỗi lần viết comment tôi đang cố tập chuyển sang cách trên. Hồi còn là sinh viên, để được điểm tốt thì gần như thông lệ là cứ phải viết thật nhiều comment