中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

從架構(gòu)的角度看,如何寫好代碼?

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬Linux鏡像隨意使用

軟件架構(gòu)實(shí)際上包括:代碼架構(gòu),以及承載代碼運(yùn)行的硬件部署架構(gòu)。實(shí)際上,硬件部署架構(gòu)最終還是由代碼的架構(gòu)來決定。

因?yàn)榇a架構(gòu)不合理,是無法把一個(gè)運(yùn)行單元分拆出多個(gè)來的,那么硬件架構(gòu)能分拆的就非常的有限,整個(gè)系統(tǒng)最終很難長的更大。

所以我們經(jīng)常會(huì)聽說,重寫代碼,推翻原有架構(gòu),重新設(shè)計(jì)等等說法,來說明架構(gòu)的進(jìn)化。

這實(shí)際上就是當(dāng)初為了完成任務(wù),沒有充分思考所帶來的后果。這也并不是架構(gòu)進(jìn)化的事情,而是個(gè)人對(duì)問題領(lǐng)域的逐漸深入理解的過程。

所以有必要再討論一下,代碼的架構(gòu)應(yīng)該是怎樣的。

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

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

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

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

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

從這個(gè)圖中可以看出,軟件代碼的相關(guān)利益人為運(yùn)行時(shí)的訪問人員和存儲(chǔ)設(shè)備。而service的代碼是最復(fù)雜的,需要服務(wù)于三方,代碼人員的負(fù)擔(dān)是最重的。

為了把這三方的變化對(duì)service的影響降到最低,對(duì)于service還必須進(jìn)一步的分拆為三個(gè)部分,讓每一個(gè)部分都能夠獨(dú)立的變化,這樣這三方的變化就不會(huì)產(chǎn)生連鎖響應(yīng),降低成本。如下圖所示:

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

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

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

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

  2. 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ù)邏輯。為什么呢?首先我們來看看什么叫業(yè)務(wù)邏輯。


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

首先這個(gè)定義的前提是指軟件代碼中的邏輯,不是現(xiàn)實(shí)生活中的邏輯。在軟件代碼中,不需縮進(jìn)和計(jì)算的順序調(diào)用,包括縮進(jìn)的代碼目的是catch exception的,都不算邏輯,除此以外都是邏輯。

以下用嚴(yán)格的順序調(diào)用來指代這種代碼。因?yàn)轫樞蛘{(diào)用是計(jì)算機(jī)的特性,由編譯器來決定的,當(dāng)然最本質(zhì)的是因?yàn)槲覀冇?jì)算的基礎(chǔ)都是圖靈機(jī)。

在現(xiàn)實(shí)生活中,順序調(diào)用也是邏輯,大家不要和我們這里說的業(yè)務(wù)邏輯相混淆。

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

  1. 如果service里面不是嚴(yán)格的順序調(diào)用,有很多分支,那么說明這個(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ù)料的問題,最終會(huì)導(dǎo)致?lián)p失用戶的利益,并且肯定會(huì)導(dǎo)致返工,損壞自己的利益。如果是有計(jì)算的邏輯的話,比如受益計(jì)算,訂單金額計(jì)算等,那么這部分應(yīng)該是Business代碼需要完成的,不能交給service代碼來實(shí)現(xiàn)。

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

  3. Repository里面如果不是嚴(yán)格的順序調(diào)用,包括存儲(chǔ)訪問的代碼里面(比如SQL),會(huì)導(dǎo)致邏輯進(jìn)入到存儲(chǔ)設(shè)備中。

    存儲(chǔ)設(shè)備的主要目的是拿來存儲(chǔ)的,一旦變成了邏輯計(jì)算的主體,就會(huì)導(dǎo)致存儲(chǔ)設(shè)備無法通過增加機(jī)器的方式橫向擴(kuò)展長大。這個(gè)時(shí)候就沒有架構(gòu)了,只能換性能更好的機(jī)器,這個(gè)叫scale up。只有scale out才能算架構(gòu)。

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

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

  2. Business不訪問任何上下文,不訪問任何具體的設(shè)備,所以這部分代碼是非常容易些單元測(cè)試的,并且單元測(cè)試必須100%覆蓋。

    因?yàn)槠渌胤經(jīng)]有業(yè)務(wù)邏輯,所以一旦有問題,就可以斷定是Model的問題,單元測(cè)試肯定可以發(fā)現(xiàn)。如果單元測(cè)試沒有發(fā)現(xiàn)問題,那么單元測(cè)試一定有問題。線上問題的模擬也就變得非常的簡(jiǎn)單,單元測(cè)試也能夠得到進(jìn)一步的補(bǔ)充。

  3. Repository很容易按照存儲(chǔ)設(shè)備本身的最小訪問粒度來完成工作,比如DB,完全可以做到單表訪問。

    因?yàn)檫@個(gè)時(shí)候存儲(chǔ)設(shè)備只關(guān)心存取數(shù)據(jù),完全和業(yè)務(wù)沒有關(guān)系。做表的分拆也是非常容易的事情,存儲(chǔ)設(shè)備通過增加機(jī)器就可以橫向擴(kuò)展長大。很多人會(huì)擔(dān)心說,沒有了join,訪問DB的次數(shù)是不是更多了,會(huì)導(dǎo)致性能下降?

    按照現(xiàn)在網(wǎng)絡(luò)的條件,網(wǎng)絡(luò)訪問和Disk IO訪問的差距已經(jīng)不大了,合理的設(shè)計(jì)下,多訪問幾次DB并不會(huì)導(dǎo)致這個(gè)問題。另外如果多臺(tái)DB的話,還能通過并行加速訪問。

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

我們?cè)賮砜匆粋(gè)實(shí)際的例子,如下圖所示:

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

  1. 不能把Business Model當(dāng)做數(shù)據(jù)對(duì)象來處理,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繁的,沒有邏輯,可以讓我快速的滿足業(yè)務(wù)的需求。

  2. 在Service這里,最好不要考慮代碼重用。因?yàn)楫?dāng)多個(gè)不同的角色訪問同一個(gè)接口,一旦某個(gè)角色的需求發(fā)生了變化,就會(huì)要求開發(fā)人員去修改。

    而這個(gè)修改往往會(huì)影響到其他的角色,需要這些角色一起配合來確定是否受影響,但是這些角色因?yàn)闆]有需求,往往不會(huì)配合。這樣就給開發(fā)人員造成了很多不必要的溝通,成本是非常高的。

    最終都會(huì)導(dǎo)致線上Bug,影響最終的用戶。所以盡量給不同的角色不同的Service,避免重用,降低溝通成本。很多人會(huì)說這樣Service不就太多了嗎? 這樣Service注冊(cè),查找等管理需求就出現(xiàn)了,Service治理中心就是來解決這個(gè)問題的。

    因?yàn)镾ervice里面沒有邏輯,所以開發(fā)和管理非常的簡(jiǎn)單,可以快速應(yīng)對(duì)業(yè)務(wù)的變化。我們只有更快地變,更容易的變,才能更好地應(yīng)對(duì)變。

  3. Business Model是必須要重用的,一旦發(fā)現(xiàn)重用出現(xiàn)問題,那么說明Business Model的識(shí)別出現(xiàn)了問題,這是一個(gè)我們要重新思考Model的信號(hào)。

    Business Model必須是一個(gè)完美的樹狀,如果不是,也說明Model的識(shí)別出了問題。

在實(shí)際操作中,Service、Glue Code、Repository不能有邏輯,實(shí)際上和很多人的觀念是沖突的,認(rèn)為這個(gè)根本做不到。做到這一點(diǎn)需要很多的學(xué)習(xí)成本,但是一定可以做得到。

當(dāng)發(fā)現(xiàn)做不到的時(shí)候,可以斷定是業(yè)務(wù)的分析出了問題。比如不該合并的合并了,不該計(jì)算的計(jì)算了。這個(gè)問題一定有辦法解決的,做不到都是理由,無非是想早點(diǎn)把自己的工作結(jié)束罷了。

雖然剛開始會(huì)比較困難,一旦把這個(gè)觀念變成自覺,開發(fā)的質(zhì)量和效率馬上就能高好幾個(gè)級(jí)別。

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

我們真正想快速的完成代碼工作,就要克服自己對(duì)時(shí)間的恐懼,真正的去研究業(yè)務(wù)的問題,相關(guān)stakeholder的利益,把這個(gè)變成我們的習(xí)慣。

寫代碼的時(shí)候讓該出現(xiàn)邏輯的地方出現(xiàn)邏輯,讓不該出現(xiàn)的地方不能出現(xiàn)。一旦不該出現(xiàn)的地方出現(xiàn)了邏輯,那么要馬上意識(shí)到,這個(gè)地方是一個(gè)坑,這個(gè)問題一定和業(yè)務(wù)的分析不透徹有關(guān)系。

很多人可能會(huì)把這個(gè)做法和Martin Fowler曾經(jīng)提出過充血模型和貧血模型來比較,和Domain Driven Design來比較,其實(shí)沒有必要。

這個(gè)分拆完全是從軟件所解決的問題,根據(jù)軟件架構(gòu)推導(dǎo)出來的,很多地方和兩位前輩的觀點(diǎn)是一致的,但是并不完全等同。

以上只是針對(duì)單一的Service部署單元的分析,擴(kuò)展開去,對(duì)于其他的部署單元也是類似的。每個(gè)單元的下一級(jí)都可以認(rèn)為是Repository,每個(gè)單元的上一級(jí)都可以認(rèn)為是User。

這些實(shí)踐在我自己的項(xiàng)目中都有用到,非常的有效,迭代的速度非常的快。很多人擔(dān)心Business Model建不好,其實(shí)沒關(guān)系,剛開始可以粗糙一點(diǎn),后續(xù)可以慢慢的完善。

這個(gè)架構(gòu)已經(jīng)隔離好了每個(gè)部分的變化對(duì)其他部分的影響,變化成本都在可控的范圍之內(nèi)。


標(biāo)簽: 代碼 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:什么是架構(gòu)?

下一篇:軟件開發(fā)所經(jīng)歷的生命周期