效率

有經驗的程序員可以很容易地分辨出架構的好壞,但如果被要求用幾句話來描述它,他們不太可能做到。好的架構沒有單一的標準,也沒有單一的定義。

然而,如果你仔細想想,你可以寫出一些好的架構應該滿足的標準。一個好的架構首先是一個邏輯架構,它可以讓程序的開發和維護過程更簡單、更高效。

當程序具有良好的體系結構時,總是很容易理解它是如何工作的以及在何處編寫代碼。一個結構良好的程序更容易更改、測試、調試和開發。聰明人制定了以下優秀架構的標準:

  • 效率;
  • 靈活性;
  • 可擴展性;
  • 可擴展性;
  • 可測性;
  • 代碼可維護性。

系統效率。當然,該程序必須解決分配的任務並在各種條件下良好地執行其功能。似乎任何程序都在做它應該做的事情(如果它被編寫的話),但通常情況並非如此。

您會經常遇到一些程序,它們並沒有按照他們聲稱的那樣去做。

  • Libre Office 是 Microsoft Office 的完全替代品(不是真的);
  • Edge 瀏覽器支持所有網絡標準(不是真的);
  • 銀行關心其用戶個人數據的安全(實際上不關心)。

而且我們還沒有涉及性能、可靠性、及時的錯誤修復或有關已知漏洞的信息的發布。

很明顯,沒有人是完美的,但程序必須解決其主要任務。因此,沒有效率,無處可去。

靈活性

在我看來,唯一比效率更重要的是靈活性。任何應用程序都必須隨著時間的推移而變化,隨著需求的變化,新的需求會被添加。對現有功能進行更改越快、越方便,引起的問題和錯誤越少,系統架構就越靈活。

很多時候,新手程序員/架構師認為他們需要一個理想的架構來完成當前的任務。不。你需要一個理想的架構來完成一年後向你宣布的任務。你,現在已經不知道未來的任務,應該知道它們會是什麼。

試圖預測它們是沒有意義的,因為總會有意想不到的事情發生。但是您必須考慮到會出現此類任務。因此,在開發過程中,嘗試根據需要如何更改來評估正在獲得的內容。

問問自己:“如果當前的架構決策被證明是錯誤的,會發生什麼?”、“將更改多少代碼?”。更改系統的一個片段不應影響其其他片段。

只要有可能,架構決策不應該一成不變,架構錯誤的後果應該合理限制。“良好的架構允許您延遲關鍵決策”(Bob Martin)並最大限度地減少錯誤的“成本”。

其中一種方法是將應用程序拆分為微服務:很容易將已經存在的邏輯分解成單獨的部分。但最大的問題是為了實現一個小功能而同時對十幾個服務進行未來更改。

可擴展性

可擴展性是通過向項目中添加新人員來減少開發時間的能力。該體系結構應允許並行化開發過程,以便許多人可以同時處理該程序。

似乎這條規則是自己執行的,但實際上一切恰恰相反。甚至還有一本超級流行的書,《人月神話》,它解釋了為什麼當一個項目中加入新人時,開發時間會增加。

可擴展性

可擴展性是在不破壞系統核心結構的情況下向系統添加新功能和實體的能力。在初始階段,只將基本和最必要的功能放入系統中是有意義的。

這就是所謂的YAGNI 原則——你不會需要它,“你不會需要它”。同時,該體系結構應該允許您根據需要輕鬆地增加額外的功能。因此,最有可能的變化的引入需要最少的努力。

系統架構的靈活性和可擴展性(即能夠改變和進化)的要求是如此重要,以至於它甚至被制定為一個單獨的原則——“開放/封閉原則開閉原則是五個 SOLID 原則中的第二個:軟件實體(類、模塊、函數)應該對擴展開放,但對修改關閉

換句話說:應該可以在不重寫系統現有部分的情況下改變和擴展系統的行為。

這意味著應用程序的設計方式應該是通過編寫新代碼(擴展)來更改其行為和添加新功能,而無需更改現有代碼。

在這種情況下,新需求的出現並不需要對現有邏輯進行修改,而是主要通過擴展來實現。這個原則是“插件架構”(Plugin Architecture)的基礎。稍後將討論實現這一點的技術。

還記得 servlet 和過濾器嗎?如果實際上可以使用 servlet 實現所有相同的邏輯,為什麼還需要過濾器,甚至使用單獨的接口?

過濾器(服務 servlet)概念的發明使得將各種服務功能移動到單獨的層成為可能。並且在未來,當改變過濾器的行為時,沒有必要改變 servlets。

在過濾器發明之前,所有負責重定向請求的服務邏輯都位於 servlet 本身中。通常邏輯上的一個小變化會導致需要遍歷所有 servlet 並對所有 servlet 進行各種更改。

可測試性

如果您是 Java 後端開發人員,那麼您的服務器應用程序通常會將一組方法公開為 REST API。為了檢查你所有的方法是否按預期工作,它們需要被測試覆蓋。

一般來說,API 測試覆蓋率是一種很好的風格。它使您能夠確保您的 API 確實按照預期的方式工作。而且,更重要的是,您可以更改服務器邏輯並輕鬆檢查您是否不小心破壞了任何東西

一旦開始編寫測試,您就會意識到大多數代碼根本無法進行測試:私有方法、強耦合、靜態類和變量。

“如果代碼有效,為什麼我們需要測試?”,初學者會問。

“如果無法測試,為什麼我們需要工作代碼?”,專業人士會問。

易於測試的代碼將包含更少的錯誤並且更可靠。但是測試不只是提高代碼質量。幾乎所有的開發人員最終都得出結論,“良好的可測試性”的要求也是一種自動導致良好設計的指導力量。

引用 Ideal Architecture 一書中的一句話:“將類的“可測試性”原則作為良好類設計的“試金石”。即使你不寫一行測試代碼,在 90 年內回答這個問題% 的案例將有助於了解他的設計是如何“好”或“壞”的。

有一整套基於測試來開發程序的方法,稱為測試驅動開發(TDD)。這當然是另一個極端:先寫代碼再寫代碼。

代碼可維護性

通常,很多人都在為這個項目工作——有些人離開了,新人來了。程序員在IT公司的平均工作時間是一年半。所以如果你來到一個 5 年前的項目,那麼你的同事中只有 20% 從一開始就參與其中。

維護和開發別人編寫的程序是非常困難的。即使程序已經寫好了,也常常需要繼續維護它:修復錯誤並進行小的修正。通常這必須由沒有參與編寫的人來完成。

因此,一個好的架構應該能夠讓新人相對容易和快速地理解這個系統。該項目必須是:

  • 結構良好。
  • 不包含重複。
  • 有格式良好的代碼。
  • 最好包括文檔。
  • 有必要為程序員應用標準和熟悉的解決方案。

您可以輕鬆地在 5 分系統上對您正在處理的項目進行評分。只需為這些要求中的每一項算兩分。如果你得到 5 個或更多,那麼你很幸運。

程序員甚至有一個最少驚奇原則:系統越奇特,別人就越難理解。通常,它與用戶界面有關,但也適用於編寫代碼。