Các mô hình chống bạn nên tránh trong mã của mình

Mọi nhà phát triển đều muốn viết mã có cấu trúc, được lập kế hoạch đơn giản và được nhận xét độc đáo. Thậm chí có vô số các mẫu thiết kế cung cấp cho chúng ta những quy tắc rõ ràng để tuân theo và một khuôn khổ cần ghi nhớ.

Nhưng chúng ta vẫn có thể tìm thấy các mẫu chống trong phần mềm được viết một thời gian hoặc được viết quá nhanh.

Một cách hack cơ bản vô hại để giải quyết vấn đề một cách nhanh chóng có thể tạo tiền lệ trong cơ sở mã của bạn. Nó có thể được sao chép ở nhiều nơi và biến thành một kiểu chống đối mà bạn cần giải quyết.

Vậy anti-pattern là gì?

Trong phần mềm, anti-pattern là một thuật ngữ mô tả cách KHÔNG giải quyết các vấn đề lặp lại trong mã của bạn. Anti-pattern được coi là thiết kế phần mềm tồi và thường là các bản sửa lỗi không hiệu quả hoặc ít người biết đến.  

Họ thường cũng thêm "nợ kỹ thuật" - là mã bạn phải quay lại và sửa chữa đúng cách sau này.

Sáu kiểu chống đối mà tôi sẽ thảo luận trong bài viết này là Mã Spaghetti , Búa vàng , Neo thuyền , Mã chết , Tăng sinh mãVật thể thần .

Mã mì Ý

Mã Spaghetti là mô hình chống được biết đến nhiều nhất. Nó là mã có cấu trúc từ ít đến 0.

Không có gì là modularised. Có các tệp ngẫu nhiên nằm trong các thư mục ngẫu nhiên. Toàn bộ dòng chảy rất khó theo dõi, và hoàn toàn bị rối với nhau (giống như mỳ Ý).

Thông thường, đây là một vấn đề mà ai đó đã không suy nghĩ cẩn thận về quy trình của chương trình của họ trước đó và chỉ mới bắt đầu viết mã.

Nó làm gì?! Tôi không thể theo dõi cái này

image.png

Đây không chỉ là cơn ác mộng về bảo trì mà còn khiến nó không thể bổ sung thêm chức năng mới.

Bạn sẽ liên tục phá vỡ mọi thứ, không hiểu phạm vi thay đổi của mình hoặc đưa ra bất kỳ ước tính chính xác nào cho công việc của mình vì không thể lường trước được vô số vấn đề nảy sinh khi thực hiện khảo cổ / phỏng đoán như vậy.

Bạn có thể đọc thêm ở đây về mẫu chống Spaghetti Code .

Búa vàng

"Tôi cho rằng thật hấp dẫn, nếu công cụ duy nhất bạn có là một cái búa, để coi mọi thứ như thể nó là một cái đinh." Abraham Maslow

Hãy tưởng tượng một kịch bản với tôi: đội ngũ nhà phát triển của bạn rất, rất giỏi về kiến ​​trúc Hammer hoàn toàn mới. Nó đã hoạt động tuyệt vời cho tất cả các vấn đề trong quá khứ của bạn. Bạn là nhóm kiến ​​trúc Hammer hàng đầu thế giới.

Nhưng bây giờ, bằng cách nào đó, mọi thứ luôn kết thúc bằng cách sử dụng kiến ​​trúc này. Một con vít đầu phẳng? Cây búa. Phillips đầu vít? Cây búa. Bạn cần một cờ lê Allen? Không, bạn không, hãy búa đi.

Bạn bắt đầu áp dụng một cách tiếp cận kiến ​​trúc không hoàn toàn phù hợp với những gì bạn cần nhưng vẫn hoàn thành công việc. Bạn đang quá phụ thuộc vào một khuôn mẫu và cần tìm hiểu công cụ tốt nhất để có công việc tốt nhất.

Toàn bộ chương trình của bạn có thể kết thúc bằng một màn trình diễn nghiêm trọng vì bạn đang cố ghép một hình vuông thành một hình tròn. Bạn biết phải mất gấp đôi thời gian để viết mã và thực thi một chương trình bằng kiến ​​trúc búa cho vấn đề này, nhưng nó dễ dàng hơn và đó là điều bạn cảm thấy thoải mái.

Nó cũng không phải là rất dễ đoán. Các ngôn ngữ khác nhau có các bản sửa lỗi chung cho các vấn đề mà chúng gặp phải và các tiêu chuẩn riêng của chúng. Bạn không thể áp dụng mọi quy tắc phù hợp với bạn bằng một ngôn ngữ cho ngôn ngữ tiếp theo mà không gặp vấn đề gì.

Đừng bỏ bê việc học tập nhất quán trong sự nghiệp của bạn. Chọn ngôn ngữ phù hợp cho vấn đề của bạn. Hãy suy nghĩ về kiến ​​trúc và đẩy ra vùng an toàn của bạn. Nghiên cứu và điều tra các công cụ mới và cách mới để tiếp cận các vấn đề bạn gặp phải.

Bạn có thể tham khảo thêm tại đây về mẫu chống Búa Vàng .

Neo thuyền

Các thuyền neo chống mẫu là nơi các lập trình viên lại mã kiểm tra vào codebase vì họ có thể cần nó sau này.

Họ đã viết một cái gì đó hơi sai đặc điểm kỹ thuật và nó chưa cần thiết, nhưng họ chắc chắn rằng họ sẽ làm trong tháng tới. Vì vậy, họ không muốn xóa nó. Gửi nó đến nơi sản xuất và sau đó khi họ cần, họ có thể nhanh chóng làm cho nó hoạt động.

Nhưng điều này gây ra cơn ác mộng bảo trì trong cơ sở mã có chứa tất cả mã lỗi thời. Vấn đề lớn là các đồng nghiệp của họ sẽ gặp khó khăn khi tìm ra mã nào đã lỗi thời và không thay đổi quy trình, so với mã hiện có.

Hãy tưởng tượng bạn đang thực hiện một bản sửa lỗi nóng và đang cố gắng tìm ra những gì có trách nhiệm gửi chi tiết thẻ của khách hàng tới API để rút tiền từ ngân hàng của họ. Bạn có thể lãng phí thời gian để đọc và gỡ lỗi mã lỗi thời mà không nhận ra rằng bạn thậm chí không ở đúng vị trí trong cơ sở mã.

Vấn đề cuối cùng là, mã lỗi thời làm cho thời gian xây dựng của bạn lâu hơn và bạn có thể trộn lẫn mã đang hoạt động và lỗi thời. Bạn thậm chí có thể bắt đầu vô tình "bật nó lên" trong quá trình sản xuất.

Bây giờ bạn có thể thấy lý do tại sao nó được gọi là mô hình chống neo thuyền - nó rất nặng khi mang theo (thêm nợ kỹ thuật) nhưng không làm được gì (hoàn toàn theo nghĩa đen, mã không phục vụ mục đích, nó không hoạt động).

Bạn có thể tham khảo thêm tại đây về Mẫu chống neo thuyền .

Mã chết

Bạn đã bao giờ phải nhìn vào đoạn mã được viết bởi một người không còn làm việc tại công ty của bạn nữa không? Có một chức năng không giống như nó đang làm gì cả. Nhưng nó được gọi từ khắp mọi nơi! Bạn hỏi xung quanh và không ai khác chắc chắn nó đang làm gì, nhưng mọi người quá lo lắng để xóa nó.

Đôi khi bạn có thể thấy nó đang làm gì, nhưng không có ngữ cảnh. Bạn có thể đọc và hiểu quy trình, nhưng tại sao? Có vẻ như chúng ta không cần phải đạt được điểm cuối đó nữa. Phản hồi luôn giống nhau cho mọi người dùng khác nhau.

Điều này thường được mô tả là mô hình chống mã chết . Khi bạn không thể thấy mã "thực tế" cần thiết cho luồng và thực thi thành công chương trình của mình, so với những gì chỉ cần 3 năm trước, chứ không phải bây giờ.

Mô hình phản đối cụ thể này phổ biến hơn trong bằng chứng về khái niệm hoặc mã nghiên cứu đã được đưa vào sản xuất.

Một lần nọ tại một buổi họp mặt về công nghệ, tôi đã gặp một anh chàng có vấn đề chính xác này. Anh ta có hàng tấn mã chết, mà anh ta biết là đã chết, và rất nhiều thứ anh ta nghi ngờ là đã chết. Nhưng anh ấy không thể xin phép quản lý để xóa tất cả các mã chết.

Anh gọi phương pháp tiếp cận của mình là thử nghiệm Khỉ, nơi anh bắt đầu bình luận và tắt mọi thứ để xem điều gì đã xảy ra trong quá trình sản xuất. Có lẽ hơi quá mạo hiểm!

If you don't fancy Monkey testing your production app, try to frame technical debt to management as "technical risk" to better explain why you think it's so important to tidy up.

Or even write down everything your particular module/section does you want to re-write, and take an iterative approach to remove piece by piece the dead code. Checking every time you haven't broken anything.

You don't have to drop a huge rewrite with thousands of changes. But you will either understand why it's so crucial and document why it's needed, or delete the dead code as you desired.

You can read more here about the Dead code anti-pattern.

Proliferation of Code

Objects or modules regularly communicate with others. If you have a clean, modularised codebase you often will need to call into other separate modules and call new functions.

The Proliferation of Code anti-pattern is when you have objects in your codebase that only exist to invoke another more important object. Its purpose is only as a middleman.

This adds an unnecessary level of abstraction (adds something that you have to remember) and serves no purpose, other than to confuse people who need to understand the flow and execution of your codebase.

A simple fix here is to just remove it. Move the responsibility of invoking the object you really want to the calling object.

You can read more here about the Proliferation of Code anti-pattern.

God Object

If everywhere in your codebase needs access to one object, it might be a God object.

God objects do too much. They are responsible for the user id, the transaction id, the customer's first and last name, the total sum of the transaction, the item/s the user is purchasing...you get the picture.

It is sometimes called the Swiss Army Knife anti-pattern because you only really need it to cut some twine, but it also can be a nail file, saw, pair of tweezers, scissors, bottle opener and a cork screw too.

In this instance you need to separate out and modularise your code better.

Programmers often compare this problem to asking for a banana, but receiving a gorilla holding a banana. You got what you asked for, but more than what you need.

The SOLID principles explicitly discuss this in object orientated languages, to help us model our software better (if you don't know what the SOLID principles are, you can read this article).

The S in the acronym stands for Single Responsibility - every class/module/function should have responsibility over one part of the system, not multiple.

You can see this problem over and over again, how about the below interface?

interface Animal { numOfLegs: string; weight: number; engine: string; model: string; sound: string; claws: boolean; wingspan: string; customerId: string; } 

Can you see by even just briefly scanning this interface that the responsibility of this is far too broad, and needs refactoring? Whatever implements this has the potential to be a God object.

How about this?

 interface Animal { numOfLegs: string; weight: number; sound: string; claws: boolean; } interface Car { engine: string; model: string; } interface Bird { wingspan: string; } interface Transaction { customerId: string; } 

Interface segregation will keep your code clear about where the responsibilities lie, and stop forcing classes that only need wingspan to also implement the engine, customerId and model  and so on.

Bạn có thể đọc thêm tại đây về mẫu chống đối tượng God .

Phần kết luận

Trong bất kỳ cơ sở mã lớn nào, luôn có sự cân bằng giữa việc quản lý nợ kỹ thuật, bắt đầu phát triển mới và quản lý hàng đợi lỗi cho sản phẩm của bạn.

Tôi hy vọng bài viết này đã giúp bạn biết được khi nào bạn có thể đi xuống lỗ thỏ của một mô hình chống và một số công cụ để giải quyết nó một cách sạch sẽ.

Tôi chia sẻ bài viết của tôi trên Twitter nếu bạn thích bài viết này và muốn xem thêm.