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ụ
Void createUser(String name, Int age, String email, String address) createUser(“ga con”, 1, “ga@gmail.com”, “chuong ga”); createUser(“Nguyen Van A”, 25, “”, “dai lo Thang Long”); createUser(“Optimus Prime”, 200,”ops@cybertron.org”, “”);
Chuyển thành
Void createUser(String name, Int age, String email, String address) createUser(“ga con” , 1 , “ga@gmail.com” , “chuong ga”); createUser(“Nguyen Van A” , 25 , “” , “dai lo Thang Long”); createUser(“Optimus Prime” , 200 ,”ops@cybertron.org”, “”);
– 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ụ
// find users by given name, given age Array findUsers(String name, Int age)
+ 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ụ :
username = line.split(':')[0].strip() if username == "root":
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
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