1 điểm bởi GN⁺ 2023-11-16 | 1 bình luận | Chia sẻ qua WhatsApp

Đưa câu lệnh điều kiện lên phía gọi hàm

  • Nếu có câu lệnh điều kiện if bên trong hàm, hãy cân nhắc chuyển nó lên phía caller.
  • Thay vì để hàm tự kiểm tra điều kiện tiên quyết ở bên trong và “không làm gì cả” khi điều kiện không được đáp ứng, hãy để caller kiểm tra điều kiện tiên quyết để có thể đảm bảo qua kiểu dữ liệu rằng điều kiện đó đã được thỏa mãn.
  • Việc đặc biệt “đưa điều kiện tiên quyết lên trên” có thể giúp giảm số lần kiểm tra nói chung, và đây là một trong những động cơ của quy tắc này.

Đẩy vòng lặp xuống dưới

  • Đây là một quy tắc xuất phát từ tư duy hướng dữ liệu: đưa vào khái niệm “batch” của đối tượng, lấy thao tác theo lô làm trường hợp cơ bản, và xem phiên bản vô hướng là trường hợp đặc biệt của phiên bản theo lô.
  • Lợi ích chính là cải thiện hiệu năng, vì có thể phân tán chi phí khởi động và có được sự linh hoạt trong thứ tự xử lý.
  • Ví dụ, trong phép nhân đa thức dựa trên FFT, việc đánh giá đa thức tại nhiều điểm cùng lúc có thể nhanh hơn so với đánh giá riêng lẻ.

Ý kiến của GN⁺

  • Điều quan trọng nhất trong bài viết này là hai quy tắc lập trình nhằm cải thiện hiệu năng và độ rõ ràng của mã trong phát triển phần mềm: “đưa câu lệnh điều kiện lên trên” và “đẩy vòng lặp xuống dưới”.
  • Những quy tắc này giúp tăng khả năng đọc hiểu mã, tối ưu hiệu năng và giảm khả năng phát sinh lỗi.
  • Bài viết này thú vị và hữu ích với nhiều lập trình viên vì nó mang lại góc nhìn về cách quản lý sự phức tạp trong kỹ nghệ phần mềm và viết mã hiệu quả hơn.

1 bình luận

 
GN⁺ 2023-11-16
Ý kiến Hacker News
  • Có ý kiến cho rằng phản ứng dữ dội trước lời khuyên về thiết kế hướng dữ liệu là điều đáng ngạc nhiên. Phần lớn người dùng trên các diễn đàn viết ứng dụng web, nên lời khuyên này có thể trông vô nghĩa. Nếu trong công việc hằng ngày bạn không cần nghĩ về instruction cache, thì nên bỏ qua lời khuyên đó. Tham khảo "Typical C++ Bullshit" của Mike Acton sẽ giúp hiểu tầm quan trọng của lời khuyên này.
  • Có ý kiến cho rằng lập trình viên thường chú ý làm cho mã đẹp ở “đơn vị nhỏ”, nhưng lại không quan tâm đủ đến việc thiết kế toàn bộ codebase cho đúng. Nếu một hàm được đặt tên tốt, có interface tốt, mục đích rõ ràng, được tài liệu hóa phù hợp và không lạm dụng tác dụng phụ, thì không nên quá bận tâm chuyện bản thân hàm đó có lộn xộn hay cách sắp xếp iffor.
  • Từ một người bắt đầu lập trình trong lĩnh vực khoa học, có ý kiến rằng các tối ưu nhỏ là rất quan trọng. Dùng sai thứ tự vòng lặp for có thể rút thời gian chạy mô phỏng từ 1 tuần xuống còn 1 giờ. Những người có nền tảng như vậy sẽ tối ưu thứ tự của forif theo bản năng.
  • Có ý kiến cho rằng khi có một “container”, thay vì viết hàm cho container thì nên viết hàm cho “Thing” ở cấp độ miền nghiệp vụ mà container đang chứa. Điều này giúp mã linh hoạt hơn và phân tách rõ hơn giữa miền cốt lõi với các mối quan tâm của ứng dụng.
  • Có nhược điểm khi đẩy if lên trên là làm cho các điều kiện tiền đề và hậu điều kiện của hàm không còn nhìn thấy trực tiếp trong định nghĩa hàm. Trong các dự án lớn, những hàm như vậy có thể bị tái sử dụng ngoài ngữ cảnh dự định và gây lỗi. Dùng framework hợp đồng có thể là một cách giải quyết, nhưng khi đó phải viết điều kiện hai lần, cả trong hợp đồng lẫn trong mã.
  • Trong ví dụ dùng ngôn ngữ Rust, hệ thống kiểu mạnh của Rust ngăn nhu cầu lập trình phòng thủ vốn cần ở các ngôn ngữ khác. Việc lập trình viên C không kiểm tra tính hợp lệ của con trỏ được truyền vào hàm rồi gây ra dereference NULL là điều không mong muốn. Một số if nên nằm ở đầu hàm chứ không phải cuối hàm, và lỗi cần được truyền đi đúng cách.
  • Có ý kiến cho rằng bài viết tưởng như sẽ dẫn đến các ví dụ mã cụ thể, nhưng thực tế lại không như vậy. Thay vì các ví dụ mã được mong đợi, người viết đã đưa ra ví dụ khác.
  • Nếu không có ngữ cảnh phù hợp thì lời khuyên này có thể là lời khuyên kỳ quặc, thậm chí tệ. Vòng lặp for và câu lệnh if đều là các phép điều khiển luồng, nên một số lập luận trong bài có vẻ vô nghĩa. Lập luận về hiệu năng là mạnh nhất, nhưng với vai trò là mối lo đối với lời khuyên chung thì nên được xem xét sau cùng.
  • Có ý kiến cho rằng khó chắc các quy tắc chung như vậy có thể áp dụng vào mã thực tế hay không. Nhiều khi các quy tắc này bị xem như giáo điều sai lầm, và các lập trình viên trẻ có thể tiếp nhận sai rồi viết ra mã tệ hơn. Không thể đẩy if lên trên khi điều kiện thường phụ thuộc vào walrus.
  • Có ý kiến cho rằng việc đẩy if tiền đề lên phía caller là một ý tưởng khủng khiếp. Trong một số trường hợp đặc biệt thì có thể là ý hay, nhưng nhìn chung thì không nên làm vậy. Trong thư viện, nên kiểm tra điều kiện tiền đề ở ranh giới bên ngoài để phần triển khai bên trong có thể tiếp tục mà không cần các giả định nội bộ. Việc phụ thuộc vào caller để kiểm tra sẽ làm mất đi mục đích đó.