Home » TechNote » Giới thiệu, tóm tắt sách “The art of readable code”

Giới thiệu, tóm tắt sách “The art of readable code”

The art of readable code” là cuốn sách thuộc về 2 tác giả Dustin Boswell và Trevor Foucher. Tư tưởng chính họ muốn truyền đạt là “code (mã nguồn chương trình) cần phải dễ đọc và dễ hiểu”, tối giản hóa thời gian cần thiết để người khác đọc hiểu code của bạn. Theo đó, các tác giả trình bày những phương pháp của họ để giúp các lập trình viên viết code dễ đọc hơn, kèm theo ví dụ chi tiết của từng phần.
Để giới thiệu cuốn sách tới mọi người, xin phép viết bài tóm tắt một số ý chính, thú vị trong cuốn sách mà bản thân thu được, đi theo thứ tự các chương và 4 phần
– Cải tiến bề mặt: cách đặt tên biến, tên hàm; viết comment và trình bày code
– Đơn giản hóa các vòng lặp và logic: cải thiện vòng lặp, logic tính toán, cách gán biến để chúng dễ hiểu hơn
– Tái cấu trúc code: cấu trúc các khối code ở cấp cao
– Chủ đề khác: áp dụng các phương pháp đã nêu cho test code và các cấu trúc dữ liệu lớn


Chapter 1: Code should be easy to understand – “Code nên viết sao cho dễ hiểu”
Chương 1 đặt vấn đề chung, làm thế nào để giúp code có tính dễ đọc, liệu có phải độ dài càng rút gọn càng tốt. Câu trả lời đưa ra rằng: code nên viết sao cho có thể giảm thiểu tối đa thời gian người khác cần để hiểu về chúng. Người khác ở đây là thành viên cùng đội, người review code, thậm chí là chính người viết đoạn code đó sau một thời gian nhìn lại.


Part 1: Surface level Improvements – Cải tiến bề mặt
Những cải tiến bề mặt thường là những việc khá đơn giản: chọn tên, viết comment, chỉnh sửa format code. Chúng ít ảnh hưởng tới hoạt động vốn có của chương trình nhưng lại có thể đem đến sự cải thiện đáng kể về độ sáng sủa trong code của bạn.


Chapter 2: Packing Information into names – Đóng gói thông tin trong tên gọi
Tên gọi của hàm, biến là điều đầu tiên người đọc nhìn thấy. Vì vậy đính kèm thông tin theo tên gọi của các đối tượng chính là cách truyền tải nội dung, mục đích của code hiệu quả nhất.


Sử dụng các từ cụ thể, đặc trưng
Ví dụ với mảng có thể thay hàm size() bằng hàm numberElements() – đếm số phần tử hoặc memoryBytes() – lấy dung lượng bộ nhớ cần thiết
Tránh dùng các từ chung chung như temp, tmp, retval …
Thêm các thông tin chi tiết, quan trọng vào trong tên
Ví dụ _ms với các biến mang giá trị đo theo đơn vị mili giây
Sử dụng tên dài cho các biến có vùng ảnh hưởng rộng
Dùng bổ sung các cách hiệu chỉnh như viết hoa, dấu gạch dưới
Ví dụ thêm dấu gạch dưới vào cuối để biểu thị thuộc tính của class, phân biệt với các biến thông thường.


Chapter 3: Names that can’t be misconstrued – Tên gọi không thể bị hiểu sai
Trong việc đặt tên, nên tránh dùng những từ ngữ có thể khiến người đọc hiểu theo nhiều nghĩa khác nhau


Nên sử dụng tiền tố min, max cho các giới hạn


const LIMIT_ELEMENTS_IN_ARRAY = 10

Người đọc sẽ phân vân liệu số lượng phần tử trong mảng yêu cầu nhỏ hơn 10, hay chấp nhận cả trường hợp mảng có tới 10 phần tử.
Thay vào đó

const MAX_ELEMENTS_IN_ARRAY = 10

Ý nghĩa trở nên rõ hơn rằng số lượng phần tử tối đa cho phép là 10
Nên sử dụng tên first, last cho các khoảng xác định
Khai báo hàm lấy xâu con của Java :

public String substring(int beginIndex, int endIndex)

Chỉ số beginIndex là 1 tên rõ nghĩa, ngược lại người đọc khó đoán được phương thức sẽ trả về xâu kết quả bao gồm ký tự có chỉ số endIndex hay không.Trên thực tế nếu gọi lệnh substring(0, 5), kết quả trả về là xâu có 5 ký tự chỉ số từ 0 tới 4. Vì vậy có thể thay khai báo thành public String substring(int firstIndex, int lastIndex), nghĩa sẽ rõ ràng hơn.
Các biến, hàm boolean: dùng các tiền tố is, has, can, should thể hiện giá trị của biến hoặc hàm là kiểu boolean
Ví dụ hàm

arr.empty()

  có thể hiểu là xóa hết các giá trị trong mảng, nếu sửa thành

arr.isEmpty()

  chắc chắn đây là hàm kiểu tra xem mảng có rỗng hay không.

Chapter 4: Aethetics – Tính thẩm mỹ
Cách trình bày, bố cục cũng góp phần quan trọng vào việc cải thiện chất lượng code. Những nguyên tắc chung cần nắm được:
– Sử dụng bố cục thích hợp, dễ dàng cho người đọc làm quen
– Các phần code tương tự nhau cũng cần trình bày giống nhau
– Nhóm các dòng lệnh liên quan thành từng khối lệnh


Theo đó, việc tổ chức code có thể áp dụng theo các gợi ý sau :
Ngắt dòng một cách nhất quán và gọn gàng
Sử dụng cách viết phân cột nếu cần thiết
Ví dụ




Chuyển thành



Chọn 1 thứ tự có nghĩa và duy trì một cách nhất quán: có thể là thứ tự đặt tham số trong khai báo gọi hàm, thứ tự gán giá trị cho biến
Nhóm các lệnh khai báo thành từng khối
Chia code có liên quan thành các đoạn riêng biệt ngăn cách với nhau, có thể them comment bổ sung cho từng đoạn


Lưu ý:Phong cách tổ chức, trình bày code của từng lập trình viên là khác nhau. Tuy nhiên điều quan trọng nhất là phong cách đó phải được sử dụng nhất quán, ổn định trong suốt quá trình viết code.


Chapter 5: Knowing what to comment – Nên viết những gì vào comment


Comment có vai trò quan trọng giúp người đọc hiểu về mục đích, ý nghĩa của code một cách nhanh hơn, đồng thời thể hiện được suy nghĩ của người lập trình khi tạo ra đoạn code đó


Những điều không nên viết trong comment
+ Không khuyến khích việc viết comment dưới dạng chỉ chép lại khai báo hàm, không có thông tin mới
Ví dụ




+ Thay vì phải viết quá nhiều comment cho hàm hoặc biến, có thể áp dụng các phương pháp trong chương 2 và 3 để đặt tên cho chúng một cách tốt nhất.
Ghi lại suy nghĩ của bản thân
+ Thêm chú thích chủ quan, ghi lại những tình huống khi có đoạn code đó
Ví dụ
// This heuristic might miss a few words. That’s OK; solving this 100% is hard.
+ Viết comment về những phần sai sót trong code
Một số tiền tố đánh dấu quen thuộc như : TODO, FIXME, HACK …
+ Viết comment cho các hằng số
Đặt mình vào vị trí của người đọc để tự hỏi liệu họ muốn biết thông tin gì trong phần comment


Chapter 6: Making comments precise and compact – Đảm bảo comment chính xác và ngắn gọn


Giữ cho comment được nhỏ gọn
Tránh dùng các đại từ mang nghĩa nhập nhằng
Ví dụ
// add value to the sum, but not in case it is greater than 20
Đại từ “it” trong câu trên không rõ là để chỉ “value” hay “the sum”
Có thể chuyển thành
// check if value is not greater than 20, then add it to the sum
Mô tả rõ ràng hoạt động của phương thức
Sử dụng các mẫu dữ liệu vào, mẫu kết quả trả về
Sử dụng các từ có nghĩa chặt


Part 2: Simplifying loops and logic – Đơn giản hóa các vòng lặp và logic


Chapter 7: Making control flows easy to read – Làm cho các luồng điều khiển trở nên dễ đọc


Thứ tự đối số trong mệnh đề so sánh


Đối số bên trái Đối số bên phải
Biểu thức có giá trị thay đổi nhiều hơn Biểu thức có giá trị ở mức độ ổn định hơn

Cách sắp xếp có thể diễn giản theo ngôn ngữ nói
Ví dụ : if (age > 18) – “nếu số tuổi lớn hơn 18” – sẽ dễ đọc hơn if (18 < age) – “nếu 18 nhỏ hơn số tuổi”
Thứ tự của các khối lệnh if/else
+ Ưu tiên các mệnh đề khẳng định hơn mệnh đề phủ định
+ Ưu tiên thực hiện các trường hợp đơn giản trước
+ Ưu tiên xử lý các trường hợp đáng chú ý trước
Hạn chế sử dụng do/while
Gọi lệnh return để trả về giá trị sớm trong hàm
Hạn chế sử dụng lệnh goto
–  Giảm các cấp lệnh lồng nhau
+ Sử dụng cách trả về kết quả sớm qua return
+ Bỏ lệnh lồng nhau trong các vòng lặp


Chapter 8: Breaking down giant expressions – Chia nhỏ các biểu thức lớn


Các biểu thức càng lớn thì việc kiểm soát cũng như hiểu được chúng lại càng trở nên khó khăn. Do đó mục tiêu là chia chúng thành các phần nhỏ hơn, dễ nắm bắt hơn.


Biến giải thích
Ví dụ :




trong đó username đóng vai trò là biến giải thích cho line.split(‘:’)[0].strip(), người đọc hiểu được đoạn code đang so sánh tên user với giá trị “root”
Biến tổng hợp : Với những biểu thức so sánh dài, ta có thể gán chúng vào một biến để dễ kiểm soát và chỉnh sửa
Ví dụ: var hasPermission = (ussername == file.owner || username == "root")
Dùng các luật của De Morgan: chuyển các biểu thức logic lớn thành tập hợp các biểu thức logic nhỏ hơn, giá trị thu được vẫn không đổi
Tránh lạm dụng các cách viết code logic rút gọn


Chapter 9: Variables and readability – Biến và tính dễ đọc
Các biến cần loại bỏ
+ Các biến tạm không tác dụng
+ Các kết quả trung gian thừa
+ Các biến đánh dấu luồng xử lý không cần thiết
Rút ngắn phạm vi ảnh hưởng của các biến
Phạm vi ảnh hưởng của 1 biến càng lớn thì người đọc càng phải ghi nhớ, lần theo giá trị của biến đó lâu hơn. Điều này sẽ gây rất nhiều khó khăn, nhầm lẫn.
Ưu tiên viết các biến khai báo 1 lần


Part 3: Reorganizing your code – Tái cấu trúc code


11921957_10203695619305843_1734407361_n
Chapter 10: Extracting unrelated subproblems – Tách rời những vấn đề không liên quan
– Code tiện ích thuần túy: cắt chuỗi, định dạng ngày tháng, quy đổi đơn vị …
– Tạo ra nhiều đoạn code xử lý chung
Các phần code này hoàn toàn tách rời phần còn lại của dự án. Điều đó khiến chúng trở nên dễ phát triển, test, cập nhật và đọc hiểu.
– Các hàm phục vụ riêng cho project
– Đơn giản hóa interface có sẵn
– Chỉnh sửa interface theo nhu cầu


Chapter 11: One task at a time – Thực hiện 1 công việc trong 1 thời điểm
Code cần tổ chức sao cho chỉ thực hiện 1 công việc cụ thể trong 1 thời điểm. Công việc đó có thể là nhập xuất dữ liệu, tính toán logic hoặc cập nhật cơ sở dữ liệu.


Trước hết nên liệt kê danh sách các công việc thực hiện trong chương trình. Một số công việc mang tính độc lập nên được chuyển thành các hàm hoặc lớp riêng biệt. Số còn lại sẽ trở thành những đoạn nhỏ trong 1 phương thức.


Chapter 12: Turning thoughts into code – Chuyển suy nghĩ vào trong code
Chương 12 nói về một kỹ thuật đơn giản nhưng hiệu quả: diễn giải chương trình bằng tiếng Anh đơn thuần và sử dụng diễn giải đó để viết lại code sao cho mang tính tự nhiên hơn. Khi xem xét từ ngữ diễn đạt, mô tả chương trình ta có thể nắm bắt, chia nhỏ các vấn đề  con bên trong.

Chapter 13: Writing less code – Viết ít code hơn


Biết được khi nào không cần code thêm chính là một trong những kỹ năng quan trọng nhất mà lập trình viên cần phải học. Mỗi dòng code mới đều đòi hỏi phải được test và bảo trì. Do đó nếu tận dụng được các thư viện có sẵn hoặc loại bỏ đi những chức năng, phương thức thừa thì bạn sẽ giữ được nội dung code sạch và có ý nghĩa.


Cách để tránh phát sinh thêm code:


Loại bỏ các chức năng thừa: Khi mới bắt đầu dự án, thông thường lập trình viên sẽ có hướng viết nhiều hàm, nhiều chức năng được cho là thú vị. Tuy nhiên sau một thời gian rà soát nếu chúng không hoặc ít phát huy tác dụng thì nên loại bỏ
Xem xét các yêu cầu: Thông thường với một vấn đề sẽ có một vài cách giải quyết khác nhau, độ phức tạp khác nhau. Do vậy việc cân nhắc chọn ra giải pháp ngắn gọn cũng giúp việc lập trình dễ đọc, dễ hiểu hơn
Sử dụng các thư viện hỗ trợ: Việc ghi nhớ và tận dụng các bộ thư viện có sẵn cũng sẽ giúp giảm đáng kể thời gian, công sức để giải quyết các bài toán đưa ra, đồng thời giảm cả khối lượng code cần viết.


Part 4: Selected topics – Những chủ đề khác


 Chapter 14: Testing and Readability – Áp dụng cho việc viết test code


  • Test code cần dễ đọc và dễ bảo trì
  • Rút ngắn các lệnh kiểm tra trong test code hết mức có thể
  • Tự định nghĩa một số hàm dùng chung để kiểm tra kết quả trong test code
  • Đưa ra các thông báo lỗi dễ hiểu hơn
  • Dùng phiên bản khác nhau của hàm assert()
  • Tự định nghĩa một số thông báo lỗi trong trường hợp test code đưa ra kết quả không thành công
  • Chọn các bộ dữ liệu test tốt
  • Đặt tên cho hàm trong test code: Có thể thêm thông tin về dữ liệu test, kết quả mong muốn trong tên của từng hàm test code để làm rõ nghĩa

Chapter 15: Designing and implementing a “Minute/Hour Counter”

Chương 15 trình bày cách vận dụng kết hợp các lý thuyết, phương pháp nên ở các phần trước để xây dựng, cải tiến code cho ứng dụng “Minute/Hour Counter”


Lời kết


“The art of readable code” cung cấp những phương pháp đơn giản, dễ hiểu trong việc tổ chức, trình bày code. Áp dụng được những phương pháp này giúp cho code trở nên sáng sủa, dẽ tiếp cận đối với người đọc cũng như lập trình viên.


Sách có văn phong dễ hiểu, minh họa hài hước, hệ thống ví dụ đơn giản, chi tiết cho từng phần, thích hợp cho tất cả các lập trình viên tìm đọc