軟件架構(gòu)是任何成功軟件系統(tǒng)的基礎(chǔ),并且會影響整個系統(tǒng)生命周期中的可維護(hù)性、可擴(kuò)展性、穩(wěn)定性和安全性等方方面面。實現(xiàn)新軟件系統(tǒng)的第一步是架構(gòu)圖。
隨著軟件系統(tǒng)和 Web 應(yīng)用程序變得越來越復(fù)雜,精心設(shè)計的系統(tǒng)架構(gòu)圖對于與其他開發(fā)人員和利益相關(guān)者進(jìn)行交流變得至關(guān)重要。軟件架構(gòu)圖是一種重要的文檔實踐,可幫助您規(guī)劃和實施網(wǎng)絡(luò)中的更改、可視化戰(zhàn)略計劃并領(lǐng)先于組織的需求。
今天,我們將重點介紹如何繪制圖表、流行軟件架構(gòu)模式的一些示例,以及找到參考架構(gòu)的地方,以用作各種用例的起點。我們還將討論一個好的架構(gòu)圖應(yīng)該完成什么,以及為什么你應(yīng)該花時間來創(chuàng)建一個。
讓我們潛入水中!
我們將介紹:
- 什么是軟件架構(gòu)
- 圖表基礎(chǔ):流程圖、C4 和 UML 2.5
- 6 種軟件架構(gòu)模式
- 3 個用于構(gòu)建應(yīng)用程序的公共云平臺
- 總結(jié)和后續(xù)步驟
軟件架構(gòu)描述了系統(tǒng)在其環(huán)境、關(guān)系、設(shè)計原則等上下文中的基本概念和屬性。軟件架構(gòu)包括軟件系統(tǒng)的組織、結(jié)構(gòu)元素、行為元素,以及將這些元素組合成更大的子系統(tǒng)。軟件系統(tǒng)通常可以包含多種架構(gòu)。
“沒有考慮整體架構(gòu)或設(shè)計的編程就像只用手電筒探索洞穴:你不知道你去過哪里,你不知道你要去哪里,你也不知道到底在哪里你是。” 丹尼·索普
擁有出色的架構(gòu)為您將來如何處理性能、容錯性、可擴(kuò)展性和可靠性奠定了基礎(chǔ)。為您的軟件選擇正確的架構(gòu)將在您擴(kuò)大規(guī)模時在壓力條件下保持穩(wěn)定的性能。
即使您預(yù)計用戶數(shù)量不會增加,考慮您的計劃的大局以及如何將該愿景傳達(dá)給其他人也可以幫助您和您的團(tuán)隊根據(jù)這些決策對您整體的影響做出戰(zhàn)略決策建筑學(xué)。
為了擴(kuò)展丹尼·索普的洞穴類比,如果你的洞穴之旅出了差錯并且你正在等待救援人員找到你,那么徹底繪制洞穴系統(tǒng)會產(chǎn)生巨大的影響。
同樣,完善的軟件架構(gòu)可以幫助您的工程師快速定位和修復(fù)錯誤。
我們需要記錄軟件架構(gòu)嗎?
您是否應(yīng)該記錄您的軟件架構(gòu)取決于您正在處理的項目類型。關(guān)于記錄軟件架構(gòu)是否真的值得花時間,或者它是否會減慢一切,存在一些爭議。現(xiàn)實在中間的某個地方。
一些開發(fā)人員并不需要為每個項目設(shè)計一個映射良好的軟件架構(gòu)。如果您是單獨工作或使用像敏捷這樣專注于持續(xù)改進(jìn)的固有適應(yīng)性開發(fā)方法,則可能很難記錄每一次更改。
“不正確的文檔通常比沒有文檔更糟糕。” 伯特蘭·邁耶
在其他時候,對復(fù)雜系統(tǒng)中軟件架構(gòu)的重要部分的記錄不足可能會導(dǎo)致重大問題或?qū)е录夹g(shù)債務(wù)。作為一般規(guī)則,一旦您的項目擴(kuò)展到多人,您就應(yīng)該開始記錄產(chǎn)品的軟件架構(gòu)。
你需要記錄什么?
您必須確保核心組件和高級架構(gòu)可供每位員工使用。在許多情況下,軟件架構(gòu)及其文檔將比產(chǎn)品的最初創(chuàng)建者更持久。從事產(chǎn)品工作的人可能會改變,使用的編程語言可能會改變,但軟件架構(gòu)幾乎總是會保持不變。
這就是為什么記錄您的軟件架構(gòu)如此重要的原因。它允許從事該項目的人員查看您的產(chǎn)品如何更改和發(fā)展的記錄。
雖然您可能不想記錄每個代碼更改或架構(gòu)更改,但您肯定希望記錄重大更改,同樣重要的是,記錄進(jìn)行這些更改的原因。
好的架構(gòu)圖能完成什么?
好的軟件架構(gòu)圖是真實和清晰的來源。您希望您的圖表能夠快速向技術(shù)和非技術(shù)受眾傳達(dá)軟件系統(tǒng)的基本組成和行為。
如果做得好,高級架構(gòu)圖和詳盡的文檔可以成為傳達(dá)系統(tǒng)或應(yīng)用程序內(nèi)部狀態(tài)的有效工具。
在開始編碼之前繪制圖表和在編寫代碼之后繪制圖表也會帶來不同的好處。
- 正向設(shè)計需要在您或您的團(tuán)隊開始編碼之前創(chuàng)建圖表。這有助于幫助您的開發(fā)人員更好地可視化他們正在嘗試創(chuàng)建的系統(tǒng)。
- 后向設(shè)計涉及在編寫代碼繪制圖表。這可以幫助開發(fā)人員了解項目是如何開發(fā)的,并記錄該工作流程以供以后改進(jìn)。
“在編程領(lǐng)域,沒有什么比無證程序更卑鄙的了。” 愛德華·尤登
您還希望您的圖表盡可能不言自明,以便任何查看它的人都可以立即看到您的軟件系統(tǒng)中的關(guān)系、約束和限制,而無需詢問您的含義。
一個好的架構(gòu)圖將:
- 圖表核心組件
- 突出關(guān)鍵系統(tǒng)交互和關(guān)系
- 易于訪問和共享
- 保持一致的風(fēng)格
- 更容易識別軟件架構(gòu)中的潛在缺陷或需要改進(jìn)的領(lǐng)域
既然我們已經(jīng)談完了記錄軟件架構(gòu)如何使您受益,那么讓我們看看一些用于制作圖表的常用方法。
流程圖
流程圖是您可以制作的最基本的圖表類型之一。它們的簡單性使它們成為在開始編碼之前可視化算法或程序邏輯的有效工具。
以下是流程圖鍵的示例,其中包含圖表中使用的一些常見符號。
在技術(shù)圖表中,每個形狀通常包括以下內(nèi)容:
- 被表示的元素的名稱
- 該元素在系統(tǒng)中的作用
- 那個元素的技術(shù)
圖表的每個組件都有將其連接到其他組件并描述它們之間的交互的箭頭。
C4 型號
C4 模型是軟件系統(tǒng)的體系結(jié)構(gòu)文檔標(biāo)準(zhǔn),它將軟件系統(tǒng)分為四個級別:
- 上下文(第 1 級):上下文圖是對系統(tǒng)做什么、它解決什么問題、涉及的人員以及與之交互的任何外部系統(tǒng)的高級概念描述。這些圖表有助于提供全局概覽。
- 容器(第 2 級):容器圖更深入地描述構(gòu)成系統(tǒng)的應(yīng)用程序或服務(wù)之間的高級交互。容器可以代表 API、數(shù)據(jù)庫、文件系統(tǒng)、微服務(wù)等。
- 組件(第 3 級):組件圖查看容器內(nèi)的不同代碼體。這些圖表有助于可視化代碼庫的抽象。
- 代碼(4 級):顧名思義,代碼圖著眼于映射到代碼的架構(gòu)元素,如類、接口、對象和函數(shù)。
作為最低要求,大多數(shù)團(tuán)隊?wèi)?yīng)該為他們的軟件系統(tǒng)創(chuàng)建和維護(hù)上下文和容器圖。
如果組件圖增加了價值,則可以創(chuàng)建它們,但您需要找到一種方法來自動更新這些圖以用于長期文檔目的。
大多數(shù) IDE(或 UML 建模工具)可以按需生成代碼圖,因此這種詳細(xì)程度的文檔更容易檢索而不是維護(hù)。如果一個組件特別重要或復(fù)雜,那么手頭有 4 級圖表可能會有所幫助,但在大多數(shù)情況下,您可以等到需要這些圖表時再生成它們。
UML 2.5
統(tǒng)一建模語言 (UML) 最常用于軟件工程,以創(chuàng)建用于記錄 4 級架構(gòu)元素的圖表。
有 14 種類型的 UML 圖分為兩大類:
- 結(jié)構(gòu)圖顯示了建模系統(tǒng)中的對象。
- 行為圖顯示了這些對象如何相互交互。
在本文中,我們將主要關(guān)注 C4 模型的第 1 級和第 2 級圖,因此我們不會在此詳細(xì)介紹。
但是,如果您想生成第 4 級圖表,那么研究 UML 可能是一個不錯的起點。
示例:發(fā)票系統(tǒng)
您正在構(gòu)建一個 Web 應(yīng)用程序,數(shù)字藝術(shù)家可以使用它來管理和向客戶發(fā)送發(fā)票。這個的上下文圖會是什么樣子?
您的圖表至少應(yīng)包括:
- 數(shù)據(jù)庫
- 業(yè)務(wù)邏輯組件
- 用戶界面
首先,從您的軟件系統(tǒng)的表示開始。
接下來,您要記錄演員是誰。演員是任何將使用該軟件系統(tǒng)的人。
在這種情況下,我們的演員是:
- 數(shù)字藝術(shù)家
- 客戶
既然您知道您的參與者是誰,請記錄與軟件系統(tǒng)交互的任何外部系統(tǒng)。
如果你想更深入,你可以創(chuàng)建一個容器圖。容器圖將關(guān)注構(gòu)成特定容器的應(yīng)用程序。
6 種軟件架構(gòu)模式
有許多軟件架構(gòu)風(fēng)格,了解流行的風(fēng)格可以為您節(jié)省一些時間。這是對六種不同類型的架構(gòu)模式的基本(但希望是全面的)介紹。
1.分層(N層)架構(gòu)
分層架構(gòu)模式,也稱為 N 層架構(gòu)模式,是大多數(shù) JAVA 企業(yè)應(yīng)用程序使用的標(biāo)準(zhǔn)架構(gòu)。分層架構(gòu)風(fēng)格將組件(或應(yīng)用程序)劃分為水平的邏輯層。
每一層在系統(tǒng)中都有不同的作用。一層可能負(fù)責(zé)處理業(yè)務(wù)邏輯,而另一層負(fù)責(zé)處理表示邏輯。這展示了一個稱為關(guān)注點分離 (SoC) 的概念。層的組件將僅處理該層內(nèi)的邏輯。像這樣分離層也使測試和開發(fā)軟件更容易,因為模式本身并不太復(fù)雜。缺點是這不是最有效的使用模式,而且很難擴(kuò)大規(guī)模。
大多數(shù)分層架構(gòu)將由四個封閉層組成:
- 介紹
- 商業(yè)
- 持久性
- 數(shù)據(jù)庫
有時,業(yè)務(wù)層和持久層會合并為一個單獨的層,尤其是當(dāng)持久性邏輯(例如,SQL)包含在業(yè)務(wù)層的組件中時。較小的應(yīng)用程序可以只有三層,而更復(fù)雜的應(yīng)用程序可以包含五個或更多。
封閉層要求請求通過目標(biāo)層之前的層。例如,如果您嘗試向數(shù)據(jù)庫層發(fā)送請求,則該請求必須首先通過表示層、業(yè)務(wù)層和持久層。
但有時,讓請求通過每一層是沒有意義的。對于這種情況,您可以打開某些層,以便請求可以跳過它們并直接轉(zhuǎn)到它們下面的層。
對于大多數(shù)應(yīng)用程序來說,分層架構(gòu)模式是一種很好的通用模式,尤其是當(dāng)您不確定要使用哪種架構(gòu)模式時。
注意:層和層都是指軟件系統(tǒng)的功能劃分。但是,層是指在與其他部門分開的基礎(chǔ)架構(gòu)上運行的軟件。因此,如果所有層都在同一設(shè)備上運行,則具有多個層的應(yīng)用程序只能具有一層。2.客戶端-服務(wù)器架構(gòu)
在客戶端-服務(wù)器架構(gòu)中,有多個節(jié)點或客戶端通過網(wǎng)絡(luò)或 Inte.NET 連接與中央服務(wù)器通信。
有兩種主要類型的組件:
- 發(fā)送請求的服務(wù)請求者(又名客戶端)
- 響應(yīng)請求的服務(wù)提供商
在這種架構(gòu)中,服務(wù)器托管、管理和交付客戶端請求的大部分資源和服務(wù)。這也稱為請求-響應(yīng)消息傳遞模式。
具有客戶端-服務(wù)器架構(gòu)的應(yīng)用程序的兩個經(jīng)典示例是萬維網(wǎng)和電子郵件。
3. 事件驅(qū)動架構(gòu)
事件驅(qū)動架構(gòu)模式是具有高度適應(yīng)性的分布式異步架構(gòu)模式。這種模式最適合具有高可擴(kuò)展性的小型到大型應(yīng)用程序。由于在此模式中事件處理器組件彼此隔離,因此可以對組件進(jìn)行更改而不會影響其他組件的性能。
這種模式有兩種主要的拓?fù)洌?strong>中介和代理拓?fù)洹?/p>
中介拓?fù)溆兴姆N主要類型的組件:
- 事件隊列
- 事件中介
- 事件通道
- 事件處理器
當(dāng)事件具有多個步驟,需要通過中央調(diào)解器進(jìn)行某種程度的協(xié)調(diào)以進(jìn)行處理時,使用調(diào)解器拓?fù)洹?/strong>
當(dāng)用戶將初始事件發(fā)送到事件隊列時,初始事件將被定向到事件中介。
接收到初始事件提示事件中介者發(fā)布和發(fā)送處理事件到事件通道,告訴他們開始執(zhí)行每個流程步驟。從事件通道接收處理事件的事件處理器包含執(zhí)行處理初始事件所需的所有步驟的業(yè)務(wù)邏輯組件。
一般來說,事件處理器組件應(yīng)該只執(zhí)行單個業(yè)務(wù)任務(wù),而不依賴于其他事件處理器。這是因為您希望您的事件處理器能夠與其他事件處理器同時運行步驟。
代理拓?fù)?/strong>用于事件不需要中央調(diào)解器來分發(fā)或協(xié)調(diào)事件的流程。
代理拓?fù)溆袃煞N主要類型的組件:
- 經(jīng)紀(jì)人
- 事件處理器
代理組件包含此事件流的所有事件通道。這些事件通道可以是消息隊列、消息主題或兩者的組合。
在代理拓?fù)渲校录幚砥鹘M件直接接收事件并負(fù)責(zé)處理和發(fā)布新事件以指示事件已被處理。
事件不斷地流經(jīng)處理器組件鏈,直到不再為初始事件發(fā)布事件。
這種進(jìn)程分布允許事件驅(qū)動架構(gòu)以最少的資源消耗運行大量并發(fā)連接。
4.微內(nèi)核架構(gòu)
微內(nèi)核架構(gòu)(也稱為插件架構(gòu))通常用于實現(xiàn)可作為第三方產(chǎn)品下載的應(yīng)用程序。這種架構(gòu)也常見于內(nèi)部業(yè)務(wù)應(yīng)用程序中。
這種架構(gòu)的一個有趣之處在于,您實際上可以將其嵌入到其他模式中,例如分層架構(gòu)。
在典型的微內(nèi)核架構(gòu)中有兩種架構(gòu)組件:核心系統(tǒng)和插件模塊。
核心系統(tǒng)包含使軟件系統(tǒng)運行所需的最小業(yè)務(wù)邏輯。您可以通過連接插件組件來擴(kuò)展軟件系統(tǒng)的功能以添加更多功能。
這有點像為您的汽車添加冷空氣進(jìn)氣口以提高其扭矩和馬力。
可以使用開放服務(wù)網(wǎng)關(guān)倡議 (OSGi)、消息傳遞、Web 服務(wù)或?qū)ο髮嵗瘉磉B接插件組件。實施方法由您決定。
注意:插件組件是獨立的組件,旨在擴(kuò)展或增強(qiáng)核心系統(tǒng)的功能,不應(yīng)與其他組件形成依賴關(guān)系。5.微服務(wù)架構(gòu)
微服務(wù)架構(gòu)是目前最流行的軟件趨勢之一,其中一個原因可以歸因于開發(fā)的易于擴(kuò)展性。當(dāng)微服務(wù)無法再維護(hù)時,可以重寫或替換它們。
術(shù)語“微服務(wù)”沒有普遍接受的定義。在本文中,我們將微服務(wù)定義為可獨立部署的模塊。
微服務(wù)架構(gòu)由具有小型代碼庫的小型、獨立、自包含服務(wù)組組成。與使用分層架構(gòu)模式的單體應(yīng)用程序不同,保持小的、獨立的代碼庫可以最大限度地減少依賴項的數(shù)量。
微服務(wù)架構(gòu)的每個組件都部署為一個單獨的單元。單獨部署單元簡化了交付管道并使部署速度更快。開發(fā)團(tuán)隊可以輕松地建立具有較小單元的持續(xù)交付管道。測試也變得更容易,因為您只需要測試單個微服務(wù)的功能。
注意:微服務(wù)架構(gòu)僅在部署自動化時才有效,因為微服務(wù)顯著增加了可部署單元的數(shù)量。
微服務(wù)架構(gòu)的另一個關(guān)鍵概念是服務(wù)組件。服務(wù)組件的復(fù)雜程度可以從單個模塊到應(yīng)用程序的大部分。微服務(wù)架構(gòu)被認(rèn)為是一種分布式模式,因為它們的服務(wù)組件彼此完全解耦。
微服務(wù)還有助于持續(xù)交付,這有助于使軟件開發(fā)更加靈活。
亞馬遜、Netflix 和 Spotify 等大公司都在實施這種架構(gòu)。
6. 云原生架構(gòu)
當(dāng)您考慮典型的 Web 應(yīng)用程序時,它們中的大多數(shù)通常以相同的方式處理來自客戶端的請求。客戶端從 Web 瀏覽器發(fā)送請求,該請求被發(fā)送到 Web 服務(wù)器,然后是應(yīng)用程序服務(wù)器,最后是數(shù)據(jù)庫服務(wù)器。當(dāng)這種數(shù)據(jù)流處理大量并發(fā)運行的請求時,您通常會遇到瓶頸問題。這就是云原生架構(gòu)模式的用武之地。云原生模式旨在通過刪除中央數(shù)據(jù)庫并使用復(fù)制的內(nèi)存數(shù)據(jù)網(wǎng)格來最大限度地減少可伸縮性和并發(fā)相關(guān)的問題。
云原生架構(gòu)主要用于分布式計算系統(tǒng),其中組件之間的交互通過一個或多個共享空間進(jìn)行調(diào)解。
在這個共享空間中,組件交換元組和條目。這給我們帶來了元組空間的概念,或分布式共享內(nèi)存的概念。
元組空間提供可以同時訪問的元組存儲庫。應(yīng)用程序數(shù)據(jù)保存在內(nèi)存中,并在活動處理單元之間復(fù)制。
此架構(gòu)模式中的兩種主要組件類型是:
- 處理單元
- 虛擬中間件
處理單元通常包含:
- 應(yīng)用模塊
- 內(nèi)存數(shù)據(jù)網(wǎng)格
- 用于故障轉(zhuǎn)移的可選異步持久存儲
- 數(shù)據(jù)復(fù)制引擎
數(shù)據(jù)復(fù)制引擎是虛擬中間件用來將一個處理單元中所做的數(shù)據(jù)更改復(fù)制到所有其他活動處理單元的工具。
虛擬化中間件管理請求、會話、數(shù)據(jù)復(fù)制、分布式請求處理和流程單元部署。
虛擬化中間件將包含四個主要組件:
- 消息傳遞網(wǎng)格
- 數(shù)據(jù)網(wǎng)格
- 處理網(wǎng)格
- 部署經(jīng)理
消息傳遞網(wǎng)格是管理輸入請求和會話信息的組件。
數(shù)據(jù)網(wǎng)格是虛擬中間件中最重要的組件,它與每個處理單元中的數(shù)據(jù)復(fù)制引擎進(jìn)行交互。
部署管理器是根據(jù)負(fù)載條件管理處理單元的啟動和關(guān)閉的組件。當(dāng)用戶負(fù)載增加時,它將啟動新的處理單元,當(dāng)用戶負(fù)載減少時,它將關(guān)閉處理單元。這種對不斷變化的環(huán)境的動態(tài)響應(yīng)允許基于空間的應(yīng)用程序輕松擴(kuò)展。
處理網(wǎng)格是一個可選組件,當(dāng)多個處理單元處理應(yīng)用程序的一部分時,它管理分布式請求處理。
這種類型的軟件架構(gòu)最適合社交網(wǎng)站或任何需要處理大量流量峰值的系統(tǒng)。
Software architecture diagramming and patterns
A software’s architecture is the foundation for any successful software system and will influence everything from maintainability, scalability, stability, and security throughout that system’s lifecycle. The first step toward implementing a new software system is the architecture diagram.
As software systems and web Applications have become increasingly complex, well-designed system architecture diagrams have become critical for communicating with other developers and stakeholders. Software architecture diagrams are an important documentation practice that will help you plan for and implement changes in your network, visualize strategic initiatives, and stay ahead of your organization’s needs.
Today, we’ll focus on how to diagram, some examples of popular Software architecture patterns, and places to find reference architectures to use as a starting point for various use cases. We’ll also go over what a good architectural diagram should accomplish and why you should take the time to create one.
Let’s dive right in!
We’ll cover:
What is software architecture
Diagramming basics: Flowcharts, C4, and UML 2.5
6 software architecture patterns
What is software architecture?
Software architecture describes the fundamental concepts and properties of a system within the context of its environment, relationships, principles of design, and more. Software architecture encompasses the organization of a software system, structural elements, behavioral elements, and the composition of those elements into larger subsystems. Software systems can often contain multiple architectures.
“Programming without an overall architecture or design in mind is like exploring a cave with only a flashlight: You don’t know where you’ve been, you don’t know where you’re going, and you don’t know quite where you are.”
Danny Thorpe
Having a great architecture lays the groundwork for how you will deal with performance, fault tolerance, scalability, and reliability in the future. Choosing the right architecture for your software will lead to stable performance under stressful conditions as you scale up.
Even if you don’t anticipate an increase in users, thinking about the big picture for your program and how you can communicate that vision to others can help you and your team makes strategic decisions based on the impact that those decisions will have on your overall architecture.
To extend Danny Thorpe’s cave analogy, having a cave system thoroughly mapped out can make a huge difference if, say, your spelunking trip has gone awry and you’re waiting for rescuers to find you.
Similarly, thorough software architecture can help your engineers quickly locate and fix bugs.
Do we need to document software architectures?
Whether you should document your software architecture depends on the type of project you’re working on. There’s some controversy on whether documenting software architectures is actually worth the time or if it slows everything down. The reality is somewhere in the middle.
Some developers don’t need a well-mapped software architecture for every project. If you’re working solo or using inherently adaptable development methodologies that focus on continuous improvements like Agile, it can be difficult to document every change.
“Incorrect documentation is often worse than no documentation.”
Bertrand Meyer
At other times, under-documenting vital parts of software architecture in a complex system can lead to significant issues or contribute to technical debt. As a general rule, as soon as your project expands to include more than one person, you should start documenting a product’s software architecture.
What do you need to document?
You must ensure that the core components and high-level architecture are available for every employee. In many cases, the software architecture and its documentation will outlast the initial creators of the product. The people working on the product may change, and the programming language used may change, but the software architecture will almost always remain.
That’s why documenting your software architecture is so important. It allows people working on the project to view a record of how your product changes and evolves.
While you probably don’t want to document every code change or architectural change, you will certainly want to document significant changes and, equally important, why those changes are made.
What do good architectural diagrams accomplish?
Good software architecture diagrams are sources of truth and clarity. You want your diagram to quickly convey a software system’s essential composition and behaviors to both technical and non-technical audiences.
High-level architectural diagrams and thorough documentation can be effective tools for communicating the internal state of a system or application when done well.
Diagramming before you start coding and diagramming after your code has been written will also confer different benefits.
Forward design entails creating your diagrams before you or your team starts coding. This has the benefit of helping your developers better visualize the system they’re trying to create.
Backward design involves diagramming after the code has already been written. This can help developers see how the project developed and document that workflow to improve later.
“There is nothing in the programming field more despicable than an undocumented program.”
Edward Yourdon
You also want your diagram to be as self-explanatory as possible so that anyone looking at it can immediately see the relationships, constraints, and limitations in your software system without needing to ask you what something means.
A good architectural diagram will:
Diagram core components
Highlight critical system interactions and relationships
Be easy to access and share
Maintain a consistent style
Make it easier to identify potential flaws or areas for improvement in the software architecture
Diagramming basics: Flowcharts, C4, and UML 2.5
Now that we’re done talking about how documenting software architecture can benefit you, let’s look at some common methods used to make diagrams.
Flowcharts
Flowcharts are one of the most basic types of diagrams you can make. Their simplicity makes them an effective tool for visualizing the logic of an algorithm or program before you start coding.
Here is an example of a flowchart key containing some common symbols used in diagrams.
In a technical diagram, each shape will typically include the following:
The name of the element being represented
The role of that element in the system
The technology of that element
Each component of a diagram will have arrows connecting it to other components and describing the interaction between them.
The C4 model
The C4 model is an architectural documentation standard for software systems that breaks a software system down into four levels:
Context (level 1): Context diagrams are high-level, conceptual descriptions of what your system does, what problem it solves, the people involved, and any external systems that interact with it. These diagrams help provide a big picture overview.
Containers (level 2): Container diagrams go one level deeper to describe high-level interactions between the applications or services that make up your system. Containers can represent APIs, databases, file systems, microservices, etc.
Components (level 3): Component diagrams look at the different code bodies within a container. These diagrams help visualize abstractions of your codebase.
Code (level 4): As the name suggests, code diagrams look at architectural elements mapped to code, like classes, interfaces, objects, and functions.
As a bare minimum, most teams should create and maintain context and container diagrams for their software system.
Component diagrams can be created if they add value, but you will want to find a way to automate updates to these diagrams for long-term documentation purposes.
Most IDEs (or UML modeling tools) can generate code diagrams on-demand, so documentation at this level of detail is more easily retrieved than maintained. If a component is particularly important or complex, then having level 4 diagrams on hand can be helpful, but for the most part, you can wait until you need these diagrams to generate them.
UML 2.5
Unified Modeling Language (UML) is most commonly used in software engineering to create diagrams for documenting level 4 architectural elements.
There are 14 types of UML diagrams falling into two main categories:
Structural diagrams show what objects are within a modeled system.
Behavioral diagrams show how those objects interact with each other.
For this article, we’ll be focusing primarily on levels 1 and 2 diagrams of the C4 model, so we won’t get into too much detail here.
However, if you want to generate level 4 diagrams, looking into UML can be a solid place to start.
Example: Invoicing system
You are building a web application that digital artists can use to manage and send invoices to clients. What would a context diagram for this look like?
At a minimum, your diagram should include the:
Database
Business logic component
UI
First, start with a representation of your software system.
Next, you want to document who the actors are. Actors are anyone who will be using the software system.
In this scenario, our actors are:
Digital artists
Clients
Now that you know who your actors are, document any external systems interacting with the software system.
If you wanted to go a level deeper, you could create a container diagram. A container diagram would focus on the applications that make up a specific container.
6 software architecture patterns
There are many software architecture styles out there, and being aware of the popular ones can save you some time. Here is a basic (but hopefully comprehensive) look at six different types of architectural patterns.
1. Layered (N-tier) architecture
The layered architecture pattern, also known as the N-tier architecture pattern, is the standard architecture used for most Java Enterprise applications. A layered architecture style divides components (or applications) into horizontal, logical layers.
Each layer has a distinct role within the system. One layer may be responsible for handling business logic, while another is responsible for handling presentation logic. This demonstrates a concept known as the separation of concerns (SoC). Components of a layer will only deal with logic within that layer. Separating layers like this also makes testing and developing software easier as the pattern itself isn’t too complex. The downside is that this isn’t the most efficient pattern to use and can be difficult to scale up.
Most layered architectures will consist of four closed layers:
Presentation
Business
Persistence
Database
Occasionally, the business layer and persistence layer are combined into a single layer, especially when the persistence logic (e.g., SQL) is contained within components in the business layer. Smaller applications can have as few as three layers, and more complex applications can contain five or more.
Closed layers require requests to go through layers that precede the target layer. For example, if you are trying to send a request to the database layer, that request must first travel through the presentation, business, and persistence layers.
But sometimes, it doesn’t make sense to have a request go through every layer. For situations like this, you can open certain layers so that requests can skip over them and go straight to the layer below them.
The layered architecture pattern is a great general-purpose pattern for most applications, especially when you’re unsure what kind of architecture pattern to use.
Note: Layers and tiers both refer to functional divisions of a software system. However, a tier refers to software running on infrastructure separated from the other divisions. So, an application with multiple layers could only have one tier if all layers are running on the same device.
2. Client-server architecture
In a client-server architecture, there are multiple nodes or clients connected over a network or internet connection who communicate with a central server.
There are two main types of components:
Service requesters (aka clients) that send requests
Service providers that respond to requests
In this architecture, the server hosts, manages and delivers most of the resources and services a client requests. This is also known as a request-response messaging pattern.
A couple of classic examples of applications with a client-server architecture are the World Wide Web and email.
3. Event-driven architecture
Event-driven architecture patterns are distributed asynchronous architecture patterns that are highly adaptable. This pattern is best suited for small to large applications with high scalability. Since event-processor components are isolated from each other in this pattern, changes to components can be made without impacting the performance of other components.
There are two main topologies to this pattern: the mediator and the broker topologies.
Mediator topologies have four main types of components:
Event queues
Event mediators
Event channels
Event processors
Mediator topologies are used when an event has multiple steps that require some level of coordination through a central mediator to be processed.
When a user sends the initial event to an event queue, the initial event is then directed to the event mediator.
Receiving the initial event prompts the event mediator to publish and send processing events to event channels, telling them to start executing each process step. The event processors receiving the processing events from the event channels contain business logic components that execute all of the steps required to process the initial event.
In general, event-processor components should only perform a single business task without relying on other event processors. This is because you want your event processors to be able to run steps concurrently with other event processors.
Broker topologies are used for process flows where an event does not need a central mediator to distribute or coordinate events.
Broker topologies have two main types of components:
Brokers
Event processors
The broker component contains all of the event channels for this event flow. These event channels can be message queues, message topics, or a combination of both.
In the broker topology, event-processor components receive events directly and are responsible for processing and publishing new events to indicate that an event has been processed.
Events continuously flow through a chain of processor components until no more events are being published for the initial event.
This distribution of processes allows event-driven architectures to run a large number of concurrent connections with minimal resource consumption.
4. Microkernel architecture
Microkernel architectures (also known as plug-in architectures) are typically used to implement applications that can be downloaded as a third-party product. This architecture is also commonly found in internal business applications.
One fun thing about this architecture is that you can actually embed it within other patterns, like layered architectures.
There are two types of architectural components in your typical microkernel architecture: a core system and plug-in modules.
The core system contains the minimum business logic needed to make the software system operational. You can extend the software system’s functionality by connecting plug-in components to add more features.
It’s kind of like adding a cold-air intake to your car to boost its torque and horsepower.
Plug-in components can be connected using an open service gateway initiative (OSGi), messaging, web services, or object instantiation. The method of implementation is up to you.
Note: Plug-in components are independent components meant to extend or enhance the core system’s functionality and should not form dependencies with other components.
5. Microservices architecture
Microservices architectures are one of the most popular software trends at the moment, and one reason for this can be attributed to the easy scalability of development. When microservices can no longer be maintained, they can be rewritten or replaced.
There’s no universally accepted definition for the term “microservice”. We will define a microservice as an independently deployable module for this article.
A microservices architecture consists of groups of small, independent, self-contained services with small code bases. Unlike with a monolithic application using a layered architecture pattern, keeping small, separate code bases can minimize the number of dependencies.
Each component of a microservices architecture is deployed as a separate unit. Separately deploying units streamlines the delivery pipeline and makes deployment much faster. Development teams can easily build up continuous delivery pipelines with smaller units. Testing also becomes easier because you only need to test the features of an individual microservice.
Note: Microservices architectures are only effective when deployment is automated because microservices significantly increase the number of deployable units.
Another key concept of the microservices architecture is the service component. Service components can range in complexity from single modules to large portions of an application. Microservices architectures are considered a distributed pattern because their service components are fully decoupled from one another.
Microservices also facilitate continuous delivery, which helps make software development more flexible.
Major companies like Amazon, Netflix, and Spotify can be found implementing this architecture.
6. Cloud-native architecture
When you think about typical web applications, most of them typically process requests from clients in the same way. A client sends a request from the web browser, which is sent to the web server, then an application server, and finally, the database server. When this kind of data flow deals with a high volume of concurrently running requests, you typically end up with bottleneck issues. This is where cloud-native architecture patterns come in. Cloud-native patterns are designed to minimize scalability- and concurrency-related issues by removing the central database and using replicated, in-memory data grids instead.
The cloud-native architecture is primarily used for distributed computing systems where the interactions between components are mediated through one or more shared spaces.
In this shared space, the components exchange tuples and entries. This brings us to the concept of tuple spaces, or the idea of distributed shared memory.
Tuple spaces provide a repository of tuples that can be accessed concurrently. Application data is kept in memory and replicated across active processing units.
The two main types of components within this architecture pattern are:
Processing units
Virtual middleware
Processing units will typically contain:
Application modules
An in-memory data grid
Optional asynchronous persistence store for failover
A data replication engine
The data replication engine is what the virtual middleware uses to replicate data changes made in one processing unit across all other active processing units.
The virtualized middleware manages requests, sessions, data replication, distributed request processing, and process-unit deployment.
The virtualized middleware will contain four main components:
The messaging grid
The data grid
The processing grid
The deployment manager
The messaging grid is the component that manages input requests and session information.
The data grid is the most important component in the virtual middleware and interacts with the data replication engines in each processing unit.
The deployment manager is the component that manages the startup and shutdown of processing units based on load conditions. It will start up new processing units when user loads increase and shut down processing units when user loads decrease. This dynamic response to changing environments allows space-based applications to scale up easily.
The processing grid is an optional component that manages distributed request processing when multiple processing units handle a portion of the application.
This type of software architecture is best for social networking sites or any system that needs to handle massive spikes in traffic.