第19章 架構(gòu)決策

對架構(gòu)師的核心期望之一是做出架構(gòu)決策。架構(gòu)決策通常涉及應(yīng)用或系統(tǒng)的結(jié)構(gòu),但也可能涉及技術(shù)決策,特別是當(dāng)這些技術(shù)決策影響架構(gòu)特性時。不管在什么環(huán)境下,一個好的架構(gòu)決策有助于指導(dǎo)開發(fā)團(tuán)隊做出正確的技術(shù)選擇。制定架構(gòu)決策涉及收集足夠的相關(guān)信息,證明決策的合理性,記錄決策,并將決策有效地傳達(dá)給合適的涉眾。

架構(gòu)決策反模式

架構(gòu)決策是一門藝術(shù)。毫不意外地,作為架構(gòu)師在做決策時會出現(xiàn)一些架構(gòu)反模式。程序員Andrew Koenig將反模式定義為一種在開始時看起來是個好主意,但會給你帶來麻煩的東西。反模式的另一個定義是產(chǎn)生負(fù)面結(jié)果的可重復(fù)過程。在做出架構(gòu)決策時,可以(而且通常會)出現(xiàn)三種主要的架構(gòu)反模式:“隱藏資產(chǎn)”(Covering Your Assets)反模式、“土撥鼠日”(Groundhog Day)反模式和“電子郵件驅(qū)動架構(gòu)”(Email-Driven Architecture)反模式。這三種反模式通常遵循一個漸進(jìn)的流程:克服“隱藏資產(chǎn)”反模式將導(dǎo)致“土撥鼠日”反模式,克服“土撥鼠日”反模式將導(dǎo)致“電子郵件驅(qū)動架構(gòu)”反模式。做出有效和準(zhǔn)確的架構(gòu)決策需要架構(gòu)師克服所有這三種反模式。

“隱藏資產(chǎn)”反模式

在嘗試做出架構(gòu)決策時出現(xiàn)的第一個反模式是“隱藏資產(chǎn)”反模式。當(dāng)架構(gòu)師由于害怕做出錯誤的選擇而避免或推遲做出架構(gòu)決策時,就會出現(xiàn)這種反模式。

有兩種方法可以克服這種反模式。第一種方法是等到最后負(fù)責(zé)的時刻才做出重要的架構(gòu)決策。最后負(fù)責(zé)時刻意味著等待,直到您有足夠的信息來證明和驗證你的決策,但不要等待太久,以至于耽誤了開發(fā)團(tuán)隊或陷入分析癱瘓的反模式。避免這種反模式的第二種方法是不斷與開發(fā)團(tuán)隊協(xié)作,以確保您所做的決策能夠按預(yù)期實(shí)現(xiàn)。這一點(diǎn)非常重要,因為作為一個架構(gòu)師,不可能對關(guān)于特定技術(shù)和所有相關(guān)問題的每一個細(xì)節(jié)都了解。通過與開發(fā)團(tuán)隊緊密合作,架構(gòu)師可以在出現(xiàn)問題時快速修正架構(gòu)決策。

為了說明這一點(diǎn),假設(shè)架構(gòu)師決定使用只讀復(fù)制緩存將所有與產(chǎn)品相關(guān)的引用數(shù)據(jù)(產(chǎn)品描述、權(quán)重和維度)緩存在需要這些信息的所有服務(wù)實(shí)例中,其中主副本歸目錄服務(wù)所有。復(fù)制緩存意味著,如果產(chǎn)品信息發(fā)生任何更改(或添加了新產(chǎn)品),目錄服務(wù)將更新其緩存,然后通過復(fù)制(內(nèi)存中)緩存產(chǎn)品將其復(fù)制到需要該數(shù)據(jù)的所有其他服務(wù)。這個決定的一個正當(dāng)?shù)睦碛墒菧p少服務(wù)之間的耦合,并在不必進(jìn)行服務(wù)間調(diào)用的情況下有效地共享數(shù)據(jù)。然而,實(shí)現(xiàn)此架構(gòu)決策的開發(fā)團(tuán)隊發(fā)現(xiàn),由于一些服務(wù)的某些可擴(kuò)展性需求,此決策將需要比可用內(nèi)存更多的進(jìn)程內(nèi)內(nèi)存。通過與開發(fā)團(tuán)隊密切合作,架構(gòu)師可以迅速意識到問題,并調(diào)整架構(gòu)決策以適應(yīng)這些情況。

“土撥鼠日”反模式

一旦架構(gòu)師克服了“隱藏資產(chǎn)”反模式并開始做出決策,第二個反模式就會出現(xiàn):“土撥鼠日”反模式。當(dāng)人們不知道為什么作出決定,所以它不斷被討論了一遍又一遍時,“土撥鼠日”反模式就會出現(xiàn)?!巴翐苁笕铡狈茨J降妹诒葼枴つ锏碾娪啊锻翐苁笕铡?,在那里,每天都是2月2日。

“土撥鼠日”反模式之所以出現(xiàn),是因為架構(gòu)師當(dāng)做出架構(gòu)決策,但無法為決策提供理由(或完整的理由)。在證明架構(gòu)決策的合理性時,為你的決策提供技術(shù)和業(yè)務(wù)合理解釋是很重要的。例如,架構(gòu)師可以決定將單個應(yīng)用拆分為單獨(dú)的服務(wù),以解耦應(yīng)用的功能方面,以便應(yīng)用的每個部分使用更少的虛擬機(jī)資源,并且可以單獨(dú)維護(hù)和部署。雖然這是一個很好的技術(shù)證明的例子,但是缺少的是業(yè)務(wù)證明,換句話說,業(yè)務(wù)為什么要為這種架構(gòu)重構(gòu)付費(fèi)?這一決策的一個很好的業(yè)務(wù)理由可能是更快地交付新的業(yè)務(wù)功能,從而縮短推出市場的時間。另一個可能是降低與開發(fā)和發(fā)布新特性相關(guān)的成本。

在論證決策時提供業(yè)務(wù)價值對于任何架構(gòu)決策都至關(guān)重要。它也是一個很好的試金石,用于確定是否應(yīng)該首先做出架構(gòu)決策。如果一個特定的架構(gòu)決策沒有提供任何業(yè)務(wù)價值,那么它可能不是一個好的決策,應(yīng)該重新考慮。

四個最常見的業(yè)務(wù)理由包括成本、推出市場時間、用戶滿意度和戰(zhàn)略定位。當(dāng)關(guān)注這些常見的業(yè)務(wù)理由時,重要的是要考慮到什么對業(yè)務(wù)利益相關(guān)者是重要的。如果業(yè)務(wù)利益相關(guān)者不太關(guān)心成本,而更關(guān)心推出市場時間,那么僅基于成本節(jié)約來證明某個特定決策的合理性可能不是正確的決定。

“電子郵件驅(qū)動架構(gòu)”反模式

一旦架構(gòu)師做出決策并充分證明這些決策是正確的,第三種體系結(jié)構(gòu)反模式就會出現(xiàn):電子郵件驅(qū)動架構(gòu)?!半娮余]件驅(qū)動架構(gòu)”反模式是人們丟失、忘記甚至不知道已經(jīng)做出了架構(gòu)決策,因此不太可能實(shí)現(xiàn)該架構(gòu)決策。這種反模式完全是為了有效地傳達(dá)你的架構(gòu)決策。電子郵件是一個很好的溝通工具,但它是一個糟糕的文檔存儲系統(tǒng)。

有許多方法可以提高溝通架構(gòu)決策的有效性,從而避免“電子郵件驅(qū)動架構(gòu)”反模式。傳達(dá)架構(gòu)決策的第一條規(guī)則是不要將架構(gòu)決策包含在電子郵件正文中。將架構(gòu)決策包含在電子郵件正文中會為該決策創(chuàng)建多個記錄系統(tǒng)。很多時候,重要的細(xì)節(jié)(包括理由)被遺漏在郵件中,因此,創(chuàng)造了“土撥鼠日”反模式一遍又一遍。另外,如果架構(gòu)決策曾經(jīng)被更改或取代,人們會如何收到修改后的決策?更好的方法是在電子郵件正文中僅提及決策的性質(zhì)和上下文,并提供一個指向?qū)嶋H架構(gòu)決策的單個記錄系統(tǒng)的鏈接和相應(yīng)的詳細(xì)信息(無論是指向wiki頁面的鏈接還是文件系統(tǒng)中的文檔)。

有效溝通架構(gòu)決策的第二條規(guī)則是只通知那些真正關(guān)心架構(gòu)決策的人。一種有效的方法是將郵件正文按如下方式來寫:

“嗨,桑德拉,我做了一個關(guān)于服務(wù)間通信的重要決策,這會直接影響到你。請使用以下鏈接查看具體決策內(nèi)容…”

注意第一句中的短語:“關(guān)于服務(wù)間通信的重要決策”。這里提到的是決策的背景,而不是實(shí)際的決策本身。第一句話的第二部分更為重要:“這會直接影響到你?!比绻粋€架構(gòu)決策沒有直接影響到這個人,那么為什么要用你的架構(gòu)決策來打擾那個人呢?這是一個很好的試金石測試,用于確定哪些涉眾(包括開發(fā)人員)應(yīng)該被直接通知架構(gòu)決策。第二句話提供了一個指向架構(gòu)決策位置的鏈接,它只位于一個位置,因此為決策提供了一個記錄系統(tǒng)。

架構(gòu)重要性

許多架構(gòu)師認(rèn)為,如果架構(gòu)決策涉及任何特定的技術(shù),那么它就不是架構(gòu)決策,而是技術(shù)決策。這并不總是正確的。如果架構(gòu)師決定使用某種特定的技術(shù),因為它直接支持特定的架構(gòu)特性(如性能或可擴(kuò)展性),那么這就是一個架構(gòu)決策。Michael Nygard,著名的軟件架構(gòu)師和《發(fā)布!》(Release it!)的作者(實(shí)用書架),通過創(chuàng)造一個術(shù)語“架構(gòu)重要性”,解決了架構(gòu)師應(yīng)該負(fù)責(zé)哪些決策(因此什么是架構(gòu)決策)的問題。Michael認(rèn)為,架構(gòu)上重要的決策是那些影響結(jié)構(gòu)、非功能特性、依賴關(guān)系、接口或構(gòu)建技術(shù)的決策。

結(jié)構(gòu)是指影響正在使用的架構(gòu)的模式或風(fēng)格的決策。這方面的一個例子是決定在一組微服務(wù)之間共享數(shù)據(jù)。這個決定影響微服務(wù)的有界上下文,因此也影響應(yīng)用的結(jié)構(gòu)。

非功能特性是對正在開發(fā)或維護(hù)的應(yīng)用或系統(tǒng)很重要的架構(gòu)特性(“-ilities”)。如果一個技術(shù)的選擇影響性能,并且性能是應(yīng)用的一個重要方面,那么它就變成了一個架構(gòu)決策。

依賴關(guān)系是指系統(tǒng)中組件和/或服務(wù)之間的耦合點(diǎn),這反過來又會影響整體的可擴(kuò)展性、模塊化、敏捷性、可測試性、可靠性等。

接口是指如何訪問和編排服務(wù)和組件,通常通過網(wǎng)關(guān)、集成中心、服務(wù)總線或API代理。接口通常涉及定義契約,包括這些契約的版本控制和棄用策略。接口影響使用系統(tǒng)的其他人,因此在架構(gòu)上具有重要意義。

最后,構(gòu)建技術(shù)指的是關(guān)于平臺、框架、工具甚至過程的決策,盡管這些決策本質(zhì)上是技術(shù)性的,但可能會影響架構(gòu)的某些方面。

架構(gòu)決策記錄

記錄架構(gòu)決策的最有效方法之一是通過架構(gòu)決策記錄(Architecture Decision Records,ADRs)。ADRs最初是由Michael

Nygard在一篇博客文章中宣傳的,后來在ThoughtWorks技術(shù)雷達(dá)上標(biāo)記為“采用”。ADR由描述特定架構(gòu)決策的短文本文件(通常一到兩頁長)組成。雖然ADRs可以使用純文本編寫,但它們通常是以某種文本文檔格式編寫的,比如AsciiDoc或Markdown?;蛘?,也可以使用wiki頁面模板編寫一個ADR。

工具也可以用來管理ADR。Nat Pryce是《Growing Object-Oriented Software Guided by Tests》(Addison-Wesley)的合著者,他為ADRs編寫了一個開源工具ADR-tools。ADR-tools提供了一個命令行界面來管理ADRs,包括編號方案、位置和替代邏輯。來自德國的軟件工程師Micha Kops寫了一篇關(guān)于使用ADR-tools的博客文章,提供了一些關(guān)于如何使用ADR-tools來管理架構(gòu)決策記錄的好例子。

基本結(jié)構(gòu)

一個ADR的基本結(jié)構(gòu)包括五個主要部分:標(biāo)題(Title)、狀態(tài)(Status)、背景(Context)、決定(Decision)和結(jié)果(Consequences)。作為基本結(jié)構(gòu)的一部分,我們通常會添加兩個附加部分:合規(guī)(Compliance)和備注(Notes)。這個基本結(jié)構(gòu)(如圖19-1所示)可以擴(kuò)展到包括任何其他認(rèn)為需要的部分,只要模板保持一致和簡潔。這方面的一個很好的例子是,如果有必要,可以添加一個替代部分,以提供對所有其他可能的替代解決方案的分析。

圖19-1. ADR基本結(jié)構(gòu)

標(biāo)題

ADR的標(biāo)題通常按順序編號,并包含描述架構(gòu)決策的簡短表述。例如,在訂單服務(wù)和支付服務(wù)之間使用異步消息傳遞的決策可以這樣閱讀:“42. 在訂單和支付服務(wù)之間使用異步消息傳遞?!?。標(biāo)題應(yīng)具有足夠的描述性,以消除對決策的性質(zhì)和背景的任何歧義,但同時應(yīng)簡短明了。

狀態(tài)

ADR的狀態(tài)可以標(biāo)記為已建議(Proposed)、已接受(Accepted)或已取代(Superseded)。已建議狀態(tài)意味著決策必須由更高級別的決策者或某種架構(gòu)治理機(jī)構(gòu)(如架構(gòu)審查委員會)批準(zhǔn)。已接受狀態(tài)表示決策已被批準(zhǔn)并準(zhǔn)備好執(zhí)行。已取代狀態(tài)意味著該決策已被另一ADR更改和取代。已取代狀態(tài)總是假定先前的ADR狀態(tài)為已接受;換句話說,一個已建議的ADR永遠(yuǎn)不會被另一個ADR取代,而是繼續(xù)被修改直到被接受。

已取代狀態(tài)是一種強(qiáng)有力的方法,它可以記錄做出了哪些決策、當(dāng)時為什么做出這些決策、新的決策是什么以及為什么改變了這些決策。通常,當(dāng)一個ADR被取代時,它會被標(biāo)上取代它的決策。同樣,取代另一個ADR的決策也標(biāo)有被其取代的ADR。例如,假設(shè)ADR 42(“在訂單和支付服務(wù)之間使用異步消息傳遞”)先前已獲得批準(zhǔn),但由于支付服務(wù)的實(shí)現(xiàn)和地位后來發(fā)生了變化,現(xiàn)在必須在兩個服務(wù)之間使用REST(ADR 68)。狀態(tài)如下所示:

ADR 42. 在訂單和支付服務(wù)之間使用異步消息傳遞

狀態(tài):被68取代

ADR 68. 在訂單和支付服務(wù)之間使用REST

狀態(tài):已接受,取代42

ADR 42和68之間的鏈接和歷史軌跡避免了必然發(fā)生的關(guān)于ADR 68 “怎么使用消息傳遞?”的問題。

ADRS和征求意見(RFC)

如果架構(gòu)師希望發(fā)送ADR草案征求意見(當(dāng)架構(gòu)師希望與更多的參與人員驗證各種假設(shè)和斷言時,這有時是個好主意),我們建議創(chuàng)建一個名為征求意見(RFC)的新狀態(tài),并指定完成評審的截止日期。這種做法避免了慣常的“分析癱瘓”反模式,即決策永遠(yuǎn)被討論,但從來沒有真正落實(shí)。一旦達(dá)到該日期,架構(gòu)師可以分析對ADR的所有評論,對決策進(jìn)行任何必要的調(diào)整,做出最終決策,并將狀態(tài)設(shè)置為“已建議”(如果架構(gòu)師能夠自己批準(zhǔn)決策,則在這種情況下,狀態(tài)將被設(shè)置為“已接受”)。一個ADR的RFC狀態(tài)示例如下:

狀態(tài)

征求意見,截止日期2010年1月9日

ADR狀態(tài)部分的另一個重要方面是,它迫使架構(gòu)師與其上司或首席架構(gòu)師進(jìn)行必要的對話,討論他們可以自行批準(zhǔn)架構(gòu)決策的標(biāo)準(zhǔn),或者是否必須通過更高級別的架構(gòu)師、架構(gòu)評審委員會批準(zhǔn),或者其他架構(gòu)管理機(jī)構(gòu)。

成本、跨團(tuán)隊影響和安全這三個準(zhǔn)則形成這些對話的良好開端。成本可以包括軟件購買或許可費(fèi)、額外的硬件成本,以及實(shí)現(xiàn)架構(gòu)決策的總體花費(fèi)。工作量成本可以通過將執(zhí)行架構(gòu)決策的預(yù)估小時數(shù)乘以公司的標(biāo)準(zhǔn)全職當(dāng)量(FTE)率來估計。項目所有者或項目經(jīng)理通常擁有FTE的金額。如果架構(gòu)決策的成本超過了某個數(shù)量,那么必須將其設(shè)置為已建議狀態(tài)并由其他人批準(zhǔn)。如果架構(gòu)決策影響其他團(tuán)隊或系統(tǒng)或具有任何類型的安全影響,那么它不能由架構(gòu)師自行批準(zhǔn),必須由更高級別的管理機(jī)構(gòu)或首席架構(gòu)師批準(zhǔn)。

一旦確定了標(biāo)準(zhǔn)和相應(yīng)的限制并達(dá)成一致(例如“超過5000歐元的成本必須得到架構(gòu)評審委員會的批準(zhǔn)”),就應(yīng)該很好地記錄這些標(biāo)準(zhǔn),以便創(chuàng)建ADRs的所有架構(gòu)師知道他們何時可以和不可以批準(zhǔn)自己的架構(gòu)決策。

背景

ADR的背景部分指定了起作用的力量。換句話說,“什么情況迫使我做出這個決策?” ADR的這一部分允許架構(gòu)師描述具體情況或問題,并簡要闡述可能的替代方案。如果要求架構(gòu)師詳細(xì)記錄每個備選方案的分析,那么可以在ADR中添加一個附加的備選方案部分,而不是將該分析添加到背景部分。

背景部分還提供了一種記錄架構(gòu)的方法。通過對背景進(jìn)行闡述,架構(gòu)師也是在描述架構(gòu)。這是一種以清晰簡潔的方式記錄架構(gòu)的一個特定領(lǐng)域的有效方法。繼續(xù)上一節(jié)中的示例,背景可能如下所示:“訂單服務(wù)必須將信息傳遞給支付服務(wù),以便為當(dāng)前下的訂單付款。這可以使用REST或異步消息傳遞來完成?!闭堊⒁猓@個簡潔的語句不僅指定了場景,還指定了備選方案。

決策

ADR的決策部分包含架構(gòu)決策內(nèi)容,以及作出決策的充分理由。Michael Nygard介紹了一種很好的方式,通過使用非常肯定的、命令性的而不是被動的語態(tài)來陳述架構(gòu)決策。例如,在服務(wù)之間使用異步消息傳遞的決策將表述為“我們將在服務(wù)之間使用異步消息傳遞”。與“我認(rèn)為服務(wù)之間的異步消息傳遞將是最佳選擇”相比,這是一種更好的說明決策的方式。注意,這里不清楚決策是什么,甚至不清楚是否已經(jīng)做出決策,只說明了架構(gòu)師的意見。

也許ADRs決策部分最強(qiáng)大的一個方面是它允許架構(gòu)師更多地強(qiáng)調(diào)為什么要這樣而不是如何去做。理解為什么要做決策比理解事情是如何運(yùn)作的重要得多。大多數(shù)架構(gòu)師和開發(fā)人員可以通過查看上下文圖來確定事情是如何工作的,但不能確定為什么要做出決策。了解做出決策的原因和相應(yīng)的理由有助于人們更好地理解問題的背景,并通過重構(gòu)到可能產(chǎn)生問題的另一個解決方案來避免可能的錯誤。

為了說明這一點(diǎn),請考慮幾年前的一個原始架構(gòu)決策,即使用Google的遠(yuǎn)程過程調(diào)用(gRPC)作為兩個服務(wù)之間通信的手段。幾年后,另一個架構(gòu)師在不理解為什么要做出這個決策的情況下,選擇覆蓋這個決策,轉(zhuǎn)而使用消息傳遞來更好地解耦服務(wù)。然而,實(shí)現(xiàn)這種重構(gòu)會突然導(dǎo)致延遲的顯著增加,進(jìn)而最終導(dǎo)致上游系統(tǒng)出現(xiàn)超時。如果理解gRPC最初的用途是顯著減少延遲(以緊密耦合服務(wù)為代價),那么第一時間就可以防止重構(gòu)的發(fā)生。

結(jié)果

ADR的結(jié)果部分是另一個非常強(qiáng)大的部分。這一部分記錄了一個架構(gòu)決策的總體影響。架構(gòu)師做出的每一個架構(gòu)決策都會產(chǎn)生某種影響,無論是好是壞。必須指定架構(gòu)決策的影響迫使架構(gòu)師考慮這些影響是否超過決策的好處。

這個部分的另一個好的用法是記錄與架構(gòu)決策相關(guān)聯(lián)的權(quán)衡分析。這些權(quán)衡可以是基于成本的,也可以是針對其他架構(gòu)特性的權(quán)衡。例如,考慮使用異步(即發(fā)即棄)消息傳遞在網(wǎng)站上發(fā)布評論的決策。這個決定的理由是將發(fā)布評論請求的響應(yīng)時間從3100毫秒顯著提高到25毫秒,因為用戶不需要等待實(shí)際的評論被發(fā)布(只需要消息被發(fā)送到隊列)。雖然這是一個很好的理由,但其他人可能會認(rèn)為這是一個壞主意,因為與異步請求相關(guān)聯(lián)的錯誤處理非常復(fù)雜(“如果有人用臟話來發(fā)布評論,會發(fā)生什么?”)。對這個決定提出質(zhì)疑的人不知道,這個問題已經(jīng)與業(yè)務(wù)相關(guān)人員和其他架構(gòu)師討論過了,從權(quán)衡的角度來看,更重要的是提高響應(yīng)能力并處理復(fù)雜的錯誤處理,而不是等待同步地向用戶提供評論成功發(fā)布的反饋。通過利用ADRs,權(quán)衡分析可以包含在結(jié)果部分,提供架構(gòu)決策的背景(和權(quán)衡)的全面情況,從而避免這些情況。

合規(guī)

ADR的合規(guī)部分不是ADR的標(biāo)準(zhǔn)部分之一,但我們強(qiáng)烈建議添加該部分。法規(guī)遵從性部分迫使架構(gòu)師考慮如何從法規(guī)遵從性的角度來度量和管理架構(gòu)決策。架構(gòu)師必須決定此決策的合規(guī)性檢查必須是手動的,還是可以使用適應(yīng)性函數(shù)(fitness function)自動進(jìn)行。如果可以使用適應(yīng)性函數(shù)實(shí)現(xiàn)自動化,那么架構(gòu)師可以在本部分中指定如何編寫適應(yīng)性函數(shù),以及是否需要對代碼庫進(jìn)行任何其他更改,以度量此架構(gòu)決策的合規(guī)性。

例如,在圖19-2所示的傳統(tǒng)n層架構(gòu)中考慮以下架構(gòu)決策。業(yè)務(wù)層中業(yè)務(wù)對象使用的所有共享對象將駐留在共享服務(wù)層中,以隔離和包含共享功能。

圖19-2.一個架構(gòu)決策示例

通過使用Java中的ArchUnit或C#中的NetArchTest,可以自動度量和管理這種架構(gòu)決策。例如,使用Java中的ArchUnit,自動適應(yīng)性函數(shù)測試可能如下所示:

@Test

public voidshared_services_should_reside_in_services_layer() {

???classes().that().areAnnotatedWith(SharedService.class)

???????.should().resideInAPackage("..services..")

??????? .because("All shared servicesclasses used by business " +

???????????????? "objects in the businesslayer should reside in the services " +

???????????????? "layer to isolate andcontain shared logic")

??????? .check(myClasses);

}

注意,這個自動適應(yīng)性函數(shù)需要編寫新的故事來創(chuàng)建一個新的Java注釋(@SharedService),然后將這個注釋添加到所有共享類中。這部分還指定了什么是測試、在哪里可以找到測試、如何執(zhí)行測試以及何時執(zhí)行測試。

備注

另一個不是標(biāo)準(zhǔn)ADR的一部分,但我們強(qiáng)烈建議添加的是備注部分。這部分包括關(guān)于ADR的各種元數(shù)據(jù),例如:

- 原作者

- 批準(zhǔn)日期

- 批準(zhǔn)人

- 取代日期

- 最后修改日期

- 修改人

- 上次修改內(nèi)容

即使在版本控制系統(tǒng)(如Git)中存儲ADRs時,附加的元信息也非常有用,超出了存儲庫所能支持的范圍,因此無論ADRs如何存儲以及存儲在何處,我們都建議添加此部分。

存儲ADRs

一旦架構(gòu)師創(chuàng)建了一個ADR,它就必須存儲在某個地方。無論ADRs存儲在哪里,每個架構(gòu)決策都應(yīng)該有自己的文件或wiki頁面。一些架構(gòu)師喜歡將ADRs與源代碼一起保存在Git存儲庫中。將ADRs保存在Git存儲庫中還允許對ADR進(jìn)行版本控制和跟蹤。但是,對于大型組織,我們出于幾個原因告誡不要使用這種做法。首先,每個需要了解架構(gòu)決策的人可能無權(quán)訪問Git存儲庫。其次,這不是存儲ADRs的好地方,因為ADR的上下文在應(yīng)用的Git存儲庫之外(比如集成架構(gòu)決策、企業(yè)架構(gòu)決策或每個應(yīng)用通用的決策)?;谶@些原因,我們建議將ADRs存儲在wiki(使用wiki模板)或共享文件服務(wù)器上的共享目錄中,wiki或其他文檔呈現(xiàn)軟件可以輕松訪問這些目錄。圖19-3顯示了這個目錄結(jié)構(gòu)(或wiki頁面導(dǎo)航結(jié)構(gòu))的示例。

圖19-3.存儲ADRs的目錄結(jié)構(gòu)示例

應(yīng)用目錄包含特定于某種應(yīng)用上下文的架構(gòu)決策。此目錄被進(jìn)一步細(xì)分為多個目錄。公共子目錄用于所有應(yīng)用程序的架構(gòu)決策,例如“所有與框架相關(guān)的類都將包含一個注釋(@framework在Java中)或?qū)傩裕╗framework]在C#)來標(biāo)識屬于底層框架代碼的類。”應(yīng)用目錄下的子目錄對應(yīng)于特定的應(yīng)用或系統(tǒng)上下文,并包含特定于該應(yīng)用或系統(tǒng)的架構(gòu)決策(在本例中,是ATP和PSTD應(yīng)用)。集成目錄包含那些涉及應(yīng)用、系統(tǒng)或服務(wù)之間通信的ADRs。企業(yè)架構(gòu)ADRs包含在企業(yè)目錄中,表示這些是影響所有系統(tǒng)和應(yīng)用的全局架構(gòu)決策。企業(yè)架構(gòu)ADR的一個例子是“對系統(tǒng)數(shù)據(jù)庫的所有訪問都只能從所屬系統(tǒng)進(jìn)行”,從而防止在多個系統(tǒng)之間共享數(shù)據(jù)庫。

在wiki中存儲ADRs時(我們的建議),適用前面描述的相同結(jié)構(gòu),每個目錄結(jié)構(gòu)表示一個導(dǎo)航頁。每個ADR將被表示為每個導(dǎo)航頁(應(yīng)用、集成或企業(yè))中的單個wiki頁面。

本節(jié)中指出的目錄或?qū)Ш巾撁Q只是一個建議。每個公司都可以選擇任何適合自己情況的名字,只要這些名字在團(tuán)隊中是一致的。

ADRs作為文檔

記錄軟件架構(gòu)一直是一個困難的話題。雖然正在出現(xiàn)一些用于繪制架構(gòu)的標(biāo)準(zhǔn)(如軟件架構(gòu)師Simon Brown的C4模型或The Open Group ArchiMate標(biāo)準(zhǔn)),但是還沒有用于記錄軟件架構(gòu)的標(biāo)準(zhǔn)。這就是ADRs的用武之地。

架構(gòu)決策記錄是記錄軟件架構(gòu)的有效手段。ADR的背景部分提供了一個極好的機(jī)會來描述需要做出架構(gòu)決策的系統(tǒng)的特定領(lǐng)域。這部分還提供了一個描述替代方案的機(jī)會。也許更重要的是決策部分描述了做出特定決策的原因,這是迄今為止最好的架構(gòu)文檔形式。結(jié)果部分通過描述特定決策的附加的方面,將最后一部分添加到架構(gòu)文檔中,例如選擇性能而不是可擴(kuò)展性的權(quán)衡分析。

使用ADRs作為標(biāo)準(zhǔn)

很少有人喜歡標(biāo)準(zhǔn)。大多數(shù)時候,標(biāo)準(zhǔn)似乎更適合于控制人們和他們做事的方式,而不是任何有用的東西。將ADRs用于標(biāo)準(zhǔn)可以改變這種不良做法。例如,ADR的背景部分描述了強(qiáng)制執(zhí)行特定標(biāo)準(zhǔn)的情況。ADR的決策部分不僅可以用來說明標(biāo)準(zhǔn)是什么,更重要的是,為什么需要存在標(biāo)準(zhǔn)。這是一種很好的方法,可以用來判斷特定標(biāo)準(zhǔn)是否應(yīng)該首先存在。如果一個架構(gòu)師不能證明這個標(biāo)準(zhǔn)是合理的,那么也許它不是一個好的標(biāo)準(zhǔn)來制定和執(zhí)行。此外,開發(fā)人員越了解某個特定標(biāo)準(zhǔn)存在的原因,他們就越有可能遵循它(相應(yīng)地,也就不會質(zhì)疑它)。ADR的結(jié)果部分是架構(gòu)師判斷標(biāo)準(zhǔn)是否有效和是否應(yīng)該制定的另一個好地方。在這一部分中,架構(gòu)師必須考慮并記錄他們正在制定的特定標(biāo)準(zhǔn)的含義和結(jié)果。通過分析結(jié)果,架構(gòu)師可能會決定該標(biāo)準(zhǔn)終究不應(yīng)該被應(yīng)用。

示例

許多架構(gòu)決策存在于我們正在進(jìn)行的“案例研究:Going, Going, Gone”中。使用事件驅(qū)動的微服務(wù)、拆分競拍者和拍賣者的用戶界面、使用實(shí)時傳輸協(xié)議(RTP)進(jìn)行視頻捕獲、使用單個API層以及使用發(fā)布和訂閱消息傳遞只是為這個拍賣系統(tǒng)做出的幾十個架構(gòu)決策中的幾個。在一個系統(tǒng)中做出的每一個架構(gòu)決策,無論多么明顯,都應(yīng)該被記錄和證明。

圖19-4說明了“Going,Going,Gone”拍賣系統(tǒng)中的一個架構(gòu)決策,即在投標(biāo)捕獲、投標(biāo)橫幅和投標(biāo)跟蹤器服務(wù)之間使用發(fā)布和訂閱(pub/sub)消息傳遞。

圖19-4.在服務(wù)之間使用發(fā)布/訂閱

此架構(gòu)決策的ADR可能類似于圖19-5:

圖19-5. ?ADR76. 投標(biāo)服務(wù)之間的異步發(fā)布/訂閱消息傳遞

原文參考:http://m.itdecent.cn/p/54fbb9f56367

全書翻譯目錄:http://m.itdecent.cn/p/05711d172dfa

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容