天天看點

《需求設計:建構使用者想要和需要的産品》——2.3 內建設計

本節書摘來自華章計算機《需求設計:建構使用者想要和需要的産品》一書中的第2章,第2.3節,作者: [英] 克裡斯·布裡頓(chris britton) 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

內建設計的主要目标是:

把任務劃分到各個應用程式與服務之中。

決定資料表與資料庫之間的指派關系。

以應用程式之間所傳遞的消息為視角,來定義內建方面的需求。

對于其他更為詳細設計的來說,內建設計确定了這些設計的範圍。使用者界面設計可以針對每個應用程式或服務分别來做(對于服務來說,其使用者指的是另一個程式),資料庫設計可以針對每個資料庫分别來做。盡管技術設計也可以針對每個應用程式或服務分别來做,但是在大多數的公司裡面,我們都可以令多個應用程式與服務共用同一套技術設計。

圖2-5示範了如何把任務劃分到多個應用程式與服務之中。

然而這樣的圖,其用處并不大,因為現實工作之中的應用程式會有很多項任務,是以很難用這樣的圖來表示。于是筆者繪制了圖2-6,并把每個應用程式所要實作的任務列了出來。圖2-6之中的方框表示應用程式或服務,箭頭表示請求/應答,但是有一些箭頭例外。從某個資料庫指向另一個資料庫,并且标有sp字樣的箭頭,表示“選取并投射”(select and project),也就是說,我們不是把所有的資料對象全都傳送過去(而是隻把自己所選擇的那些對象傳送過去),即便傳送,也未必要把對象的每一個屬性都放在資料流裡。(從資料對象的全部屬性之中選出某些屬性,這叫做投射。選取和投射這兩個詞,都是資料庫領域的術語。)該圖的下方有一條标有字母d的消息。d表示可延期的(deferrable),意思是說,發送方把這條消息發送出去之後就可以不管了,它無需确認該消息已收到。圖2-6中的這條消息,是為了在order資料庫中記錄“訂單已打包并等待投遞”這一事實。

應用程式可以分為三類:

線上應用程式(online application)。這種應用程式有終端使用者來對其進行操控。筆者把它們直接叫做應用程式(application)。在圖2-6中,order訂單錄入應用程式和倉庫前端就屬于這一類。

批次應用程式(batch application)。這種應用程式由某些時間事件來觸發。例如,負責計算應付利息的銀行應用程式,就屬于此類。筆者在圖中會給這類方框的左上角畫一個簡單的鐘面。

服務應用程式(service application)。這些應用程式是供其他程式來調用的,筆者會把它們稱為服務。(請注意:應用程式服務與圖書館服務等業務服務不是一回事。業務服務可以由相關成員通過線上應用程式來提供,而服務應用程式則沒有直接的真人使用者。)

《需求設計:建構使用者想要和需要的産品》——2.3 內建設計
《需求設計:建構使用者想要和需要的産品》——2.3 內建設計

那麼,應用程式到底是什麼呢?應用程式這個概念,現在已經不再等同于單純的程式(program)了。我們會把應用程式實作成若幹元件,并對這些元件分層,也有可能會把這些元件在各台伺服器上面複制一份。元件是安裝單元,但由于它們特别小,是以同一個項目或子項目,通常同時需要照管很多個元件。筆者把這些元件稱為應用程式。下面給出定義:

應用程式是由計算機代碼檔案及配置所構成的集合,這些内容總是同時釋出并投入生産。

這裡有一個重要的問題要注意,如果應用程式a給應用程式b發送消息,那麼你最好是做好一種準備:這兩個程式有可能不會在同一時刻投入生産。例如,有一款新的訂單錄入應用程式,它有可能需要同時具備兩種訂單發送能力,一種是給舊版的訂單履行(order fulfillment)應用程式發訂單,另一種是給新版的訂單履行應用程式發訂單。由此可見,即便對于應用程式的開發工作來說,釋出單元(unit of release)也依然是一項相當重要的屬性,因為它意味着我們可以在某種程度上較為獨立地開發各個應用程式。

同樣的問題還會發生在資料庫上面:你可能隻想把資料庫更新到新的版本,但并不想同時把所有的應用程式也更新到新的發行版。然而有的時候,例如,修改了某一列的名稱時,你必須同時釋出應用程式與資料庫,但一般來說,應該盡量避免這種情況。

圖2-6僅僅是為了示範而繪制的。它不一定代表該業務問題的最佳解決方案。最佳的解決方案需要根據具體的情況來确定。從前,某些公司會研發那種涵蓋多項任務的龐大應用程式,而另外一些公司則會研發很多個小的應用程式。當soa(面向服務的架構)興起之後,有的公司開始研發龐大的服務與三層應用程式(three-tier application),這種應用程式由(與使用者相溝通的)表現應用程式、業務邏輯服務及資料服務構成。然而某些soa項目做得并不好,于是很多人就開始和soa保持距離了。最近又流行微服務(microservice)[3]。微服務與傳統soa服務的主要差別是,它會對功能需求做分割,使其能夠用很多個小的服務來實作,而不是用少數幾個大的服務來實作。這樣做所依據的理由是:很多個小的項目要比一個大的項目更容易成功,這個理由能夠說得通。

請注意,soa與微服務這兩個詞的定義方式有很多種,而且經常互相沖突。有些人認為soa就是由soap等web技術所實作的服務。維基百科的微服務詞條[4]認為,微服務與soa不同,因為微服務僅僅實作在某一個應用程式之中,而soa則會對多個應用程式進行內建。假如真是這樣,那微服務就糟糕了,因為內建是個相當重要的工作,它并不是開發者僅僅為了好玩而想出來的東西,我們需要通過內建來為業務功能提供支援。martin fowler[3]認為微服務旨在把某塊功能交給開發者負責,由于還要有一些應用程式用來處理使用者界面,是以,筆者認為,這意味着要把業務邏輯層與資料處理層相合并。這個想法很好,因為大多數的“業務邏輯”,實際上談的都是資料處理(筆者在20世紀90年代就提倡過這個想法)。eric knorr[5]認為,soa是由管理層來引領的(這有點令人不舒服),而微服務則是開發者來引領的(這很讨人喜歡)。然後,還有一些人認為soa和微服務在技術上也有差別。前者使用老式的技術,而後者則使用最近興起的那些更為輕量級的技術。到底應該使用什麼技術,取決于我們是不是希望中間件廠商能夠提供諸如監控系統及重新格式化資料等額外的功能,其實這些功能也可以在應用程式的代碼裡面輕松地實作出來。

微服務确實有很多特性,但筆者對it業所炒作出來的這些萬能技術、架構及開發流程感到頭疼。雖然單獨挑出微服務來評價,可能有失公允,但筆者還是要在本書之中讨論一下這個利弊參半的技術。it界的流行風潮一個接着一個,我們都不停地去趕時髦。才華已經不再受到重視,機械式的學習卻非常吃香,概念問題很少有人關注,許多想法也叫人給丢進垃圾堆裡去了,當然,總是會有人從中撿起來幾個,稍微加工一下,想借此把自己打造成it界的大師。sir isaac newton寫過一句話:“如果我看得比别人更遠,那是因為我站在巨人的肩上”[6],假如牛頓在it界工作,那他肯定早把巨人的腿給砍了。

造成這種風潮的一個原因在于:it界的一些知名人士并沒有把業務需求與it概念或是實作該概念的具體技術清楚地分開。對于soa來說,它所要應對的業務需求,是準确且高效地處理資料,它的it概念,是以程式來調用服務,并且通常是通過網絡進行調用的,至于web服務,則是實作這種業務需求所采用的一項具體技術。

新技術雖然不斷地受到炒作,但某些基本的問題卻依然擺在那裡,就服務領域來說,下面這幾個簡單的問題至少争論了30年:

1.到底應不應該使用服務?

2.應該把服務做到多大?

現在我們就來依次讨論這兩個問題。

有很多理由促使我們采用服務來實作軟體産品,例如:

想要複用邏輯與資料。例如,銀行業的許多應用程式,都需要從賬戶之中取錢(有一些還需要向賬戶之中存錢),是以,最好是把這些代碼一次寫好,并反複地用它來管理賬戶的入賬與出賬。

性能方面的理由。我們可能需要用多台伺服器及備份伺服器來實作更高的性能與更大的彈性。

安全方面的理由。例如,你可能不想像圖2-6那樣,把面向客戶的web網站與訂單資料庫直接連起來,而是想令網絡流量通過一些防火牆層,以阻止其中某些類型的資訊達到伺服器。

想要把大項目分成多個小項目。

還有很多應用程式并沒有上述理由,但卻依然使用了服務。唯一的解釋就是:這些應用程式想要為以後的複用提前做打算。由于同時編寫服務與前端應用程式所需的工作量,要比隻寫一個應用程式大,是以這個理由并不算太好。

那麼,服務和應用程式到底應該做到多大呢?對于這個問題,有幾種看法。第一種觀點認為,這個大小應該根據來使用者的情況來定。這意味着面向使用者的應用程式,應該要為某個使用者組所需的全部工作提供支援。(前面說過,同一個人可以屬于兩個或兩個以上的使用者組。)如果兩個使用者組之間的關系比較緊密(如銷售人員與銷售經理),那麼應用程式可以同時處理這兩個組。至于底層的很多處理工作,則可以交給服務來辦。第二種觀點認為,這個大小應該根據資料的精确度來定,意思是說,你需要確定每份資訊都有權威的資料源。資料是可以複制的,但如果同一個事實有兩種互相沖突的觀察結果,那麼就會對業務造成阻礙。這并不是說你非得打造一個龐大的資料庫。從理論上講,我們可以把情境設計之中的每張資料表,都與某一個資料庫相對應,這樣做的缺點是需要進行更多的管理工作,而且由于很多事務都要更新多張資料表,是以處理效率不太高。我們最好是把資料表分組,并且指派某個任務來專門更新某一組資料表。然而,某些資料表的使用範圍很廣(例如,存放顧客、訂單及産品等資料的表格),于是我們可能會在多個資料庫裡面存放這些表格。在圖2-6中,産品資料與訂單資料就存在複本。在複制資料表的時候,隻應該把需要用到的那些資料複制出來,這對于性能和安全都有好處。是以,我們隻應該把目前正在銷售的那些産品儲存在order processing(訂單處理)資料庫之中,而且隻應該把已送出的訂單之中與送貨有關那部分資訊,從order(訂單)資料庫發送到delivery(投遞)資料庫之中。第三種觀點認為,應該把應用程式與服務指派給很多個小團隊來負責開發,并且盡量縮減它們之間的依賴關系(除非進行情境設計,否則很難知道這種依賴關系)。上述三種觀點,會把設計推向不同的方向。要想把設計做好,就需要在這幾種做法之間權衡,并且要發揮創造力,以便找出有效的解決方案。

分析內建設計的時候,首先應該檢查每項任務是否都得到了實作,以及它們是否都能夠通路到各自所需的資料。如果要進行資料傳輸,那就粗略地計算一下應用程式之間所傳遞的資料量。如果要從一個資料庫複制資料到另外一個資料庫,那就需要考慮:萬一資料複制出現延遲,會不會引發什麼後果。

內建設計之是以必須要做,還有一個重要的原因在于:我們需要與已有的應用程式或第三方所開發的應用程式相內建。現實工作中,很少會從頭開始實作項目所需的每一段代碼,因為可能已經有一些應用程式擺在那裡了。這些已有的或第三方的應用程式盡管不太完美,但是采用它們來做項目,要比從頭開始做項目更加劃算。還有一種情況是:我們計劃把目前版本的應用程式更新到新版,在更新過程中,可能需要将舊版應用程式部分替換掉。

我們可以從現有的應用程式之中重建一套情境設計,筆者把這種設計叫做情境模型(context model)。如果我們打算做的那套情境設計,要對現有應用程式進行修改,那麼就應該根據現有的應用程式來建構這樣一個情境模型,并且與打算做的那套情境設計互相對比,以發現二者之間的差別。當新的應用程式與現有程式之間有複雜的互相依賴關系時,這麼做尤其有用。

根據現有應用程式所做的情境模型,也有助于我們對同領域或相似領域的新設計方案進行檢查,因為我們可以用該模型來判斷自己有沒有把所需的全部功能都涵蓋進來。此外,這種模型還能幫我們對新的開發項目進行商業論證。