
8. Búa vàng
Búa vàng là một phản mẫu được xác định bởi sự tự tin rằng một giải pháp cụ thể có thể áp dụng phổ biến. Ví dụ:-
Sau khi gặp một vấn đề và tìm ra một mô hình cho giải pháp hoàn hảo, một lập trình viên cố gắng áp dụng mô hình này vào mọi nơi, áp dụng nó cho các dự án hiện tại và tương lai, thay vì tìm kiếm các giải pháp thích hợp cho các trường hợp cụ thể.
-
Một số nhà phát triển đã từng tạo biến thể bộ đệm của riêng họ cho một tình huống cụ thể (vì không có gì khác phù hợp). Sau đó, trong dự án tiếp theo không liên quan đến logic bộ đệm đặc biệt, họ đã sử dụng lại biến thể của mình thay vì sử dụng các thư viện được tạo sẵn (ví dụ: Ehcache). Kết quả là một loạt các lỗi và sự không tương thích, cũng như rất nhiều thời gian lãng phí và căng thẳng.
Bất cứ ai cũng có thể rơi vào mô hình chống này. Nếu bạn là người mới bắt đầu, bạn có thể không am hiểu về các mẫu thiết kế. Điều này có thể khiến bạn cố gắng giải quyết mọi vấn đề theo một cách mà bạn đã thành thạo. Nếu chúng ta đang nói về các chuyên gia, thì chúng ta gọi đây là sự biến dạng chuyên nghiệp hoặc mọt sách. Bạn có các mẫu thiết kế ưa thích của riêng mình và thay vì sử dụng mẫu phù hợp, bạn sử dụng mẫu yêu thích của mình, giả sử rằng sự phù hợp tốt trong quá khứ sẽ đảm bảo kết quả tương tự trong tương lai.
Cạm bẫy này có thể tạo ra những kết quả rất đáng buồn — từ việc triển khai tồi tệ, không ổn định và khó duy trì cho đến thất bại hoàn toàn của dự án. Cũng giống như không có một viên thuốc nào cho mọi bệnh tật, không có một mẫu thiết kế nào cho mọi trường hợp.
9. Tối ưu hóa sớm
Tối ưu hóa sớm là một anti-pattern mà cái tên của nó đã nói lên điều đó.10. Mã spaghetti
Mã spaghetti là một mã chống mẫu được xác định bởi mã có cấu trúc kém, khó hiểu và khó hiểu, chứa tất cả các loại phân nhánh, chẳng hạn như gói ngoại lệ, điều kiện và vòng lặp. Trước đây, toán tử goto là đồng minh chính của anti-pattern này. Các câu lệnh Goto không thực sự được sử dụng nữa, điều này giúp loại bỏ một số khó khăn và vấn đề liên quan.
public boolean someDifficultMethod(List<String> XMLAttrList) {
...
int prefix = stringPool.getPrefixForQName(elementType);
int elementURI;
try {
if (prefix == -1) {
...
if (elementURI != -1) {
stringPool.setURIForQName(...);
}
} else {
...
if (elementURI == -1) {
...
}
}
} catch (Exception e) {
return false;
}
if (attrIndex != -1) {
int index = attrList.getFirstAttr(attrIndex);
while (index != -1) {
int attName = attrList.getAttrName(index);
if (!stringPool.equalNames(...)){
...
if (attPrefix != namespacesPrefix) {
if (attPrefix == -1) {
...
} else {
if (uri == -1) {
...
}
stringPool.setURIForQName(attName, uri);
...
}
if (elementDepth >= 0) {
...
}
elementDepth++;
if (elementDepth == fElementTypeStack.length) {
...
}
...
return contentSpecType == fCHILDRENSymbol;
}
}
}
}
}
Nó trông khủng khiếp, phải không? Thật không may, đây là anti-pattern phổ biến nhất :( Ngay cả người viết mã như vậy cũng sẽ không thể hiểu nó trong tương lai. Các nhà phát triển khác nhìn thấy mã sẽ nghĩ, "Chà, nếu nó hoạt động, thì được thôi — tốt hơn hết là đừng chạm vào nó". Thông thường, một phương pháp ban đầu rất đơn giản và rất minh bạch, nhưng khi các yêu cầu mới được thêm vào, phương pháp đó dần dần được thêm vào với ngày càng nhiều câu lệnh điều kiện, biến nó thành một thứ quái dị như thế này. Nếu một phương pháp như vậy xuất hiện, bạn cần phải cấu trúc lại nó hoàn toàn hoặc ít nhất là những phần khó hiểu nhất. Thông thường, khi lên lịch cho một dự án, thời gian được phân bổ cho việc tái cấu trúc, ví dụ, 30% thời gian chạy nước rút là dành cho việc tái cấu trúc và kiểm tra. Tất nhiên, điều này giả định rằng không có bất kỳ sự vội vàng nào (nhưng khi nào điều đó xảy ra).đây .
11. Những con số kỳ diệu
Số ma thuật là một dạng phản mẫu trong đó tất cả các loại hằng số được sử dụng trong một chương trình mà không có bất kỳ lời giải thích nào về mục đích hoặc ý nghĩa của chúng. Đó là, chúng thường được đặt tên kém hoặc trong những trường hợp cực đoan, không có bình luận nào giải thích những bình luận đó là gì hoặc tại sao. Giống như mã spaghetti, đây là một trong những anti-pattern phổ biến nhất. Một người nào đó không viết mã có thể có hoặc không có manh mối về những con số kỳ diệu hoặc cách chúng hoạt động (và theo thời gian, chính tác giả sẽ không thể giải thích chúng). Do đó, việc thay đổi hoặc xóa một số sẽ khiến mã ngừng hoạt động cùng nhau một cách kỳ diệu. Ví dụ: 36 và 73. Để chống lại mô hình chống đối này, tôi khuyên bạn nên xem lại mã. Mã của bạn cần được xem xét bởi các nhà phát triển không tham gia vào các phần có liên quan của mã. Đôi mắt của họ sẽ tươi sáng và họ sẽ có câu hỏi: đây là gì và tại sao bạn lại làm như vậy? Và tất nhiên, bạn cần sử dụng tên giải thích hoặc để lại nhận xét.12. Lập trình sao chép và dán
Lập trình sao chép và dán là một kiểu chống đối trong đó mã của người khác được sao chép và dán một cách thiếu suy nghĩ, có thể dẫn đến các tác dụng phụ không lường trước được. Ví dụ: các phương pháp sao chép và dán bằng các phép tính toán học hoặc các thuật toán phức tạp mà chúng tôi không hiểu đầy đủ. Nó có thể hiệu quả đối với trường hợp cụ thể của chúng ta, nhưng trong một số trường hợp khác, nó có thể dẫn đến rắc rối. Giả sử tôi cần một phương thức để xác định số lượng tối đa trong một mảng. Lục lọi trên Internet, tôi tìm thấy giải pháp này:
public static int max(int[] array) {
int max = 0;
for(int i = 0; i < array.length; i++) {
if (Math.abs(array[i]) > max){
max = array[i];
}
}
return max;
}
Chúng tôi nhận được một mảng với các số 3, 6, 1, 4 và 2, và phương thức trả về 6. Tuyệt vời, hãy tiếp tục! Nhưng sau đó, chúng tôi nhận được một mảng bao gồm 2,5, -7, 2 và 3, và kết quả của chúng tôi là -7. Và kết quả này là không tốt. Vấn đề ở đây là Math.abs() trả về giá trị tuyệt đối. Sự thiếu hiểu biết về điều này dẫn đến thảm họa, nhưng chỉ trong một số tình huống nhất định. Nếu không tìm hiểu sâu về giải pháp, có nhiều trường hợp bạn sẽ không kiểm chứng được. Mã được sao chép cũng có thể vượt ra ngoài cấu trúc bên trong của ứng dụng, cả về mặt phong cách lẫn mức độ kiến trúc, cơ bản hơn. Mã như vậy sẽ khó đọc và bảo trì hơn. Và tất nhiên, chúng ta không được quên rằng việc sao chép trực tiếp mã của người khác là một loại đạo văn đặc biệt.
13. Phát minh lại bánh xe
Phát minh lại bánh xe là một phản mẫu, đôi khi còn được gọi là phát minh lại bánh xe hình vuông. Về bản chất, mẫu này đối lập với mẫu chống sao chép và dán được xem xét ở trên. Trong mô hình chống đối này, nhà phát triển thực hiện giải pháp của riêng mình cho một vấn đề mà các giải pháp đã tồn tại. Đôi khi những giải pháp hiện có này tốt hơn những gì lập trình viên phát minh ra. Thông thường, điều này chỉ dẫn đến mất thời gian và năng suất thấp hơn: lập trình viên có thể không tìm ra giải pháp nào cả hoặc có thể tìm ra giải pháp không phải là giải pháp tốt nhất. Điều đó nói rằng, chúng ta không thể loại trừ khả năng tạo ra một giải pháp độc lập, bởi vì làm điều đó là con đường trực tiếp dẫn đến lập trình sao chép và dán. Lập trình viên nên được hướng dẫn bởi các nhiệm vụ lập trình cụ thể phát sinh để giải quyết chúng một cách thành thạo, cho dù bằng cách sử dụng các giải pháp làm sẵn hoặc bằng cách tạo các giải pháp tùy chỉnh. Rất thường xuyên, lý do sử dụng mô hình chống này chỉ đơn giản là vội vàng. Kết quả là một phân tích nông về (tìm kiếm) các giải pháp làm sẵn. Phát minh lại bánh xe hình vuông là trường hợp phản mẫu đang được xem xét có kết quả tiêu cực. Đó là, dự án yêu cầu một giải pháp tùy chỉnh và nhà phát triển tạo ra nó, nhưng thật tệ. Đồng thời, một tùy chọn tốt đã tồn tại và những người khác đang sử dụng nó thành công. Điểm mấu chốt: một lượng lớn thời gian bị mất. Đầu tiên, chúng tôi tạo ra thứ gì đó không hoạt động. Sau đó, chúng tôi cố gắng cấu trúc lại nó, và cuối cùng chúng tôi thay thế nó bằng thứ đã tồn tại. Một ví dụ là triển khai bộ đệm tùy chỉnh của riêng bạn khi đã có nhiều triển khai. Cho dù bạn là một lập trình viên tài năng đến đâu, bạn nên nhớ rằng việc phát minh lại bánh xe vuông ít nhất cũng là một sự lãng phí thời gian. Và, như bạn đã biết, thời gian là tài nguyên quý giá nhất.14. Bài toán yo-yo
Vấn đề yo-yo là một phản mẫu trong đó cấu trúc của ứng dụng quá phức tạp do bị phân mảnh quá mức (ví dụ: chuỗi thừa kế được chia nhỏ quá mức). "Vấn đề yo-yo" phát sinh khi bạn cần hiểu một chương trình có hệ thống phân cấp kế thừa dài và phức tạp, tạo ra các lệnh gọi phương thức được lồng sâu. Do đó, các lập trình viên cần điều hướng giữa nhiều lớp và phương thức khác nhau để kiểm tra hành vi của chương trình. Tên của mô hình chống này xuất phát từ tên của đồ chơi. Ví dụ, hãy xem chuỗi kế thừa sau: Chúng ta có giao diện Công nghệ:
public interface Technology {
void turnOn();
}
Giao diện Transport kế thừa nó:
public interface Transport extends Technology {
boolean fillUp();
}
Và sau đó chúng ta có một giao diện khác, GroundTransport:
public interface GroundTransportation extends Transport {
void startMove();
void brake();
}
Và từ đó, chúng ta lấy được một lớp Car trừu tượng:
public abstract class Car implements GroundTransportation {
@Override
public boolean fillUp() {
/* some implementation */
return true;
}
@Override
public void turnOn() {
/* some implementation */
}
public boolean openTheDoor() {
/* some implementation */
return true;
}
public abstract void fixCar();
}
Tiếp theo là lớp Volkswagen trừu tượng:
public abstract class Volkswagen extends Car {
@Override
public void startMove() {
/* some implementation */
}
@Override
public void brake() {
/* some implementation */
}
}
Và cuối cùng, một mô hình cụ thể:
public class VolkswagenAmarok extends Volkswagen {
@Override
public void fixCar(){
/* some implementation */
}
}
Chuỗi này buộc chúng ta phải tìm kiếm câu trả lời cho những câu hỏi như:
-
Có bao nhiêu phương pháp
VolkswagenAmarok
? -
Loại nào nên được chèn thay vì dấu chấm hỏi để đạt được mức độ trừu tượng tối đa:
? someObj = new VolkswagenAmarok(); someObj.brake();
15. Sự phức tạp ngẫu nhiên
Sự phức tạp không cần thiết là một phản mẫu trong đó các biến chứng không cần thiết được đưa vào một giải pháp.
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description)throws Exception {
switch (type){
case CAR:
jdbcTemplate.update(CREATE_RELATION_WITH_CAR, languageId, serviceId, description);
case USER:
jdbcTemplate.update(CREATE_RELATION_WITH_USER, languageId, serviceId, description);
case FILE:
jdbcTemplate.update(CREATE_RELATION_WITH_FILE, languageId, serviceId, description);
case PLAN:
jdbcTemplate.update(CREATE_RELATION_WITH_PLAN, languageId, serviceId, description);
case CUSTOMER:
jdbcTemplate.update(CREATE_RELATION_WITH_CUSTOMER, languageId, serviceId, description);
default:
throw new Exception();
}
}
Và theo đó, chúng ta có enum này:
public enum ServiceType {
CAR(),
USER(),
FILE(),
PLAN(),
CUSTOMER()
}
Mọi thứ có vẻ đơn giản và tốt... Nhưng còn những phương pháp khác thì sao? Thật vậy, tất cả chúng cũng sẽ có một loạt switch
các câu lệnh và một loạt các truy vấn cơ sở dữ liệu gần như giống hệt nhau, do đó sẽ làm lớp của chúng ta phức tạp và phình to lên rất nhiều. Làm thế nào tất cả điều này có thể được thực hiện dễ dàng hơn? Hãy nâng cấp enum của chúng ta một chút:
@Getter
@AllArgsConstructor
public enum ServiceType {
CAR("cars_descriptions", "car_id"),
USER("users_descriptions", "user_id"),
FILE("files_descriptions", "file_id"),
PLAN("plans_descriptions", "plan_id"),
CUSTOMER("customers_descriptions", "customer_id");
private String tableName;
private String columnName;
}
Bây giờ mỗi loại có tên của các trường ban đầu của bảng. Do đó, phương pháp tạo mô tả trở thành:
private static final String CREATE_RELATION_WITH_SERVICE = "INSERT INTO %s(language_id, %s, description) VALUES (?, ?, ?)";
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description) {
jdbcTemplate.update(String.format(CREATE_RELATION_WITH_SERVICE, type.getTableName(), type.getColumnName()), languageId, serviceId, description);
}
Thật tiện lợi, đơn giản và nhỏ gọn phải không nào? Dấu hiệu của một nhà phát triển giỏi thậm chí không phải là tần suất anh ta hoặc cô ta sử dụng các mẫu, mà là tần suất anh ta hoặc cô ta tránh các phản mẫu. Sự thiếu hiểu biết là kẻ thù tồi tệ nhất, bởi vì bạn cần biết kẻ thù của mình bằng mắt thường. Vâng, đó là tất cả những gì tôi có cho ngày hôm nay. Cảm ơn mọi người! :)
GO TO FULL VERSION