Tôi hiện đang đọc và làm việc thông qua "Mã sạch: Cẩm nang về thủ công phần mềm linh hoạt" của Robert C. Martin. Tác giả nói về cách một chức năng chỉ nên làm một việc, và do đó tương đối ngắn. Cụ thể Martin viết:
Điều này ngụ ý rằng các khối trong câu lệnh if, câu lệnh khác, trong khi câu lệnh, v.v. nên dài một dòng. Có lẽ dòng đó nên là một chức năng gọi. Điều này không chỉ giữ cho hàm bao quanh nhỏ, mà còn thêm giá trị tài liệu vì hàm được gọi trong khối có thể có một tên mô tả độc đáo.
Điều này cũng ngụ ý rằng các chức năng không nên đủ lớn để giữ các cấu trúc lồng nhau. Do đó, mức thụt lề của hàm không được lớn hơn một hoặc hai. Điều này, tất nhiên, làm cho các chức năng dễ đọc và dễ hiểu hơn
Điều này có ý nghĩa, nhưng dường như mâu thuẫn với các ví dụ về những gì tôi thấy là mã sạch. Lấy phương pháp sau đây làm ví dụ:
public static boolean millerRabinPrimeTest(final int n) {
final int nMinus1 = n - 1;
final int s = Integer.numberOfTrailingZeros(nMinus1);
final int r = nMinus1 >> s;
//r must be odd, it is not checked here
int t = 1;
if (n >= 2047) {
t = 2;
}
if (n >= 1373653) {
t = 3;
}
if (n >= 25326001) {
t = 4;
} // works up to 3.2 billion, int range stops at 2.7 so we are safe :-)
BigInteger br = BigInteger.valueOf(r);
BigInteger bn = BigInteger.valueOf(n);
for (int i = 0; i < t; i++) {
BigInteger a = BigInteger.valueOf(SmallPrimes.PRIMES[i]);
BigInteger bPow = a.modPow(br, bn);
int y = bPow.intValue();
if ((1 != y) && (y != nMinus1)) {
int j = 1;
while ((j <= s - 1) && (nMinus1 != y)) {
long square = ((long) y) * y;
y = (int) (square % n);
if (1 == y) {
return false;
} // definitely composite
j++;
}
if (nMinus1 != y) {
return false;
} // definitely composite
}
}
return true; // definitely prime
}
}
Mã này được lấy từ repo mã nguồn Apache Commons tại: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/primes/SmallPrimes.java
Phương pháp này rất dễ đọc đối với tôi. Đối với các triển khai thuật toán như thế này (triển khai Kiểm tra tính nguyên thủy của Miller-Rabin), liệu có phù hợp để giữ mã như hiện tại và vẫn coi đó là 'sạch', như được định nghĩa trong sách không? Hoặc thậm chí một cái gì đó đã có thể đọc được vì lợi ích này từ việc trích xuất các phương thức để làm cho thuật toán về cơ bản là một chuỗi các hàm gọi "chỉ làm một việc"? Một ví dụ nhanh về trích xuất phương thức có thể là di chuyển ba câu lệnh if đầu tiên sang một hàm như:
private static int getTValue(int n)
{
int t = 1;
if (n >= 2047) {
t = 2;
}
if (n >= 1373653) {
t = 3;
}
if (n >= 25326001) {
t = 4;
}
return t;
}
Lưu ý: Câu hỏi này khác với câu hỏi có thể trùng lặp (mặc dù câu hỏi đó cũng hữu ích với tôi), vì tôi đang cố xác định xem tôi có hiểu ý định của tác giả của Clean Code hay không và tôi đang cung cấp một ví dụ cụ thể để làm cho mọi thứ nhiều hơn bê tông.