NO IMAGE

轉自:https://www.zybuluo.com/jtong/note/480426

(本文不適合初學者閱讀,目前只是為了方便培訓的時候預習而寫,也不適合無後續服務的人閱讀) 
現在,我們把上一篇的應用變成網路版。這個時候,你至少有了兩個應用,一個客戶端應用,一個服務端應用。到這一刻,我們就算具有了一個系統。

當我們有一個系統的時候,我們需要一種框架來簡化思考我們的應用。這裡又需要我們再次展示我們的概念性思考能力,這時我會採用Linux的模型來思考這個問題,所以應用程式一般我會分為三層:

layer-of-application.png-307.5kB

core層是我的核心邏輯,核心的計算部分放在這裡。(Linux裡是Kernel,不過Kernel這詞比較偏門,咱們這教程的目標是為了儘量降低門檻,還是用core吧) 
shell層是我連結核心層和使用者的地方,你可以簡單理解為解析使用者輸入,包裝核心層的計算結果,變成使用者看到的輸出。Shell層還有一個作用,當我們有多個應用的時候,彼此之間的shell層是互相互動的,Core層是互相不知道彼此的存在的。 
config層比較難理解,從工程的角度,我們的Core層和Shell層,都不應該控制彼此的生命週期,它們所有的依賴都應該是外部配置的,它們只依賴抽象的介面而不是具體實現。config層就是這一層配置,在Linux的Shell裡對應的就是環境變數這個概念。

引入這些概念有什麼好處呢?如果用這些概念來解釋我們的應用,可以支撐非常大的架構的思考。

我們想象一下,系統隨著演進而變大,出現原本的小東西也會變的非常龐大。比如上一篇main函式裡的幾行程式碼,隨著系統變大,相應的Router也不可能自己寫了,Router和Command的關係自然也是在檔案裡配置的,慢慢的我們就開始需要一個IOC容器。Service本身會變得很複雜,彼此之間可能會有關係,而且甚至可能是別的應用提供的Service。如果我們再使用應用框架裡的概念,那麼思考也好,交流也好,都會變得很低效。所以我們才引出了config,shell,core這三個概念來簡化應用的內部,這樣就可以思考大量的應用之間的關係是應該是一個什麼樣的架構了,不過這個方向是一個更復雜的問題,這裡就不展開了。

回到我們的系統上,在一個剛剛出現了前後端概念的系統裡,我們的新概念們能幫助我們理解架構的演進,下面就基於這些概念帶著大家推演一遍現代常用的一些軟體框架是因為哪些力量驅動出來的。

Core的重新定義

當我們把系統分為客戶端和服務端的時候,那麼客戶端要做什麼呢?服務端要做什麼呢?

往往客戶端是需要更多的照顧使用者體驗,填平服務端的介面和使用者體驗之間的溝壑。

服務端則要保證資料讀寫的效能,安全性和易於被客戶端使用。

從這兩點來看,客戶端應該考慮的是使用者體驗,而不是讓使用者體驗為服務端扭曲。所以客戶端的core層更多的是那層填平服務端介面和使用者體驗之間溝壑的那堆程式碼,而它給shell的介面應該是以shell好呼叫為導向的。

那麼怎麼算是好用呢?

邊界與無限

剛才談到,在我們的邊界處,好用是一個非常重要的需求。怎麼算好用呢?最重要的是邊界要找對,如果你過界了,做了事情也會被埋怨。當我們思考系統的時候,邊界往往是不好找的。這就需要引入一個新的架構模式: MVC。

所謂的MVC就是Model-View-Controller。一個常見系統,往往Model層負責核心基本元素和基本演算法,View層負責展示和表達資料,Controller層負責排程和組合,把Model層和View層連線在一起。

一般來講,Model層通常是我們的Core,Controller層往往就是我們的shell,View層就是shell返回的資料。這個時候邊界的思考就清楚了,誰是我們的model和model相關的核心計算,誰就是我們的core。誰是我們的Controller負責排程組合和內外相連,誰就是我們的shell。而我們的計算結果,也就是我們的View層,是會離開我們的應用供別人使用的,那它是我們的最外面的邊界。我們思考邊界只需要關注在View層,思考清楚我們的View是否在一個抽象層次上就可以了。

但是,世界不是這麼簡單的分三層就可以結束了,世界是往復迴圈以致無窮的。所以我們的MVC也是迴圈迭代的,也就是說MVC中的某一層還可能再分MVC。那麼是哪一層呢?View層。還記得我們第一篇講得,資料和過程是不嚴格區分的,所以我們返回的資料,可以被解析為新的過程,新的過程再產生新的資料,從而往復迴圈以致無窮。

MVC.png-71.1kB

所以可以認為服務端是原應用的Core層進化出來的。

如果我們把View層進化下去,我們前面提到的客戶端的Shell返回的資料,還會再劃分,就會有新的元件層(Component),模版層(Layout),頁面層(Page,也有人愛用Container)等等。

隨著出現了MVC,再進一步思考就會逐漸發現,其實core層不應該關心後端程式碼,它應該關心前端的領域物件,以使用者眼中的模型為基礎計算,而不是後端業務人員眼中的模型為基礎來計算。所以他會把彌合後端和前端的工作交給shell層,而shell層會夾在三方面很難受,他一方面要對接後端,一方面要對接core,還有一方面要適配真正的前端模型。前端和後端的拉鋸戰就會出現,在這股力量的擠壓之下,我們的BFF就會自然而然的出現,所謂的前後端分離也就是自然而然的事情了。

題外話

題外話1

對於有經驗的同學要說一句:資料庫不是核心,你的程式碼才是核心。資料庫就是系統的另外一個應用而已,雖然資料庫廠商希望你把核心放在它裡面,但你不要被廠商的策略綁架了你的自由。

題外話2

物件導向,有一位同學總是在給我糾結這個物件導向怎麼畫。其實之所以有此問並不是不知道怎麼用強型別語言來畫圖,如我們第二篇所述,你換成類圖也是一樣的。主要的糾結點在於,那個函式放在哪個類裡這個問題。

之所以一直沒講,是因為物件導向是純粹的人類思考問題的方式,它是非常不精確的,把哪個函式放在哪個類裡這個事情是一門藝術而不是一門科學。當我們有一個Dog類的時候,有一個bark方法是非常明顯的。當我們有一個貨物類(Goods)的時候,算稅應該是它的方法嗎?當我們有一個資料庫實體的時候,比如User,Item等等,那麼儲存算他的方法嗎?如果我們做一個CRM系統,Client明顯跟所有的業務都有關係,總不能Client這個類上有所有業務的方法吧?所以我們無論怎麼放,都可能是有問題的,而且在變化來臨前,我們沒有什麼客觀的標準來判斷當前的做法是否合理。

如果只是畫圖來表達的話,其實我們的方塊上,也表達出了哪個函式屬於哪個類,這樣已經便於有經驗的人發現問題並解決問題了。只是沒有任何客觀的公式可以幫助大家輕鬆的解決問題。我們只能幫你這麼多了,畢竟方法,從來也不是為弱者服務的。

題外話3

你這個是不是六邊形架構? 
其實可以看作是六邊形架構的一種變種,我只是比較討厭六邊形這個詞,它太容易讓人糾結為啥是六個邊,不是八個?比如我叫八卦可不可以?所以我們也不要太糾結他叫什麼,領會精神就好。