日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
軟件項(xiàng)目的套路:從三明治到六邊形

1. 軟件項(xiàng)目的套路

創(chuàng)新互聯(lián)是專業(yè)的嵐皋網(wǎng)站建設(shè)公司,嵐皋接單;提供成都網(wǎng)站制作、成都網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行嵐皋網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!

如果你平時(shí)的工作是做各種項(xiàng)目(而不是產(chǎn)品),而且你工作的時(shí)間足夠長(zhǎng),那么自然見識(shí)過(guò)很多不同類型的項(xiàng)目。在切換過(guò)多次上下文之后,作為程序員的你,自然而然的會(huì)感到一定程度的重復(fù),稍加抽象,你會(huì)發(fā)現(xiàn)所有的業(yè)務(wù)系統(tǒng)都幾乎做著同樣的事情:

  • 從某種渠道與用戶交互,從而接受輸入(Native App,Mobile Site,Web Site,桌面應(yīng)用等等)
  • 將用戶輸入的數(shù)據(jù)按照一定規(guī)則進(jìn)行轉(zhuǎn)換,然后保存起來(lái)(通常是關(guān)系型數(shù)據(jù)庫(kù))
  • 將業(yè)務(wù)數(shù)據(jù)以某種形式展現(xiàn)(列表,卡片,地圖上的Marker,時(shí)間線等)

稍加簡(jiǎn)化,你會(huì)發(fā)現(xiàn)大部分業(yè)務(wù)系統(tǒng)其實(shí)就是對(duì)某種形式的資源進(jìn)行管理。所謂管理,也無(wú)非是增刪查改(CRUD)操作。比如知乎是對(duì)“問(wèn)題”這種資源的管理,LinkedIn是對(duì)“Profile”的管理,Jenkins對(duì)構(gòu)建任務(wù)的管理等等,粗略的看起來(lái)都是這一個(gè)套路(當(dāng)然,每個(gè)系統(tǒng)管理的資源類型可能不止一種,比如知乎還有時(shí)間線,Live,動(dòng)態(tài)等等資源的管理)。

這些情況甚至?xí)o開發(fā)者一種錯(cuò)覺:世界上所有的信息管理系統(tǒng)都是一樣的,不同的僅僅是技術(shù)棧和操作的業(yè)務(wù)對(duì)象而已。如果寫好一個(gè)模板,幾乎都可以將開發(fā)過(guò)程自動(dòng)化起來(lái)。事實(shí)上,有一些工具已經(jīng)支持通過(guò)配置文件(比如yaml或者json/XML)的描述來(lái)生成對(duì)應(yīng)的代碼的功能。

如果真是這樣的話,軟件開發(fā)就簡(jiǎn)單多了,只需要知道客戶業(yè)務(wù)的資源,然后寫寫配置文件,***執(zhí)行了一個(gè)命令來(lái)生成應(yīng)用程序就好了。不過(guò)如果你和我一樣生活在現(xiàn)實(shí)世界的話,還是趁早放棄這種完全自動(dòng)化的想法吧。

2. 復(fù)雜的業(yè)務(wù)

現(xiàn)實(shí)世界的軟件開發(fā)是復(fù)雜的,復(fù)雜性并不體現(xiàn)在具體的技術(shù)棧上。如Java,Spring,Docker,MySQL等等具體的技術(shù)是可以學(xué)習(xí)很快就熟練掌握的。軟件真正復(fù)雜的部分,往往是業(yè)務(wù)本身,比如航空公司的超售策略,在超售之后Remove乘客的策略等;比如亞馬遜的打折策略,物流策略等。

用軟件模型如何優(yōu)雅而合理的反應(yīng)復(fù)雜的業(yè)務(wù)(以便在未來(lái)業(yè)務(wù)發(fā)生變化時(shí)可以更快速,更低錯(cuò)誤的作出響應(yīng))本身也是復(fù)雜的。要將復(fù)雜的業(yè)務(wù)規(guī)則轉(zhuǎn)換成軟件模型是軟件活動(dòng)中非常重要的一環(huán),也是信息傳遞往往會(huì)失真的一環(huán)。業(yè)務(wù)人員說(shuō)的A可能被軟件開發(fā)者理解成Z,反過(guò)來(lái)也一樣。

舉個(gè)例子,我給租來(lái)的房子買了1年的聯(lián)通寬帶??墒沁^(guò)了6個(gè)月后,房東想要賣房子把我趕了出來(lái),在搬家之后,我需要通知聯(lián)通公司幫我做移機(jī)服務(wù)。

如果純粹從開發(fā)者的角度出發(fā),寫出來(lái)的代碼可能看起來(lái)是這樣的:

 
 
 
 
  1. public class Customer {
  2.   private String address;
  3.   public void setAddress(String address) {
  4.     this.address = address;
  5.   }
  6.      
  7.   public String getAddress() {
  8.     return this.address;
  9.   }
  10. }

中規(guī)中矩,一個(gè)簡(jiǎn)單的值對(duì)象。作為對(duì)比,通過(guò)與領(lǐng)域?qū)<业慕涣髦?,寫出?lái)的代碼會(huì)是這樣:

 
 
 
 
  1. public class Customer {
  2.   private String address;
  3.     public void movingHome(String address) {
  4.     this.address = address;
  5.   }
  6. }

通過(guò)引入業(yè)務(wù)場(chǎng)景中的概念movingHome,代碼就變得有了業(yè)務(wù)含義,除了可讀性變強(qiáng)之外,這樣的代碼也便于和領(lǐng)域?qū)<疫M(jìn)行交流和討論。Eric在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain Drvien Design)中將統(tǒng)一語(yǔ)言視為實(shí)施DDD的先決條件。

3. 層次架構(gòu)(三明治)

All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections.

-- David Wheeler

上文提到,業(yè)務(wù)系統(tǒng)對(duì)外的呈現(xiàn)是對(duì)某種資源的管理,而且,現(xiàn)實(shí)世界里的業(yè)務(wù)系統(tǒng)往往要對(duì)多種資源進(jìn)行管理。這些資源還會(huì)互相引用,互相交織。比如一個(gè)看板系統(tǒng)中的泳道、價(jià)值流、卡片等;LinkedIn中的公司,學(xué)校,個(gè)人,研究機(jī)構(gòu),項(xiàng)目,項(xiàng)目成員等,它們往往會(huì)有嵌套、依賴等關(guān)系。

為了管理龐大的資源種類和繁復(fù)的引用關(guān)系,人們自然而然的將做同樣事情的代碼放在了統(tǒng)一的地方。將不同職責(zé)的事物分類是人類在處理復(fù)雜問(wèn)題時(shí)自然使用的一種方式,將復(fù)雜的、龐大的問(wèn)題分解、降級(jí)成可以解決的問(wèn)題,然后分而治之。

比如在實(shí)踐中 ,展現(xiàn)部分的代碼只負(fù)責(zé)將數(shù)據(jù)渲染出來(lái),應(yīng)用部分的代碼只負(fù)責(zé)序列化/反序列化、組織并協(xié)調(diào)對(duì)業(yè)務(wù)服務(wù)的調(diào)用,數(shù)據(jù)訪問(wèn)層則負(fù)責(zé)屏蔽底層關(guān)系型數(shù)據(jù)庫(kù)的差異,為上層提供數(shù)據(jù)。

這就是層級(jí)架構(gòu)的由來(lái):上層的代碼直接依賴于臨近的下層,一般不對(duì)間接的下層產(chǎn)生依賴,層次之間通過(guò)精心設(shè)計(jì)的API來(lái)通信(依賴通常也是單向的)。

以現(xiàn)代的眼光來(lái)看,層次架構(gòu)的出現(xiàn)似乎理所應(yīng)當(dāng)、自然而然,其實(shí)它也是經(jīng)過(guò)了很多次的演進(jìn)而來(lái)的。以JavaEE世界為例,早期人們會(huì)把應(yīng)用程序中負(fù)責(zé)請(qǐng)求處理、文件IO、業(yè)務(wù)邏輯、結(jié)果生成都放在servlet中;后來(lái)發(fā)明了可以被Web容器翻譯成servlet的JSP,這樣數(shù)據(jù)和展現(xiàn)可以得到比較好的分離(當(dāng)然中間還有一些迂回,比如JSTL、taglib的濫用又導(dǎo)致很多邏輯被泄露到了展現(xiàn)層);數(shù)據(jù)存儲(chǔ)則從JDBC演化到了各種ORM框架,***再到JPA的大一統(tǒng)。

如果現(xiàn)在把一個(gè)Spring-Boot寫的RESTful后端,和SSH(Spring-Struts-Hibernate)流行的年代的后端來(lái)做對(duì)比,除了代碼量上會(huì)少很多以外,層次結(jié)構(gòu)上基本上并無(wú)太大區(qū)別。不過(guò)當(dāng)年在SSH中復(fù)雜的配置,比如大量的XML變成了代碼中的注解,容器被內(nèi)置到應(yīng)用中,一些配置演變成了慣例,大致來(lái)看,應(yīng)用的層次基本還是保留了:

  • 展現(xiàn)層
  • 應(yīng)用層
  • 數(shù)據(jù)訪問(wèn)層

在有些場(chǎng)景下,應(yīng)用層內(nèi)還可能劃分出一個(gè)服務(wù)層。

4. 前后端分離

隨著智能設(shè)備的大爆發(fā),移動(dòng)端變成了展現(xiàn)層的主力,如何讓應(yīng)用程序很容易的適配新的展現(xiàn)層變成了新的挑戰(zhàn)。這個(gè)新的挑戰(zhàn)驅(qū)動(dòng)出了前后端分離方式,即后端只提供數(shù)據(jù)(JSON或者XML),前端應(yīng)用來(lái)展現(xiàn)這些數(shù)據(jù)。甚至很多時(shí)候,前端會(huì)成為一個(gè)獨(dú)立的應(yīng)用程序,有自己的MVC/MVP,只需要有一個(gè)HTTP后端就可以獨(dú)立工作。

前后端分離可以很好的解決多端消費(fèi)者的問(wèn)題,后端應(yīng)用現(xiàn)在不區(qū)分前端的消費(fèi)者到底是誰(shuí),它既可以是通過(guò)4G網(wǎng)絡(luò)連接的iOS上的Native App,也可以是iMac桌面上的Chrome瀏覽器,還可以是Android上的獵豹瀏覽器。甚至它還可以是另一個(gè)后臺(tái)的應(yīng)用程序:總之,只要可以消費(fèi)HTTP協(xié)議的文本就可以了!

這不得不說(shuō)是一個(gè)非常大的進(jìn)步,一旦后端應(yīng)用基本穩(wěn)定,頻繁改變的用戶界面不會(huì)影響后端的發(fā)布計(jì)劃,手機(jī)用戶的體驗(yàn)改進(jìn)也與后端的API設(shè)計(jì)沒有任何關(guān)系,似乎一切都變的美好起來(lái)了。

5. 業(yè)務(wù)與基礎(chǔ)設(shè)施分離

不過(guò),如果有一個(gè)消費(fèi)者(一個(gè)業(yè)務(wù)系統(tǒng)),它根本不使用HTTP協(xié)議怎么辦?比如使用消息隊(duì)列,或者自定義的Socket協(xié)議來(lái)進(jìn)行通信,應(yīng)用程序如何處理這種場(chǎng)景? 這種情況就好比你看到了這樣一個(gè)函數(shù):

 
 
 
 
  1. httpService(request, response);

作為程序員,自然會(huì)做一次抽象,將協(xié)議作為參數(shù)傳入:

 
 
 
 
  1. service(request, response, protocol);

更進(jìn)一步,protocol可以在service之外構(gòu)造,并注入到應(yīng)用中,這樣代碼就可以適配很多種協(xié)議(比如消息隊(duì)列,或者其他自定義的Socket協(xié)議)。 比如:

 
 
 
 
  1. public interface Protocol {
  2.   void transform(Request request, Response response);
  3. }
  4. public class HTTP implements Protocol {
  5. }
  6. public class MyProtocol implements Protocol {
  7. }
  8. public class Service {  
  9.   public Service(Protocol protocol) {
  10.     this.protocol = protocol;   
  11.   }        
  12.    
  13.   public void service(request, response) {
  14.     //business logic here
  15.     protocol.transfrom(request, response);  
  16.   }
  17. }

類似的,對(duì)于數(shù)據(jù)的持久化,也可以使用同樣的原則。對(duì)于代碼中諸如這樣的代碼:

 
 
 
 
  1. persisteToDatabase(data);

在修改之后會(huì)變成:

 
 
 
 
  1. persistenceTo(data, repository);

應(yīng)用依賴倒置原則,我們會(huì)寫出這樣的形式:

 
 
 
 
  1. public class DomainService {
  2.   public BusinessLogic(Repository repository) {
  3.     this.repository = repository
  4.   }
  5.      
  6.     public void perform() {
  7.       //perform business logic
  8.       repository.save(record);
  9.   }
  10. }

對(duì)于Repository可能會(huì)有多種實(shí)現(xiàn)。根據(jù)不同的需求,我們可以自由的在各種實(shí)現(xiàn)中切換:

 
 
 
 
  1. public class InMemoryRepository implements Repository {}
  2. public class RDBMSRepository implements Repository {}

這樣業(yè)務(wù)邏輯和外圍的傳輸協(xié)議、持久化機(jī)制、安全、審計(jì)等等都隔離開來(lái)了,應(yīng)用程序不再依賴具體的傳輸細(xì)節(jié),持久化細(xì)節(jié),這些具體的實(shí)現(xiàn)細(xì)節(jié)反過(guò)來(lái)會(huì)依賴于應(yīng)用程序。

通過(guò)將傳統(tǒng)內(nèi)置在層次架構(gòu)中的數(shù)據(jù)庫(kù)訪問(wèn)層、通信機(jī)制等部分的剝離,應(yīng)用程序可以簡(jiǎn)單的分為內(nèi)部和外部?jī)纱蟛糠?。?nèi)部是業(yè)務(wù)的核心,也就是DDD(Domain Driven Design)中強(qiáng)調(diào)的領(lǐng)域模型(其中包含領(lǐng)域服務(wù),對(duì)業(yè)務(wù)概念的建立的模型等);外部則是類似RESTful API,SOAP,AMQP,或者數(shù)據(jù)庫(kù),內(nèi)存,文件系統(tǒng),以及自動(dòng)化測(cè)試。

這種架構(gòu)風(fēng)格被稱為六邊形架構(gòu),也叫端口適配器架構(gòu)。

6. 六邊形架構(gòu)(端口適配器)

六邊形架構(gòu)最早由Alistair Cockburn提出。在DDD社區(qū)得到了發(fā)展和推廣,然后IDDD(《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》)一書中,作者進(jìn)行了比較深入的討論。

簡(jiǎn)而言之,在六邊形架構(gòu)風(fēng)格中,應(yīng)用程序的內(nèi)部(中間的橙色六邊形)包含業(yè)務(wù)規(guī)則,基于業(yè)務(wù)規(guī)則的計(jì)算,領(lǐng)域?qū)ο?,領(lǐng)域事件等。這部分是企業(yè)應(yīng)用的核心:比如在線商店里什么樣的商品可以打折,對(duì)那種類型的用戶進(jìn)行80%的折扣;取消一個(gè)正在執(zhí)行的流水線會(huì)需要發(fā)生什么動(dòng)作,刪除一個(gè)已經(jīng)被別的Job依賴的Stage又應(yīng)該如何處理。

而外部的,也是我們平時(shí)最熟悉的諸如REST,SOAP,NoSQL,SQL,Message Queue等,都通過(guò)一個(gè)端口接入,然后在內(nèi)外之間有一個(gè)適配器組成的層,它負(fù)責(zé)將不同端口來(lái)的數(shù)據(jù)進(jìn)行轉(zhuǎn)換,翻譯成領(lǐng)域內(nèi)部可以識(shí)別的概念(領(lǐng)域?qū)ο?,領(lǐng)域事件等)。

內(nèi)部不關(guān)心數(shù)據(jù)從何而來(lái),不關(guān)心數(shù)據(jù)如何存儲(chǔ),不關(guān)心輸出時(shí)JSON還是XML,事實(shí)上它對(duì)調(diào)用者一無(wú)所知,它可以處理的數(shù)據(jù)已經(jīng)是經(jīng)過(guò)適配器轉(zhuǎn)換過(guò)的領(lǐng)域?qū)ο罅恕?/p>

六邊形架構(gòu)的優(yōu)點(diǎn):

  • 業(yè)務(wù)領(lǐng)域的邊界更加清晰
  • 更好的可擴(kuò)展性
  • 對(duì)測(cè)試的友好支持
  • 更容易實(shí)施DDD

要新添加一種數(shù)據(jù)庫(kù)的支持,或者需要將RESTful的應(yīng)用擴(kuò)展為支持SOAP,我們只需要定義一組端口-適配器即可,對(duì)于業(yè)務(wù)邏輯部分無(wú)需觸碰,而且對(duì)既有的端口-適配器也不會(huì)有影響。

由于業(yè)務(wù)之外的一切都屬于外圍,所以應(yīng)用程序是真的跑在了Web容器中還是一個(gè)Java進(jìn)程中其實(shí)是無(wú)所謂的,這時(shí)候自動(dòng)化測(cè)試會(huì)容易很多,因?yàn)闇y(cè)試的重點(diǎn):業(yè)務(wù)邏輯和復(fù)雜的計(jì)算都是簡(jiǎn)單對(duì)象,也無(wú)需容器,數(shù)據(jù)庫(kù)之類的環(huán)境問(wèn)題,單元級(jí)別的測(cè)試就可以覆蓋大部分的業(yè)務(wù)場(chǎng)景。

這種架構(gòu)模式甚至可能影響到團(tuán)隊(duì)的組成,對(duì)業(yè)務(wù)有深入理解的業(yè)務(wù)專家和技術(shù)專家一起來(lái)完成核心業(yè)務(wù)領(lǐng)域的建模及編碼,而外圍的則可以交給新人或者干脆外包出去。

在很多情況下,從開發(fā)者的角度進(jìn)行的假設(shè)都會(huì)在事后被證明是錯(cuò)誤的。人們?cè)陬A(yù)測(cè)軟件未來(lái)演進(jìn)方向時(shí)往往會(huì)做很多錯(cuò)誤的決定。比如對(duì)關(guān)系型數(shù)據(jù)庫(kù)的選用,對(duì)前端框架的選用,對(duì)中間件的選用等等,六邊形架構(gòu)可以很好的幫助我們避免這一點(diǎn)。

7. 小結(jié)

軟件的核心復(fù)雜度在于業(yè)務(wù)本身,我們需要對(duì)業(yè)務(wù)本身非常熟悉才可能正確的為業(yè)務(wù)建模。通過(guò)統(tǒng)一的語(yǔ)言我們可以編寫出表意而且易于和業(yè)務(wù)人員交流的模型。

另一方面模型應(yīng)該盡可能的和基礎(chǔ)設(shè)施(比如JSON/XML的,數(shù)據(jù)庫(kù)存儲(chǔ),通信機(jī)制等)分離開。這樣一來(lái)可以很容易用mock的方式來(lái)解耦模型和基礎(chǔ)設(shè)施,從而更容易測(cè)試和修改,二來(lái)我們的領(lǐng)域模型也更獨(dú)立,更精簡(jiǎn),在適應(yīng)新的需求時(shí)修改也會(huì)更容易。

【本文是專欄作者“ThoughtWorks”的原創(chuàng)稿件,微信公眾號(hào):思特沃克,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】


文章標(biāo)題:軟件項(xiàng)目的套路:從三明治到六邊形
當(dāng)前網(wǎng)址:http://www.5511xx.com/article/dhsggso.html