Hiệu quả

Các lập trình viên có kinh nghiệm có thể dễ dàng phân biệt một kiến ​​trúc tốt với một kiến ​​trúc tồi, nhưng nếu được yêu cầu mô tả nó trong một vài từ, họ sẽ không thể làm được như vậy. Không có tiêu chí duy nhất cho kiến ​​trúc tốt và không có định nghĩa duy nhất.

Tuy nhiên, nếu bạn nghĩ về nó, bạn có thể viết ra một số tiêu chí mà một kiến ​​trúc tốt phải đáp ứng. Một kiến ​​trúc tốt trước hết là một kiến ​​trúc logic giúp quá trình phát triển và bảo trì chương trình trở nên đơn giản và hiệu quả hơn.

Khi một chương trình có kiến ​​trúc tốt, nó luôn đủ dễ dàng để hiểu cách thức hoạt động của nó và viết mã ở đâu. Một chương trình được kiến ​​trúc tốt sẽ dễ thay đổi, kiểm tra, gỡ lỗi và phát triển hơn. Những người thông minh đã xây dựng các tiêu chí sau đây cho kiến ​​trúc tốt:

  • Hiệu quả;
  • Uyển chuyển;
  • Khả năng mở rộng;
  • Khả năng mở rộng;
  • khả năng kiểm tra;
  • Khả năng bảo trì mã.

Hiệu quả hệ thống. Tất nhiên, chương trình phải giải quyết các nhiệm vụ được giao và thực hiện tốt các chức năng của nó, trong các điều kiện khác nhau. Có vẻ như bất kỳ chương trình nào cũng làm những gì nó nên làm (nếu nó được viết), nhưng thường thì điều này hoàn toàn không xảy ra.

Bạn sẽ liên tục bắt gặp các chương trình không làm những gì họ yêu cầu.

  • Libre Office là một sự thay thế hoàn toàn cho Microsoft Office (không thực sự);
  • Trình duyệt Edge hỗ trợ tất cả các tiêu chuẩn web (không thực sự);
  • Ngân hàng quan tâm đến tính bảo mật của dữ liệu cá nhân của người dùng (thực tế là không).

Và chúng tôi vẫn chưa đề cập đến hiệu suất, độ tin cậy, sửa lỗi kịp thời hoặc công bố thông tin về các lỗ hổng đã biết.

Rõ ràng là không có ai là hoàn hảo, nhưng chương trình phải giải quyết các nhiệm vụ chính của nó. Do đó, không hiệu quả thì chẳng đâu vào đâu.

Uyển chuyển

Theo tôi, điều duy nhất quan trọng hơn hiệu quả là tính linh hoạt. Bất kỳ ứng dụng nào cũng phải thay đổi theo thời gian, khi yêu cầu thay đổi, những ứng dụng mới sẽ được thêm vào. Việc thực hiện các thay đổi đối với chức năng hiện có càng nhanh chóng và thuận tiện thì càng gây ra ít sự cố và lỗi, kiến ​​trúc hệ thống càng linh hoạt .

Rất thường xuyên, các lập trình viên/kiến trúc sư mới làm quen nghĩ rằng họ cần một kiến ​​trúc lý tưởng cho các nhiệm vụ hiện tại. KHÔNG. Bạn cần một kiến ​​trúc lý tưởng cho các nhiệm vụ sẽ được thông báo cho bạn sau một năm. Bạn, bây giờ không biết các nhiệm vụ trong tương lai, nên biết chúng sẽ là gì.

Thật vô nghĩa khi cố gắng dự đoán chúng, bởi vì sẽ luôn có điều gì đó bất ngờ xảy ra. Nhưng bạn phải tính đến việc các nhiệm vụ như vậy sẽ xuất hiện. Do đó, trong quá trình phát triển, hãy cố gắng đánh giá những gì đang thu được về cách nó sẽ cần được thay đổi.

Hãy tự hỏi: "Điều gì xảy ra nếu quyết định kiến ​​trúc hiện tại là sai?", "Bao nhiêu mã sẽ được thay đổi?". Thay đổi một phân đoạn của hệ thống sẽ không ảnh hưởng đến các phân đoạn khác của nó.

Bất cứ khi nào có thể, các quyết định kiến ​​trúc không nên được đặt trong đá và hậu quả của các lỗi kiến ​​trúc nên được hạn chế một cách hợp lý. "Cấu trúc tốt cho phép bạn TRÌ HOÃN các quyết định quan trọng" (Bob Martin) và giảm thiểu "chi phí" của những sai lầm.

Một trong những cách tiếp cận này là chia nhỏ ứng dụng thành các dịch vụ siêu nhỏ: thật dễ dàng để chia logic đã tồn tại thành các phần riêng biệt. Nhưng vấn đề lớn nhất là thực hiện các thay đổi trong tương lai đối với hàng tá dịch vụ cùng một lúc để triển khai một tính năng nhỏ.

khả năng mở rộng

Khả năng mở rộng là khả năng giảm thời gian phát triển bằng cách thêm người mới vào dự án. Kiến trúc nên cho phép quá trình phát triển được song song để nhiều người có thể làm việc trên chương trình cùng một lúc.

Có vẻ như quy tắc này được thực hiện bởi chính nó, nhưng trong thực tế, mọi thứ hoàn toàn ngược lại. Thậm chí còn có một cuốn sách siêu nổi tiếng, The Mythical Man-Month , giải thích tại sao khi những người mới được thêm vào một dự án, thời gian phát triển sẽ tăng lên.

khả năng mở rộng

Khả năng mở rộng là khả năng thêm các tính năng và thực thể mới vào hệ thống mà không phá vỡ cấu trúc cốt lõi của nó. Ở giai đoạn ban đầu, chỉ nên đưa các chức năng cơ bản và cần thiết nhất vào hệ thống.

Đây được gọi là nguyên tắc YAGNI - bạn sẽ không cần nó , “bạn sẽ không cần nó”. Đồng thời, kiến ​​trúc sẽ cho phép bạn dễ dàng tăng thêm chức năng bổ sung khi cần. Và do đó, việc đưa ra những thay đổi có thể xảy ra nhất đòi hỏi ít nỗ lực nhất.

Yêu cầu về kiến ​​trúc của hệ thống phải linh hoạt và có thể mở rộng (nghĩa là có khả năng thay đổi và phát triển) quan trọng đến mức nó thậm chí còn được hình thành như một nguyên tắc riêng biệt - “Nguyên tắc Mở/Đóng . Nguyên tắc Open-Closed là nguyên tắc thứ hai trong năm nguyên tắc RẮN: các thực thể phần mềm (lớp, mô-đun, chức năng) nên mở để mở rộng, nhưng đóng để sửa đổi .

Nói cách khác: có thể thay đổi và mở rộng hành vi của hệ thống mà không cần viết lại các phần hiện có của hệ thống .

Điều này có nghĩa là ứng dụng phải được thiết kế theo cách sao cho việc thay đổi hành vi của ứng dụng và thêm chức năng mới có thể đạt được bằng cách viết mã mới (phần mở rộng) mà không phải thay đổi mã hiện có.

Trong trường hợp này, sự xuất hiện của các yêu cầu mới sẽ không đòi hỏi phải sửa đổi logic hiện có, nhưng có thể được thực hiện chủ yếu bằng cách mở rộng nó. Nguyên tắc này là cơ sở của “kiến trúc plug-in” (Plugin Architecture). Các kỹ thuật mà điều này có thể đạt được sẽ được thảo luận sau.

Nhớ servlet và bộ lọc? Tại sao các bộ lọc lại cần thiết, và ngay cả với các giao diện riêng biệt, nếu trên thực tế, tất cả logic tương tự có thể được triển khai bằng cách sử dụng các servlet?

Chính việc phát minh ra khái niệm bộ lọc (máy chủ dịch vụ) đã giúp chuyển các chức năng dịch vụ khác nhau sang một lớp riêng biệt. Và trong tương lai, khi thay đổi hành vi của các bộ lọc, không cần thiết phải thay đổi các servlet.

Trước khi phát minh ra bộ lọc, tất cả logic dịch vụ chịu trách nhiệm chuyển hướng các yêu cầu đều nằm trong chính các servlet. Và thường thì một thay đổi nhỏ về logic sẽ dẫn đến nhu cầu xem qua tất cả các servlet và thực hiện nhiều thay đổi khác nhau cho tất cả.

khả năng kiểm tra

Nếu bạn là Nhà phát triển phụ trợ Java, thì các ứng dụng máy chủ của bạn thường hiển thị một tập hợp các phương thức dưới dạng API REST. Và để kiểm tra xem tất cả các phương pháp của bạn có hoạt động như dự định hay không, chúng cần được kiểm tra.

Nói chung, phạm vi kiểm tra API là một phong cách tốt. Nó cho phép bạn đảm bảo rằng API của bạn thực sự làm những gì nó dự định làm. Ngoài ra, quan trọng hơn, bạn có thể thay đổi logic máy chủ và dễ dàng kiểm tra xem bạn có vô tình làm hỏng bất kỳ thứ gì không .

Ngay khi bạn bắt đầu viết bài kiểm tra, bạn sẽ nhận ra rằng hầu hết mã không thể kiểm tra được: các phương thức riêng tư, liên kết mạnh, các lớp tĩnh và các biến.

“Tại sao chúng ta cần kiểm tra nếu mã hoạt động?”, Người mới bắt đầu sẽ hỏi.

“Tại sao chúng ta cần mã làm việc nếu nó không thể được kiểm tra?”, Chuyên gia sẽ hỏi.

Mã dễ kiểm tra sẽ chứa ít lỗi hơn và đáng tin cậy hơn. Nhưng các bài kiểm tra không chỉ cải thiện chất lượng mã. Hầu như tất cả các nhà phát triển cuối cùng đều đi đến kết luận rằng yêu cầu về “khả năng kiểm thử tốt” cũng là một lực hướng dẫn tự động dẫn đến thiết kế tốt.

Đây là một trích dẫn từ cuốn sách Kiến trúc lý tưởng: "Sử dụng nguyên tắc "khả năng kiểm tra" của một lớp như một "bài kiểm tra giấy quỳ" về thiết kế lớp tốt. Ngay cả khi bạn không viết một dòng mã kiểm tra nào, hãy trả lời câu hỏi này trong 90 % trường hợp sẽ giúp hiểu mọi thứ tốt" hay "xấu" như thế nào với thiết kế của anh ấy."

Có cả một phương pháp để phát triển các chương trình dựa trên các bài kiểm tra, được gọi là Phát triển dựa trên bài kiểm tra (TDD). Tất nhiên, đây là một thái cực khác: viết mã trước khi bạn viết mã.

khả năng bảo trì mã

Theo quy định, rất nhiều người làm việc trong chương trình - một số rời đi, những người mới đến. Thời gian làm việc trung bình của một lập trình viên trong một công ty CNTT là một năm rưỡi. Vì vậy, nếu bạn đến với một dự án đã 5 năm tuổi, thì chỉ có 20% đồng nghiệp của bạn làm việc với nó ngay từ đầu.

Việc duy trì và phát triển một chương trình do người khác viết ra là rất khó. Ngay cả khi chương trình đã được viết, thường cần phải tiếp tục duy trì nó: sửa lỗi và thực hiện các chỉnh sửa nhỏ. Và thường thì điều này phải được thực hiện bởi những người không tham gia viết nó.

Do đó, một kiến ​​trúc tốt sẽ giúp những người mới hiểu hệ thống tương đối dễ dàng và nhanh chóng . Dự án phải là:

  • Cấu trúc tốt.
  • Không chứa trùng lặp.
  • Có mã được định dạng tốt.
  • Đó là mong muốn bao gồm tài liệu.
  • Cần áp dụng các giải pháp tiêu chuẩn và quen thuộc cho người lập trình.

Bạn có thể dễ dàng đánh giá dự án mà bạn đang thực hiện trên hệ thống 5 điểm . Chỉ cần tính hai điểm cho mỗi yêu cầu này . Và nếu bạn nhận được 5 hoặc nhiều hơn, thì bạn là người may mắn.

Các lập trình viên thậm chí còn có một nguyên tắc ít gây ngạc nhiên nhất : hệ thống càng kỳ lạ thì người khác càng khó hiểu. Thông thường, nó được sử dụng liên quan đến giao diện người dùng, nhưng nó cũng được áp dụng để viết mã.