工程師每天都在研究的軟件架構(gòu)是什么背镇?

在某些時(shí)候,工程師必須繪制一些方框和箭頭來(lái)描述軟件系統(tǒng)的頂層設(shè)計(jì)泽裳。但是瞒斩,這些方框和箭頭叫什么?我們經(jīng)常使用諸如微服務(wù)涮总,實(shí)體胸囱,REST 或事件驅(qū)動(dòng)之類(lèi)的術(shù)語(yǔ),這些又是什么瀑梗?

作為研究論文的一部分烹笔,我一直在閱讀有關(guān)軟件體系結(jié)構(gòu)概念和定義的知識(shí),并且在整篇文章中抛丽,我將解釋其中的一些概念谤职,這些概念適用于我在研究生期間也一直在從事的項(xiàng)目:JSON- RPC Playground 控制臺(tái)。

軟件架構(gòu)是什么亿鲜?

我將使用 Roy Fielding(HTTP 規(guī)范的主要作者之一和 REST 風(fēng)格的創(chuàng)建者)在其博士學(xué)位論文中給出的定義(如果您對(duì) Software Architecture 感興趣允蜈,我推薦您看看這篇論文)。

軟件體系結(jié)構(gòu)是軟件系統(tǒng)在其操作的某個(gè)階段的運(yùn)行時(shí)元素的抽象蒿柳。一個(gè)系統(tǒng)可能由許多抽象級(jí)別和許多操作組成饶套,每個(gè)階段都有自己的軟件體系結(jié)構(gòu)。

架構(gòu)是抽象的

在描述體系結(jié)構(gòu)時(shí)垒探,可以對(duì)實(shí)現(xiàn)細(xì)節(jié)進(jìn)行抽象妓蛮,以簡(jiǎn)化設(shè)計(jì)。如用 Elixir 或 Java 編寫(xiě)身份驗(yàn)證服務(wù)有關(guān)系嗎圾叼,顯然這不是在架構(gòu)層面要考慮的事情蛤克?還是它在系統(tǒng)中扮演的角色 - 驗(yàn)證用戶(hù) - 我們應(yīng)該關(guān)注什么?

架構(gòu)與運(yùn)行時(shí)有關(guān)

源代碼結(jié)構(gòu)不是系統(tǒng)的體系結(jié)構(gòu)夷蚊。當(dāng)系統(tǒng)處于活動(dòng)狀態(tài)時(shí)构挤,不同的應(yīng)用程序可以共享公共庫(kù)或模塊,但彼此之間完全斷開(kāi)連接撬码,這個(gè)是低耦合的設(shè)計(jì)儿倒。我們專(zhuān)注于處理數(shù)據(jù)以及如何移動(dòng)數(shù)據(jù)版保。軟件架構(gòu)一般用高內(nèi)聚呜笑、低耦合方式構(gòu)建夫否。

架構(gòu)專(zhuān)注于特定的階段

并非每個(gè)組件都會(huì)始終發(fā)揮作用或成為各個(gè)流程的一部分。系統(tǒng)關(guān)閉時(shí)涉及的組件及其配置可能與系統(tǒng)正常操作模式中涉及的組件及其配置完全不同叫胁。

架構(gòu)是嵌套的

在抽象元素實(shí)現(xiàn)時(shí)凰慈,我們將忽略與當(dāng)前架構(gòu)無(wú)關(guān)的細(xì)節(jié)。如果我們將重點(diǎn)轉(zhuǎn)移到更深層次驼鹅,則將出現(xiàn)具有其自身的元素和配置集的新體系結(jié)構(gòu)微谓。我們將找到許多嵌套的體系結(jié)構(gòu),直到元素足夠簡(jiǎn)單以至于無(wú)法分解為止输钩,實(shí)現(xiàn)原子性構(gòu)建豺型。

一系列決策的結(jié)果是創(chuàng)建了一個(gè)軟件體系結(jié)構(gòu),每個(gè)決策都帶來(lái)了一組屬性和約束买乃。無(wú)論它們?cè)趫D表中是明確指出的姻氨,還是僅存在于架構(gòu)師和開(kāi)發(fā)人員的思想中,對(duì)于這些決定和約束應(yīng)該都有一種理解或意圖剪验。隨著系統(tǒng)的發(fā)展肴焊,這些最初的決定很可能與架構(gòu)的實(shí)際情況不符。如果這些差異是不希望的或偶然的功戚,那么我們說(shuō)該體系結(jié)構(gòu)已被侵蝕娶眷,造成了體系結(jié)構(gòu)的“技術(shù)負(fù)債”。

案例研究:JSON-RPC 控制臺(tái)

我們的客戶(hù)平臺(tái)之一是由數(shù)十個(gè) JVM 微服務(wù)組成啸臀,它們使用 JSON-RPC 2.0 協(xié)議相互通信届宠。每個(gè)服務(wù)使用一組 Java 接口聲明其 RPC API,這些 Java 接口作為“ Service-API”庫(kù)(JAR)發(fā)布在公共存儲(chǔ)庫(kù)中乘粒。想要與服務(wù)進(jìn)行交互的客戶(hù)端只需將其 API JAR 聲明為項(xiàng)目依賴(lài)項(xiàng)即可席揽。平臺(tái)庫(kù)將生成實(shí)現(xiàn)此類(lèi)接口的對(duì)象,并通過(guò)依賴(lài)注入提供實(shí)現(xiàn)代碼類(lèi)谓厘。從代碼角度來(lái)看幌羞,您只是在調(diào)用常規(guī)方法,但是在后臺(tái)竟稳,平臺(tái)庫(kù)正在執(zhí)行 RPC 調(diào)用并為您處理所有涉及的管道属桦。這在編寫(xiě)代碼時(shí)極大地提高了工作效率!

但是他爸,要手動(dòng)測(cè)試所有這些 RPC 方法(例如聂宾,使用諸如 Postman 或 curl 的工具),就必須找到正確的代碼庫(kù)诊笤,手動(dòng)檢查服務(wù)接口系谐,其方法和參數(shù)(可能具有許多嵌套對(duì)象級(jí)別) ),然后手動(dòng)構(gòu)建所需的 JSON payout 以執(zhí)行 API 調(diào)用。一般而言纪他,API 文檔有幫助鄙煤,但是很難保持最新,這是一個(gè)問(wèn)題茶袒。

這里梯刚,我創(chuàng)建一個(gè) GUI 應(yīng)用程序,該應(yīng)用程序會(huì)自動(dòng)生成可輕松填充的表單薪寓,以調(diào)用服務(wù)公開(kāi)的任何 RPC 方法亡资。這些表單是通過(guò)與 JSON-RPC 2.0 兼容的服務(wù)描述文件生成的,該文件是通過(guò)分析 Service-API JAR 庫(kù)創(chuàng)建的向叉。通過(guò)使用與生產(chǎn)中運(yùn)行的實(shí)際代碼相同的源锥腻,可以確保它們保持最新。

工程師每天都在研究的軟件架構(gòu)是什么母谎?

架構(gòu)元素

構(gòu)架系統(tǒng)意味著要做出一系列決定旷太,這些決定可以塑造構(gòu)成系統(tǒng)的不同元素(組件嫉柴,連接器和數(shù)據(jù))的配置暇藏。

組件(Components)

組件是軟件指令和內(nèi)部狀態(tài)的抽象單元浑吟,它通過(guò)接口提供轉(zhuǎn)換或執(zhí)行數(shù)據(jù)計(jì)算迄委。組件是由它們向其他組件提供的服務(wù)定義的零酪,而不是由它們的界面后面的實(shí)現(xiàn)定義的匀们。如果其他組件無(wú)法識(shí)別某些行為谱秽,則該行為不是體系結(jié)構(gòu)的一部分暇赤。

示例

  • RPC 控制臺(tái):將服務(wù)描述轉(zhuǎn)換為一組表單冗栗,捕獲用戶(hù)輸入演顾,執(zhí)行 RPC 調(diào)用并顯示其結(jié)果。
  • RPC 服務(wù)器:接收 RPC 請(qǐng)求隅居,對(duì)其進(jìn)行計(jì)算钠至,然后返回結(jié)果。
  • 分析器:將 Service-API JAR 轉(zhuǎn)換為服務(wù)描述胎源。
  • JAR 存儲(chǔ)庫(kù):存儲(chǔ)并提供 Service-API JAR棉钧。
  • 服務(wù)說(shuō)明存儲(chǔ)庫(kù):存儲(chǔ)并提供服務(wù)說(shuō)明。

請(qǐng)注意涕蚤,就此體系結(jié)構(gòu)的觀(guān)點(diǎn)而言宪卿,在定義 RPC Server 組件時(shí),我們對(duì) RPC Server 提供的特定功能不感興趣万栅,因?yàn)樗c其余組件無(wú)關(guān)佑钾。我們甚至將這個(gè)組件的許多不同實(shí)例均等地分組,即使實(shí)際上它們?cè)诠δ苌蠒?huì)有很大不同烦粒。如休溶,一個(gè)可能是 Users 服務(wù),而另一個(gè)可能是 Books 服務(wù)。

連接器(Connectors)

連接器可實(shí)現(xiàn)不同組件之間的通信和數(shù)據(jù)傳輸兽掰。他們不轉(zhuǎn)換數(shù)據(jù)芭碍,而是通過(guò)界面在不同組件之間對(duì)數(shù)據(jù)進(jìn)行移動(dòng)。但是在內(nèi)部禾进,當(dāng)查看一個(gè)特定連接器的體系結(jié)構(gòu)時(shí)豁跑,我們可能會(huì)發(fā)現(xiàn)它實(shí)際上是由一個(gè)子系統(tǒng)組成的廉涕,這些子系統(tǒng)接收數(shù)據(jù)泻云,將其轉(zhuǎn)換為更好的格式以進(jìn)行傳輸,將其發(fā)送到另一端狐蜕,然后反轉(zhuǎn)轉(zhuǎn)換宠纯,然后再傳遞給系統(tǒng)的其余部分。由于這些轉(zhuǎn)換對(duì)系統(tǒng)的其余部分不可見(jiàn)层释,因此我們可以將它們抽象化為更高的層次婆瓜。

在示例中:

  • RPC 客戶(hù)端:開(kāi)始 RPC 調(diào)用。
  • RPC 服務(wù)器:接收 RPC 請(qǐng)求并返回 RPC 響應(yīng)贡羔。
  • HTTP 客戶(hù)端:?jiǎn)?dòng) HTTP 連接以獲取服務(wù)描述廉白。
  • AWS 庫(kù):將服務(wù)描述從分析器傳輸?shù)椒?wù)描述存儲(chǔ)庫(kù)。
  • Gradle 庫(kù):將 Service-API JAR 依賴(lài)項(xiàng)從 JAR 存儲(chǔ)庫(kù)傳輸?shù)椒治銎鳌?/li>

對(duì)于 AWS Library 和 Gradle Library 而言乖寒,我們不直接負(fù)責(zé)這些數(shù)據(jù)傳輸?shù)姆绞胶秕濉H缓螅覀兛梢允褂眠B接器的視圖楣嘁,而忽略其實(shí)現(xiàn)的細(xì)節(jié)磅轻。

數(shù)據(jù) (data)

許多軟件體系結(jié)構(gòu)定義沒(méi)有將數(shù)據(jù)作為核心概念提及,我認(rèn)為這并不完整逐虚。數(shù)據(jù)是系統(tǒng)存在的原因聋溜,有時(shí)甚至是驅(qū)動(dòng)系統(tǒng)配置的主要因素。數(shù)據(jù)定義為通過(guò)連接器從一個(gè)組件傳輸?shù)搅硪唤M件的信息叭爱。

在示例中:

  • 服務(wù)描述:以 JSON-RPC 2.0 兼容結(jié)構(gòu)描述服務(wù)公開(kāi)的可用 RPC 方法撮躁。它包括服務(wù)器 URL,方法名稱(chēng)买雾,參數(shù)和類(lèi)型之類(lèi)的信息馒胆。
  • RPC 請(qǐng)求:包括 RPC 方法名稱(chēng)及其參數(shù)。
  • RPC 結(jié)果:RPC 調(diào)用執(zhí)行的結(jié)果凝果。
  • Service-API JAR:包含 RPC 服務(wù)的 Java 接口的 JAR 文件祝迂。

架構(gòu)風(fēng)格

架構(gòu)風(fēng)格是架構(gòu)設(shè)計(jì)決策的命名集合,當(dāng)在特定上下文中應(yīng)用時(shí)對(duì)應(yīng)不同的系統(tǒng)元素器净,它們的配置以及它們之間的關(guān)聯(lián)方式施加約束型雳,進(jìn)而生成具有眾所周知架構(gòu)解決方案。

樣式是一種用于對(duì)體系結(jié)構(gòu)進(jìn)行分類(lèi)并定義其共同特征的機(jī)制。每種樣式都為組件的交互提供了抽象纠俭,通過(guò)忽略架構(gòu)其余部分的細(xì)節(jié)來(lái)捕獲交互模式的本質(zhì)沿量。樣式可以?xún)H關(guān)注體系結(jié)構(gòu)的某些方面,甚至可以將它們組合以生成更復(fù)雜的樣式或混合樣式冤荆。

客戶(hù)端 - 服務(wù)器朴则,微服務(wù),Monolithic 甚至是 REST 都是不同的體系結(jié)構(gòu)樣式钓简,您很可能已將其應(yīng)用于數(shù)十種異構(gòu)系統(tǒng)乌妒。

創(chuàng)造自己的風(fēng)格

如果您熟悉諸如 Swagger 的 REST API 之類(lèi)的工具,您可能會(huì)注意到我的 JSON-RPC 項(xiàng)目與之相似外邓。雖然我的控制臺(tái)使用了針對(duì)基于 JSON-RPC 的服務(wù)量身定制的服務(wù)描述作為輸入撤蚊,但是 REST API 具有OpenAPI 標(biāo)準(zhǔn)。從服務(wù)的源代碼生成規(guī)范格式是一種強(qiáng)大的模式损话,可用于創(chuàng)建許多不同的使用者工具:文檔導(dǎo)航器侦啸,客戶(hù)端代碼生成器,模擬服務(wù)器等丧枪。

讓我們嘗試為該工具系列定義通用的體系結(jié)構(gòu)樣式光涂,該樣式可以應(yīng)用于任何其他協(xié)議以獲得相同的好處:我將其稱(chēng)為“服務(wù)描述”樣式。

服務(wù)風(fēng)格描述

讓我們開(kāi)始定義架構(gòu)的不同元素

數(shù)據(jù)元素:

  • 目標(biāo)源代碼:目標(biāo)服務(wù)接口的源代碼拧烦。
  • 服務(wù)描述:特定于協(xié)議的格式忘闻,遵循協(xié)議標(biāo)準(zhǔn),可以描述任何目標(biāo)服務(wù)的接口屎篱。

組件:

  • 生成器:自動(dòng)從目標(biāo)源代碼創(chuàng)建服務(wù)描述服赎,并將其發(fā)布到提供者。
  • 存儲(chǔ)庫(kù):存儲(chǔ)并提供服務(wù)說(shuō)明交播。
  • 客戶(hù)端:使用存儲(chǔ)庫(kù)中的服務(wù)描述重虑,并將其用作提供針對(duì)目標(biāo)服務(wù)動(dòng)態(tài)定制功能的唯一來(lái)源。

連接器 (connectors):

  • 生成器 -> 存儲(chǔ)庫(kù):將服務(wù)描述從生成器傳輸?shù)酱鎯?chǔ)庫(kù)秦士。
  • 存儲(chǔ)庫(kù) -> 客戶(hù)端:將服務(wù)描述從存儲(chǔ)庫(kù)傳輸?shù)娇蛻?hù)端缺厉。

必須從源代碼創(chuàng)建服務(wù)描述∷硗粒客戶(hù)端需要始終保持最新的服務(wù)說(shuō)明才能正常運(yùn)行提针,因?yàn)槌欠?wù)說(shuō)明中包含客戶(hù)信息,否則他們對(duì)目標(biāo)服務(wù)的具體情況一無(wú)所知曹傀。主要來(lái)源是代碼辐脖,如果流程不是自動(dòng)化的,則很可能會(huì)出現(xiàn)服務(wù)描述過(guò)時(shí)且客戶(hù)端損壞的風(fēng)險(xiǎn)皆愉。這并不意味著不能手動(dòng)構(gòu)建服務(wù)描述嗜价。這樣做有很多有效的用例艇抠,例如,如果您想在實(shí)際實(shí)現(xiàn)之前擁有一個(gè)模擬服務(wù)器久锥。但是家淤,依賴(lài)于手動(dòng)任務(wù)的系統(tǒng)將不被視為該體系結(jié)構(gòu)樣式的實(shí)現(xiàn)。

請(qǐng)注意瑟由,我們對(duì)生成器如何使用源代碼沒(méi)有任何限制絮重。實(shí)際上,生成器甚至可以作為目標(biāo)構(gòu)建過(guò)程中的一個(gè)步驟來(lái)實(shí)現(xiàn)(例如歹苦,使用 Maven 插件)青伤。服務(wù)描述應(yīng)遵循協(xié)議標(biāo)準(zhǔn)。該體系結(jié)構(gòu)的主要優(yōu)點(diǎn)之一是客戶(hù)端可針對(duì)使用同一協(xié)議的許多不同目標(biāo)服務(wù)進(jìn)行重用暂氯,因此潮模,服務(wù)描述無(wú)法了解僅適用于一項(xiàng)特定服務(wù)的特定實(shí)現(xiàn)細(xì)節(jié)亮蛔〕帐客戶(hù)端提供的功能不屬于體系結(jié)構(gòu)的一部分:客戶(hù)端可以與目標(biāo)服務(wù)(例如,用于 Playground 控制臺(tái))進(jìn)行交互究流,或者根本不進(jìn)行交互(對(duì)于靜態(tài)文檔而言)辣吃。客戶(hù)背后的主要限制是芬探,除了服務(wù)描述所包含的信息外神得,他們還應(yīng)該對(duì)目標(biāo)服務(wù)的實(shí)施細(xì)節(jié)一無(wú)所知。連接器的定義非常寬松偷仿,因?yàn)槲覀儗?duì)信息的傳輸方式?jīng)]有任何限制哩簿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酝静,一起剝皮案震驚了整個(gè)濱河市节榜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌别智,老刑警劉巖宗苍,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異薄榛,居然都是意外死亡讳窟,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)敞恋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)丽啡,“玉大人,你說(shuō)我怎么就攤上這事硬猫〔构浚” “怎么了倚评?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)馏予。 經(jīng)常有香客問(wèn)我天梧,道長(zhǎng),這世上最難降的妖魔是什么霞丧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任呢岗,我火速辦了婚禮,結(jié)果婚禮上蛹尝,老公的妹妹穿的比我還像新娘后豫。我一直安慰自己,他們只是感情好突那,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布挫酿。 她就那樣靜靜地躺著,像睡著了一般愕难。 火紅的嫁衣襯著肌膚如雪早龟。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天猫缭,我揣著相機(jī)與錄音葱弟,去河邊找鬼。 笑死猜丹,一個(gè)胖子當(dāng)著我的面吹牛芝加,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播射窒,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼藏杖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了脉顿?” 一聲冷哼從身側(cè)響起蝌麸,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弊予,沒(méi)想到半個(gè)月后祥楣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汉柒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年误褪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碾褂。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兽间,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出正塌,到底是詐尸還是另有隱情嘀略,我是刑警寧澤恤溶,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站帜羊,受9級(jí)特大地震影響咒程,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讼育,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一帐姻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奶段,春花似錦饥瓷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蹲缠,卻和暖如春棺克,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吼砂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工逆航, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鼎文,地道東北人渔肩。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拇惋,于是被迫代替她去往敵國(guó)和親周偎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容