1. The art of readable code
Chương I & II
GMO VNLAB
Trần Thanh Hiếu
Dustin Boswell and Trevor
Foucher
1
2. Giới thiệu
• Mục đích của cuốn sách là giúp lập
trình viên tạo ra những đoạn code
tốt hơn, dễ đọc, dễ hiểu.
• Cuốn sách không nói về những thứ
như architecture hay design
pattern mà sẽ tập trung vào những
kiến thức căn bản nhất liên quan
đến code như tên biến hay cách
viết vòng lặp.
2
3. Giới thiệu
Cuốn sách chia làm 4 phần
• Surface-level improvements
Cách đặt tên biến, chú thích …
• Simplifying loops and logic
Cách thức cải tiến vòng lặp, logic, biến để chương
trình dễ hiểu hơn
• Reorganizing your code
Cách thức tổ chức lại code
• Selected topics
Code dễ hiểu, dễ test và vấn đề về code cho cấu
trúc dữ liệu lớn
3
5. Cái gì làm code trở nên tốt
hơn?
Lựa chọn khi code
• Ngắn gọn, tối giản nhưng mất nhiều
thời gian cho người khác hiểu
• Dài dòng nhưng dễ hiểu
Chapter I 5
6. Nguyên lý cơ bản
“Code should be written to minimize the time it
would take for someone else to understand it.”
Code dễ đọc có thể giúp cho những
người mới tham gia dự án hay cho
chính bản thân khi mấy tháng sau
cần nhìn lại phần code này.
Ngoài ra cũng dễ dàng cho việc
tái sử dụng vào các dự án khác.
Chapter I 6
7. Is Smaller Always Better?
Giảm số dòng code là mục tiêu tốt
nhưng tối giản được thời gian hiểu
mới là mục tiêu tốt nhất.
Do đó có thể đánh đổi thêm 1 vài
dòng code và comment để code dễ
hiểu hơn
Chapter I 7
8. Does Time-Till-Understanding
Conflict with Other Goals?
Mục tiêu làm code dễ hiểu có bị xung
đột với các mục tiêu khác?
Theo kinh nghiệm của tác giả, các mục
tiêu khác cũng không bị ảnh hưởng
nhiều.
Dù đó là mức độ tối ưu code cao thì
cũng có phương án để code dễ hiểu.
Hơn nữa code dễ hiểu cũng thường có
cấu trúc tốt và thuận lợi hơn cho quá
trình kiểm thử.
Chapter I 8
10. Surface-Level Improvements
Nhiều sự thay đổi nhỏ sẽ tạo nên sự
cải thiện không ngờ cho toàn bộ code.
Không mất quá nhiều công sức nhưng
chắc chắn chỉ với việc đặt tên biến,
comment, và format tốt cũng sẽ làm
code dễ đọc, dễ hiểu hơn rất nhiều.
Cải tiến bề mặt đáng để quan tâm và
thực hiện trước tiên
Chapter II 10
11. Packing Information into Names
• Hãy nghĩ tên cũng như những comment nhỏ
• Good name có thể truyền đạt được rất nhiều
thông tin
Chapter II 11
12. 6 Topics
• Choose Specific Words
• Avoid Generic Names Like tmp and
retval
• Using concrete names instead of
abstract names
• Attaching extra information to a
name, by using a suffix or prefix
• Deciding how long a name should be
• Using name formatting to pack extra
information
Chapter II 12
13. 1.Choose Specific Words
• Chọn từ rõ ràng, tránh những từ
không có ý nghĩa.
class BinaryTree { int Size();
…}
Size ở là size gì ?
Good name: MemoryBytes()
KEY IDEA:
“It’s better to be clear and precise than to be cute”
Rõ ràng, chính xác thì tốt hơn.
Chapter II 13
14. 2.Avoid Generic Names Like
tmp
Thay vì chọn những cái empty name
như tmp, retval, foo thì hãy chọn
những cái tên mô tả giá trị của
biến.
Chapter II 14
15. Avoid Generic Names Like tmp
Ví dụ kinh điển:
if (right < left) { tmp = right;
right = left;
left = tmp; }
tmp ở đây được cho là hợp lý.
Lý do: Mục đích của nó chỉ lưu trú tạm thời
trong 3 line code và không có nhiệm vụ nào
khác.
Chapter II 15
16. Avoid Generic Names Like tmp
String tmp = user.name();
tmp += " " + user.phone_number(); tmp += " " +
user.email();
...
template.set("user_info", tmp);
Trường hợp trên thì việc sử dụng
tmp là một sự lười biếng
Lời khuyên:
Chỉ sử dụng tmp trong trường hợp
thời gian sống của biến ngắn.
Chapter II 16
17. Avoid Generic Names Like tmp
Loop Iterators
Liên quan đến vòng lặp, ngoài
việc sử dụng những chỉ mục thông
thường như i,j, trong một số trường
hợp nên sử dụng những chỉ mục với
tên chính xác hơn.
Chapter II 17
18. Avoid Generic Names Like tmp
for (int i = 0; i < clubs.size(); i++)
for (int j = 0; j < clubs[i].members.size(); j++)
for (int k = 0; k < users.size(); k++)
if (clubs[i].members[k] == users[j])
cout << "user[" << j << "] is
in club[" << i << "]" << endl;
Thay vì
if (clubs[i].members[k] == users[j])
Sử dụng
if (clubs[ci].members[mi] == users[ui])
Chữ cái c,m,u sẽ giúp dễ dàng phát hiện ra giá trị tương ứng với
mỗi vòng lặp. Người khác cũng sẽ nắm bắt được code nhanh hơn rất
nhiều.
Lời khuyên:
Cần xây dựng thói quen suy nghĩ đặt tên hợp lý
Chapter II 18
19. Prefer Concrete Names over
Abstract Names
Khi đặt tên biến, hàm, thuộc tính
hay mô tả:
Cụ thể luôn tốt hơn trừu tượng
Thay vì
ServerCanStart()
Sử dụng
CanListenOnPort()
Chapter II 19
20. 4. Attaching Extra
Information to a Name
Chapter II 20
Mỗi tên biến hãy coi như một chú thích nhỏ. Đảm bảo rằng
mỗi khi tên biến được nhìn thấy thì những thông tin quan
trọng nhất cũng được nắm bắt.
string id; // Example: "af84ef845cd8“
Sử dụng hex_id thay thế cho id người đọc dễ dàng hiểu
được format id
21. Values with Units
Giá trị và đơn vị
Thay vì
var start = (new Date()).getTime(); // top of
the page
Sử dụng
var start_ms = (new Date()).getTime(); // top of
the page
Có thể dễ dàng nhận ra giá trị
trả về là milliseconds
Chapter II 21
22. Values with Units
Function parameter Renaming parameter to encode units
Start(int delay) delay → delay_secs
CreateCache(int size) size → size_mb
ThrottleDownload(float limit) limit → max_kbps
Rotate(float angle) angle → degrees_cw
Chapter II 22
23. Encoding Other Important
Attributes
Hãy đính kèm định danh những thuộc
tính quan trọng
Dựa vào cách đặt tên này có thể dễ
dàng nhận ra password đang ở dạng
plaintext và cần được xử lý mã hóa
Mã html đã được chuyển đổi sang utf8
Chapter II 23
password plaintext_password
html html_utf8
24. HUNGARIAN NOTATION
Tham khảo hệ thống cách đặt tên
được sử dụng nhiều tại Microsoft
Đính kèm kiểu của tất cả các biến
trong tiền tố
Name Meaning
pLast A pointer (p) to the last element in some data structure
pszBuffer A pointer (p) to a zero-terminated (z) string (s) buffer
cch A count (c) of characters (ch)
mpcopx A map (m) from a pointer to a color (pco) to a pointer to an x-axis length (px)
24Chapter II
25. 5.How Long Should a Name Be?
Có một ràng buộc ngầm là không nên
đặt tên quá dài
newNavigationControllerWrappingViewControllerForDataSourceOf
Class
Quá khó nhớ và tiêu tốn nhiều không
gian.
Cân nhắc:
Đánh đổi giữa việc bao gồm nhiều nội dung và độ dài
của tên.
Chapter II 25
26. Shorter Names Are Okay for
Shorter Scope
Những định danh có phạm vi nhỏ
không cần mang quá nhiều thông tin
Phạm vi có thể hiểu là số lượng dòng code
có thể nhìn thấy định danh này.
Định danh sử dụng trong một phạm
vi lớn cần mang đủ thông tin để dễ
dàng nắm bắt.
Chapter II 26
27. Typing Long Names—Not a
Problem Anymore
• Hầu hết các lập trình viên đều không
chú ý tới tính năng “word completion”
của các text editor
• Hãy dùng thử ngay và đừng ngạc nhiên vì
sự chính xác bất ngờ của nó.
Chapter II 27
Editor Command
Vi Ctrl-p
Emacs Meta-/ (hit ESC, then /)
Eclipse Alt-/
IntelliJ IDEA Alt-/
TextMate ESC
28. Acronyms and Abbreviations
Lập trình viên vẫn hay sử dụng các từ
viết tắt để có các định ngắn gọn hơn
BEManager <-> BackEndManager
Sự ngắn gọn này có đáng cho những hiểu
nhầm có thể xảy ra?
Quy tắc:
Đồng đội mới phải hiểu được định danh có ý nghĩa gì.
Với những từ viết tắt phổ biến như
str,doc có thể được sử dụng nhưng như vd ở
trên BEManager thực sự khó có thể phán
đoán chính xác
28Chapter II
29. Throwing Out Unneeded Words
• Hãy loại bỏ những từ không cần
thiết
Chapter II 29
ConvertToString ToString
DoServeLoop ServeLoop
30. 6.Use Name Formatting to
Convey Meaning
Chỉ với việc sử dụng dấu gạch
dưới, gạch ngang hay viết hoa cũng
sẽ giúp truyền đạt thêm nhiều thông
tin.
Phần lớn các class chúng ta hay
viết có dạng
CamelCase
Phần lớn các biến sẽ có dạng
lower_separated
Chapter II 30
31. Other Formatting Conventions
JAVASCRIPT
Tác giả của cuốn sách avaScript :
The Good Parts (Douglas Crokford)
khuyên rằng constructor nên sử dụng
viết hoa và function bình thường
nên bắt đầu với ký tự low
var x = new DatePicker(); // DatePicker() is a
"constructor" function
var y = pageHeight(); // pageHeight() is an ordinary
function
Chapter II 31
32. Other Formatting Conventions
JQUERY
var $all_images = $("img"); // $all_images is a jQuery
object
var height = 250; // height is not
Sử dụng tiền tố $
Dễ dàng nắm bắt được
$all_images là 1 jquery result
object
Chapter II 32
34. Other Formatting Conventions
• Cho dù sử dụng hế thống quy tắc
nào thì nó cũng sẽ giúp ích rất
nhiều cho hoạt động chung của cả
team.
• Và 1 hệ thống nên được duy trì
xuyên suốt project
Chapter II 34
35. Summary
• Use specific words
Featch, Download thì tốt hơn Get
• Avoid generic names
tmp, retval chỉ sử dụng khi có lý do đặc biệt
• Use concrete names
CanListenOnPort() tốt hơn là ServerCanStart()
• Attach important details
append_ms ms sẽ cho biết giá trị của nó là dạng milliseconds
• Use longer names for larger scopes
Tên ngắn chỉ tốt khi được sử dụng tại vài line code. Với phạm vi rộng
cần chứa nhiều thông tin để dễ nắm bắt
• Use capitalization, underscores, and so on in a
meaningful way
Sử dụng hợp lý ký tự viết hoa, gạch chân để truyền đạt nhiều ý nghĩa hơn
35