Giới thiệu cuốn “The Art of Readable Code” (4)
Bài đăng này đã không được cập nhật trong 9 năm
Cuốn sách này của Dustin Boswell và Trevor Foucher tập trung vào các kỹ thuật đơn giản và hữu hiệu để viết code tốt hơn. Bạn có thể áp dụng các kỹ thuật này bất cứ khi nào bạn viết code. Tác giả trình bày các ý tưởng chính sau:
i. Cần viết code dễ hiểu
ii. Cần viết code để người đọc tốn ít thời gian nhất để hiểu. Tác giả sử dụng các ví dụ dễ hiểu được viết trên nhiều ngôn ngữ để trình bày trong các chương các khía cạnh khác nhau để giúp bạn viết code dễ hiểu.
I. Đặt tên, chú thích và định dạng đơn giản - sử dụng cho tất cả các dòng code bạn viết
II. Giảm thiểu sự phức tạp và mập mờ trong cách dùng các vòng lặp, logic và các biến
III. Xem xét vấn đề ở mức độ hàm, như cấu trúc lại các khối code để thực hiện 1 task 1 lần
IV. Viết code để test hiệu quả, chính xác và dễ đọc.
IV. Viết code để test hiệu quả, chính xác và dễ đọc.
Ví dụ, chúng ta có đoạn code test sau:
void Test1() {
vector docs;
docs.resize(5);
docs[0].url = "http://example.com";
docs[0].score = -5.0;
docs[1].url = "http://example.com";
docs[1].score = 1;
docs[2].url = "http://example.com";
docs[2].score = 4;
docs[3].url = "http://example.com";
docs[3].score = -99998.7;
docs[4].url = "http://example.com";
docs[4].score = 3.0;
SortAndFilterDocs(&docs);
assert(docs.size() == 3);
assert(docs[0].score == 4);
assert(docs[1].score == 3.0);
assert(docs[2].score == 1);
}
1. Viết test dễ đọc hơn
Chúng ta có thể viết hàm sau
void AddScoredDoc(vector& docs, double score) {
ScoredDocument sd;
sd.score = score;
sd.url = "http://example.com";
docs.push_back(sd);
}
Sử dụng hàm này để viết lại chương trình test
void Test1() {
vector docs;
AddScoredDoc(docs, -5.0);
AddScoredDoc(docs, 1);
AddScoredDoc(docs, 4);
AddScoredDoc(docs, -99998.7);
...
}
2. Dùng lời giải thích test đơn giản nhất
Dùng lời giải thích code test này là chúng ta có một danh sách các văn bản có các điểm số là [-5, 1, 4, -99998.7, 3]
. Sau hàm SortAndFilterDocs()
, các văn bản còn lại cần phải có điểm theo thứ tự sau [4, 3, 1]
. Vậy code test của chúng ta nên có dạng CheckScoresBeforeAfter("-5, 1, 4, -99998.7, 3", "4, 3, 1");
3. Thực hiện Custom “Minilanguages”
Để ý rằng CheckScoresBeforeAfter() lấy 2 biến string là mảng của các điểm. Trong C++, viết dưới dạng array như sau
CheckScoresBeforeAfter({-5, 1, 4, -99998.7, 3}, {4, 3, 1});
Vì chúng ta để các scores dưới dạng string, phân tách bởi dấm phảy nên chúng ta cần hàm phân tích các biến string và chuyển đổi giữa string và vector
void CheckScoresBeforeAfter(string input, string expected_output) {
vector docs = ScoredDocsFromString(input);
SortAndFilterDocs(&docs);
string output = ScoredDocsToString(docs);
assert(output == expected_output);
}
vector:
vector ScoredDocsFromString(string scores) {
vector docs;
replace(scores.begin(), scores.end(), ',', ' ');
// Populate 'docs' from a string of space-separated scores.
istringstream stream(scores);
double score;
while (stream >> score) {
AddScoredDoc(docs, score);
}
return docs;
}
string ScoredDocsToString(vector docs) {
ostringstream stream;
for (int i = 0; i 0) stream << ", ";
stream << docs[i].score;
}
return stream.str();
}
Ban đầu có vẻ như là cần nhiều code nhưng sau đó nó sẽ thực sự hữu dụng.
4. Thực hiện các thông báo lỗi dễ hiểu
Nếu chúng ta dùng
assert(output == expected_output)
Thông báo lỗi fail sẽ có dạng như sau
Assertion failed: (output == expected_output),
function CheckScoresBeforeAfter, file test.cc, line 37.
Ta sẽ không biết input và output nên ta có thể viết cách khác như sau sử dụng thư viện Boost C++
BOOST_REQUIRE_EQUAL(output, expected_output)
Bây giờ, nếu test fails, nó sẽ báo
test.cc(37): fatal error in "CheckScoresBeforeAfter": critical check
output == expected_output failed ["1, 3, 4" != "4, 3, 1"]
5. Chọn đúng test input
Thay vì chọn
CheckScoresBeforeAfter("-5, 1, 4, -99998.7, 3", "4, 3, 1");
ta có thể chọn
CheckScoresBeforeAfter("1, 2, -1, 3", "3, 2, 1");
Ta chọn các giá trị dương đơn giản để test việc sắp xếp và chọn 1 giá trị âm để test việc loại bỏ các giá trị âm đi.
6. Nhiều hàm test chức năng
Ví dụ 4 hàm sau
CheckScoresBeforeAfter("2, 1, 3", "3, 2, 1"); // Basic sorting
CheckScoresBeforeAfter("0, -0.1, -10", "0"); // All values < 0 removed
CheckScoresBeforeAfter("1, -2, 1, -2", "1, 1"); // Duplicates not a problem
CheckScoresBeforeAfter("", ""); // Empty input OK
7. Đặt tên hàm test
Thay vì đặt tên là
void Test1(){
...
}
ta có thể đặt là
void Test_SortAndFilterDocs(){
...
}
End
All rights reserved