自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

架構(gòu)漫談:從架構(gòu)的角度看如何寫好代碼

開發(fā) 架構(gòu)
軟件架構(gòu)實(shí)際上包括了:代碼架構(gòu),以及承載代碼運(yùn)行的硬件部署架構(gòu)。實(shí)際上,硬件部署架構(gòu)最終還是由代碼的架構(gòu)來(lái)決定。因?yàn)榇a架構(gòu)不合理,是無(wú)法把一個(gè)運(yùn)行單元分拆出多個(gè)來(lái)的,那么硬件架構(gòu)能分拆的就非常的有限,整個(gè)系統(tǒng)最終很難長(zhǎng)的更大。

軟件架構(gòu)實(shí)際上包括了:代碼架構(gòu),以及承載代碼運(yùn)行的硬件部署架構(gòu)。實(shí)際上,硬件部署架構(gòu)最終還是由代碼的架構(gòu)來(lái)決定。因?yàn)榇a架構(gòu)不合理,是無(wú)法把一個(gè)運(yùn)行單元分拆出多個(gè)來(lái)的,那么硬件架構(gòu)能分拆的就非常的有限,整個(gè)系統(tǒng)最終很難長(zhǎng)的更大。

所以我們經(jīng)常會(huì)聽說(shuō),重寫代碼,推翻原有架構(gòu),重新設(shè)計(jì)等等說(shuō)法,來(lái)說(shuō)明架構(gòu)的進(jìn)化。這實(shí)際上就是當(dāng)初為了完成任務(wù),沒(méi)有充分思考所帶來(lái)的后果。這也并不是架構(gòu)進(jìn)化的事情,而是個(gè)人對(duì)問(wèn)題領(lǐng)域的逐漸深入理解的過(guò)程。所以有必要再討論一下,代碼的架構(gòu)應(yīng)該是怎樣的。

本文會(huì)在之前幾篇文章的基礎(chǔ)上,進(jìn)一步探討如何把架構(gòu)的思考進(jìn)行落地,細(xì)化到我們代碼的實(shí)踐當(dāng)中,盡量不要讓代碼成為系統(tǒng)長(zhǎng)大的瓶頸,降低架構(gòu)分拆的成本。

在前面我們提到,軟件實(shí)際上是對(duì)現(xiàn)實(shí)生活的模擬,虛擬化。這是一個(gè)非常重要的前提,直接決定了我們的代碼應(yīng)該分為幾部分。結(jié)合每個(gè)部署單元所承擔(dān)的責(zé)任,可以明確的拆分為兩個(gè)不同的責(zé)任:

表達(dá)業(yè)務(wù)邏輯的代碼。很多人把這部分叫做Domain Logic,或者叫Domain Model。這部分實(shí)際是來(lái)源于生活的,必須保持和現(xiàn)實(shí)生活中的切分一致,并非人為的抽象而成。

對(duì)用戶提供訪問(wèn)并保存業(yè)務(wù)邏輯運(yùn)行結(jié)果的代碼。計(jì)算機(jī)的狀態(tài)保存有一個(gè)缺陷,本機(jī)保留業(yè)務(wù)運(yùn)行結(jié)果有很大的問(wèn)題,一般都在外存儲(chǔ)設(shè)備上保存,也便于擴(kuò)展。

所以單個(gè)部署單元的代碼可以分為兩個(gè)部分,如下圖所示: 

架構(gòu)漫談(八):從架構(gòu)的角度看如何寫好代碼

從這個(gè)圖中可以看出,軟件代碼的相關(guān)利益人為運(yùn)行時(shí)的訪問(wèn)人員和存儲(chǔ)設(shè)備。而service的代碼是最復(fù)雜的,需要服務(wù)于三方,代碼人員的負(fù)擔(dān)是最重的。為了把這三方的變化對(duì)service的影響降到最低,對(duì)于service還必須進(jìn)一步的分拆為三個(gè)部分,讓每一個(gè)部分都能夠獨(dú)立的變化,這樣這三方的變化就不會(huì)產(chǎn)生連鎖響應(yīng),降低成本。如下圖所示: 

架構(gòu)漫談(八):從架構(gòu)的角度看如何寫好代碼

這樣,就劃分成了幾個(gè)責(zé)任:

Service就專注于user的需求,并組合Glue Code提供的服務(wù)完成需求。

Glue Code專注于組合business的調(diào)用,管理Business里面對(duì)象的生命周期,并且通過(guò)Repository保存或加載Business的狀態(tài)

Business專注于實(shí)現(xiàn)業(yè)務(wù)的核心模型。

Repository專注于數(shù)據(jù)的保存,并和存儲(chǔ)設(shè)備一一對(duì)應(yīng)。

大家注意看,還是樹形架構(gòu)。并且左側(cè)的主要需要計(jì)算機(jī)的相關(guān)理論知識(shí),并且要直接面對(duì)用戶的需求。右側(cè)的更多的需要面對(duì)業(yè)務(wù)的核心。只要這幾塊的開發(fā)人員互相商量好了接口定義,這幾個(gè)部分的開發(fā)就可以并行的進(jìn)行,極大的提升開發(fā)的效率,縮短開發(fā)的時(shí)間。要做好這幾部分,還需要注意,邏輯只允許存在于Business中,Service、Glue Code、Repository都不允許存在業(yè)務(wù)邏輯。為什么呢?首先我們來(lái)看看什么叫業(yè)務(wù)邏輯。

什么叫業(yè)務(wù)邏輯?

首先這個(gè)定義的前提是指軟件代碼中的邏輯,不是現(xiàn)實(shí)生活中的邏輯。在軟件代碼中,不需縮進(jìn)和計(jì)算的順序調(diào)用,包括縮進(jìn)的代碼目的是catch exception的,都不算邏輯,除此以外都是邏輯。以下用嚴(yán)格的順序調(diào)用來(lái)指代這種代碼。因?yàn)轫樞蛘{(diào)用是計(jì)算機(jī)的特性,由編譯器來(lái)決定的,當(dāng)然最本質(zhì)的是因?yàn)槲覀冇?jì)算的基礎(chǔ)都是圖靈機(jī)。在現(xiàn)實(shí)生活中,順序調(diào)用也是邏輯,大家不要和我們這里說(shuō)的業(yè)務(wù)邏輯相混淆。

為什么說(shuō)除了Business代碼中有邏輯以外,其他地方不能有邏輯呢? 我們每個(gè)部分分別分析:

如果service里面不是嚴(yán)格的順序調(diào)用,有很多分支,那么說(shuō)明這個(gè)service做了兩件或者兩件以上的事情。必須把這個(gè)service分拆,確保每個(gè)service只做一件事情。因?yàn)槿绻贿@么分拆的話,一旦這個(gè)service中的某各部分發(fā)生變動(dòng),其他的部分的執(zhí)行必定會(huì)受影響。而確定到底有哪些影響的溝通成本非常高,其他相關(guān)利益方?jīng)]有動(dòng)力去配合,我們往往不會(huì)投入精力仔細(xì)評(píng)估。最后上線會(huì)出很多不可預(yù)料的問(wèn)題,最終會(huì)導(dǎo)致?lián)p失用戶的利益,并且肯定會(huì)導(dǎo)致返工,損壞自己的利益。如果是有計(jì)算的邏輯的話,比如受益計(jì)算,訂單金額計(jì)算等,那么這部分應(yīng)該是Business代碼需要完成的,不能交給service代碼來(lái)實(shí)現(xiàn)。

Glue Code里面如果不是嚴(yán)格的順序調(diào)用,同理會(huì)和service一樣遇到同樣的問(wèn)題。

Repository里面如果不是嚴(yán)格的順序調(diào)用,包括存儲(chǔ)訪問(wèn)的代碼里面(比如SQL),會(huì)導(dǎo)致邏輯進(jìn)入到存儲(chǔ)設(shè)備中。存儲(chǔ)設(shè)備的主要目的是拿來(lái)存儲(chǔ)的,一旦變成了邏輯計(jì)算的主體,就會(huì)導(dǎo)致存儲(chǔ)設(shè)備無(wú)法通過(guò)增加機(jī)器的方式橫向擴(kuò)展長(zhǎng)大。這個(gè)時(shí)候就沒(méi)有架構(gòu)了,只能換性能更好的機(jī)器,這個(gè)叫scale up。只有scale out才能算架構(gòu)。

以上都會(huì)導(dǎo)致架構(gòu)無(wú)法快速的橫向擴(kuò)展和分拆,并且增加了修改的成本,這些是不符合開發(fā)人員以及業(yè)務(wù)的利益的。

這么做的好處有哪些呢?

Service、Glue Code、Repository里面的代碼是嚴(yán)格的順序調(diào)用,那么這些代碼只要做連通性測(cè)試即可,不需要單元測(cè)試。因?yàn)檫@些代碼都需要和很多上下文打交道,很難做單元測(cè)試。這樣才算是真正的組合。

Business不訪問(wèn)任何上下文,不訪問(wèn)任何具體的設(shè)備,所以這部分代碼是非常容易寫單元測(cè)試的,并且單元測(cè)試必須100%覆蓋。因?yàn)槠渌胤經(jīng)]有業(yè)務(wù)邏輯,所以一旦有問(wèn)題,就可以斷定是Model的問(wèn)題,單元測(cè)試肯定可以發(fā)現(xiàn)。如果單元測(cè)試沒(méi)有發(fā)現(xiàn)問(wèn)題,那么單元測(cè)試一定有問(wèn)題。線上問(wèn)題的模擬也就變得非常的簡(jiǎn)單,單元測(cè)試也能夠得到進(jìn)一步的補(bǔ)充。

Repository很容易按照存儲(chǔ)設(shè)備本身的最小訪問(wèn)粒度來(lái)完成工作,比如DB,完全可以做到單表訪問(wèn)。因?yàn)檫@個(gè)時(shí)候存儲(chǔ)設(shè)備只關(guān)心存取數(shù)據(jù),完全和業(yè)務(wù)沒(méi)有關(guān)系。做表的分拆也是非常容易的事情,存儲(chǔ)設(shè)備通過(guò)增加機(jī)器就可以橫向擴(kuò)展長(zhǎng)大。很多人會(huì)擔(dān)心說(shuō),沒(méi)有了join,訪問(wèn)DB的次數(shù)是不是更多了,會(huì)導(dǎo)致性能下降? 按照現(xiàn)在網(wǎng)絡(luò)的條件,網(wǎng)絡(luò)訪問(wèn)和Disk IO訪問(wèn)的差距已經(jīng)不大了,合理的設(shè)計(jì)下,多訪問(wèn)幾次DB并不會(huì)導(dǎo)致這個(gè)問(wèn)題。另外如果多臺(tái)DB的話,還能通過(guò)并行加速訪問(wèn)。

由于Service、Glue Code、Repository代碼簡(jiǎn)單了,才可以讓我們的開發(fā)人員投入更多的時(shí)間研究業(yè)務(wù),畢竟這部分才是軟件所真正服務(wù)的對(duì)象。

我們?cè)賮?lái)看一個(gè)實(shí)際的例子,如下圖所示: 

架構(gòu)漫談(八):從架構(gòu)的角度看如何寫好代碼

Manager類實(shí)際就是Glue Code。有幾個(gè)注意點(diǎn)需要說(shuō)明一下:

不能把Business Model當(dāng)做數(shù)據(jù)對(duì)象來(lái)處理,Model關(guān)心的實(shí)際上是業(yè)務(wù)行為,數(shù)據(jù)只是是這些行為的結(jié)果。所以Glue Code需要把Model轉(zhuǎn)換為Entity,Entity和存儲(chǔ)設(shè)備里面的存儲(chǔ)粒度一一對(duì)應(yīng)。比如在DB中,每個(gè)Entity對(duì)應(yīng)一張表,并且跟著表的變化而變化,這樣就保證存儲(chǔ)的變更不會(huì)影響Model。同樣Service和用戶之間的數(shù)據(jù)交互,也是不會(huì)和Model之間相關(guān)的,確保用戶的需求變化,不會(huì)影響到Model。因?yàn)橛脩舻男枨笞兓亲铑l繁的,沒(méi)有邏輯,可以讓我快速的滿足業(yè)務(wù)的需求。

在Service這里,最好不要考慮代碼重用。因?yàn)楫?dāng)多個(gè)不同的角色訪問(wèn)同一個(gè)接口,一旦某個(gè)角色的需求發(fā)生了變化,就會(huì)要求開發(fā)人員去修改。而這個(gè)修改往往會(huì)影響到其他的角色,需要這些角色一起配合來(lái)確定是否受影響,但是這些角色因?yàn)闆](méi)有需求,往往不會(huì)配合。這樣就給開發(fā)人員造成了很多不必要的溝通,成本是非常高的。最終都會(huì)導(dǎo)致線上Bug,影響最終的用戶。所以盡量給不同的角色不同的Service,避免重用,降低溝通成本。很多人會(huì)說(shuō)這樣Service不就太多了嗎? 這樣Service注冊(cè),查找等管理需求就出現(xiàn)了,Service治理中心就是來(lái)解決這個(gè)問(wèn)題的。因?yàn)镾ervice里面沒(méi)有邏輯,所以開發(fā)和管理非常的簡(jiǎn)單,可以快速應(yīng)對(duì)業(yè)務(wù)的變化。我們只有更快地變,更容易的變,才能更好地應(yīng)對(duì)變。

Business Model是必須要重用的,一旦發(fā)現(xiàn)重用出現(xiàn)問(wèn)題,那么說(shuō)明Business Model的識(shí)別出現(xiàn)了問(wèn)題,這是一個(gè)我們要重新思考Model的信號(hào)。Business Model必須是一個(gè)完美的樹狀,如果不是,也說(shuō)明Model的識(shí)別出了問(wèn)題。

在實(shí)際操作中,Service、Glue Code、Repository不能有邏輯,實(shí)際上和很多人的觀念是沖突的,認(rèn)為這個(gè)根本做不到。做到這一點(diǎn)需要很多的學(xué)習(xí)成本,但是一定可以做得到。當(dāng)發(fā)現(xiàn)做不到的時(shí)候,可以斷定是業(yè)務(wù)的分析出了問(wèn)題。比如不該合并的合并了,不該計(jì)算的計(jì)算了。這個(gè)問(wèn)題一定有辦法解決的,做不到都是理由,無(wú)非是想早點(diǎn)把自己的工作結(jié)束罷了。雖然剛開始會(huì)比較困難,一旦把這個(gè)觀念變成自覺(jué),開發(fā)的質(zhì)量和效率馬上就能高好幾個(gè)級(jí)別。

我的游泳教練曾和我說(shuō)過(guò)這些話,我至今記憶猶新:“業(yè)余選手,越想從水里浮起來(lái),就越想把頭抬起來(lái),身體反而沉下去。只有克服恐懼,把頭往水里壓下去,身體才能夠從水里浮起來(lái)。真正專業(yè)的習(xí)慣往往是和我們?nèi)粘5男袨橄喾吹?rdquo;。

我們真正想快速的完成代碼工作,就要克服自己對(duì)時(shí)間的恐懼,真正的去研究業(yè)務(wù)的問(wèn)題,相關(guān)stakeholder的利益,把這個(gè)變成我們的習(xí)慣。寫代碼的時(shí)候讓該出現(xiàn)邏輯的地方出現(xiàn)邏輯,讓不該出現(xiàn)的地方不能出現(xiàn)。一旦不該出現(xiàn)的地方出現(xiàn)了邏輯,那么要馬上意識(shí)到,這個(gè)地方是一個(gè)坑,這個(gè)問(wèn)題一定和業(yè)務(wù)的分析不透徹有關(guān)系。

很多人可能會(huì)把這個(gè)做法和Martin Fowler曾經(jīng)提出過(guò)充血模型和貧血模型來(lái)比較,和Domain Driven Design來(lái)比較,其實(shí)沒(méi)有必要。這個(gè)分拆完全是從軟件所解決的問(wèn)題,根據(jù)軟件架構(gòu)推導(dǎo)出來(lái)的,很多地方和兩位前輩的觀點(diǎn)是一致的,但是并不完全等同。

以上只是針對(duì)單一的Service部署單元的分析,擴(kuò)展開去,對(duì)于其他的部署單元也是類似的。每個(gè)單元的下一級(jí)都可以認(rèn)為是Repository,每個(gè)單元的上一級(jí)都可以認(rèn)為是User。這些實(shí)踐在我自己的項(xiàng)目中都有用到,非常的有效,迭代的速度非常的快。很多人擔(dān)心Business Model建不好,其實(shí)沒(méi)關(guān)系,剛開始可以粗糙一點(diǎn),后續(xù)可以慢慢的完善。這個(gè)架構(gòu)已經(jīng)隔離好了每個(gè)部分的變化對(duì)其他部分的影響,變化成本都在可控的范圍之內(nèi)。

 

責(zé)任編輯:武曉燕 來(lái)源: 咔咔侃技術(shù)
相關(guān)推薦

2021-10-13 08:16:14

SQL 代碼系統(tǒng)

2010-06-07 10:44:09

2019-04-18 14:24:52

技術(shù)互聯(lián)網(wǎng)架構(gòu)

2022-03-14 22:22:56

工程設(shè)計(jì)論代碼

2021-11-04 09:55:59

代碼編程語(yǔ)言

2020-09-30 08:08:15

單元測(cè)試應(yīng)用

2019-06-10 19:00:23

Cmain函數(shù)編程語(yǔ)言

2019-04-28 16:10:50

設(shè)計(jì)Redux前端

2022-03-09 15:48:13

Java代碼

2021-08-11 08:41:20

全棧開發(fā)技術(shù)架構(gòu)前端

2015-05-05 11:04:31

CoreOS自動(dòng)化運(yùn)維

2020-07-31 08:12:49

代碼機(jī)器設(shè)備

2024-12-10 00:00:10

MySQLJOIN算法

2020-02-04 09:53:05

數(shù)據(jù)安全數(shù)據(jù)泄漏信息安全

2009-07-01 08:49:34

架構(gòu)Web2.0Twitter

2011-06-12 09:08:46

字母索引

2012-04-29 10:37:28

APP

2010-07-16 09:00:20

開源RedOffice紅旗2000

2016-01-05 13:22:42

技術(shù)架構(gòu)SaaS客服平臺(tái)

2013-12-11 21:48:38

OpenStack
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)