1. 程式人生 > >Web前後端:如何分離,如何解耦?

Web前後端:如何分離,如何解耦?

摘要:在本文中我們一起來探討一下為什麼要在軟體開發中進行前後端的分離,如何做到前後端分離,如何解耦。

簡單地說,就是要把複雜的問題簡單化,把一個從0到N的問題轉化為N個0到1的問題。另一個相近的說法就是“解耦”。

舉個例子,我們接到一個客戶需求,要求寫一個應用,這個應用中有頁面的切換,有對應頁面的資料互動,資料的獲取,資料的計算,如果把這些功能放在一個單一的應用中的話,從大局觀的角度來看,這個單一的應用是比較複雜的。

為了降低這個複雜度,我們首先要做的就是前後端分開,關於前後端的定義,大體來說是這樣的:前端負責的內容主要有頁面路徑管理,頁面對應資料的顯示與管理等等;後端負責的內容主要有資料的提供,資料的計算,安全性管理等等;前後端的通訊一般通過HTTP請求來實現;當然這裡也有個例外情況,比如有一部分功能可能要求實時性,像類似聊天類的功能,共享文件的功能,畫板分享的功能,多人協同操作的功能等等,需要通過socketio這樣的通訊機制進行。

再細分一下講,單一的程式框架模型會是MVC(Model-View-Controller)結構的。前後端分離以後,後端會有Model/Entity-Repository/Service-Controller,前端會有View-Model-API呼叫。

看一下前端部分,View主要是指網頁的頁面,手機端的頁面(Android就是Activity,Layout和View等, iOS就是View Controller和UIView等),如果使用跨平臺技術(如React Native, Flutter,Xamarin等)也離不開上述的概念,大同小異。這部分的處理當然離不開資料Model和API呼叫。處理好這些以後前端的任務也就做好了。

再看一下後端部分,介面相關的處理已經不再是後端的任務了,後端只需要通過API提供前端需要的資料就可以了。Controller就是用來定義這些API的,這一部分會分析或者計算出前端的輸入和輸出模型,具體處理方式有以下幾個因素考慮:請求的型別如GET,POST, PUT, DELTE,PATCH等;資料From Body,資料From Route,資料From Form等等;資料處理完成以後,一個是通過API返回,一個是更新資料來源,這裡的資料來源可以是資料庫如SQL和NoSQL,可以是訊息中介軟體如Kafka,也可以是資料緩衝伺服器如Redis等等。通過上述的描述,我們可以看到後端的任務變得更加輕量級了,邏輯上也更加簡單了。

所以,通過前後端的分離,我們把前端和後端的複雜度始終維持在可控的範圍內。如果在軟體開發中始終使用這種理念的話,我們會大大擴充套件我們的軟體開發效率和程式質量。因為解決一個N難度的問題顯然要比解決N個1難度問題要困難得多。對於一個N難度的問題,我們將其分解為N個1難度的問題之後,我們可以各個擊破,步步為營,一步一個腳印,在工作中從容而且自信,因為我們始終用最簡單的方法去解決問題。如果碰上覆雜的問題,就再將其分化為多個難度為1的問題,以此類推。簡單一些講,就是要保證我們在解決問題的時候,不打無準備之仗,始終腳踏實地,分而治之,避免把我們自己架到火爐上烤。

複雜度降低以後,整個專案的維護成本和擴充套件成本都會非常的低。我們對專案開發的駕馭能力也會提高很多。

再說一個數據流向的問題,這個主要發生在前端。 這部分的處理會直接關聯到前端程式設計的複雜度。在三大前端框架中有雙向資料流向和單向資料流向,其中React只支援單向資料流向。但是目前有了Hooks機制以後,你可以通過傳Setter和Getter兩個Reference來達到修改資料的目的。這種通過傳遞引數到其他Component的模式實際上增加了程式的複雜度,因為一層層的傳遞使得元件之間的耦合性增強了。

那麼如何解決這個問題呢?

在Angular中可以通過Service中定義Getter和Setter來解決這個問題,每個需要操作這個資料的元件都可以依賴注入這個Service,有了這個Service,就可以很輕鬆的讀取和更新其中的資料了,對於資料的監聽,可以通過在Service定義一個Subject,監聽到資料變化以後,你可以更新介面,向伺服器傳送請求等等,這樣做,元件之間的耦合性就大大降低了。

再說一下單向資料流向機制如Ngrx, VueX, Mux等等。單向資料流向機制在目前的前端開發中使用很普遍,然而,實際上這種機制會增加程式的複雜度。這個主要是因為這種機制會在前端開發層級中引入另外一套體系來維護資料的流向,假如我們對已有的業務定義為從0到1的實現,加上這個機制以後,就變成了0到1再加上另外一個0到1,變成了0到2的問題。這就變複雜了。

前端只要做好如下的任務如頁面的切換,資料與後端的互動,資料模型與API的對應, 元件儘量的寫成Self-Contained就可以了。

所以我不建議在前端中再額外的新增類似的資料流向機制了。

再談一下後端的分析。我們在談後端的時候,我們不太關心使用什麼技術(Node JS,.net Core,SpringBoot,PHP, Python, Ruby On Rails等等),這是因為後端的邏輯是清晰的,不管你用那種技術,程式的設計的層級是大同小異的。

後端的主要任務是API資料的提供。比如使用者相關的API,建立一個使用者,更新一個使用者,刪除一個使用者等等的操作都是在一個使用者Controller定義相關的API。對於Controller的新增,我建議要根據業務層來新增,不要在一個Controller中做太多的事情。比如我們可以新增Book Controller來處理Book相關的操作,訂單Controller來處理訂單相關的操作。

這樣做是為了把API設計變成線性的,平行的,各自Controller之間的耦合性降到最低,從而也就降低了複雜度。

進一步說,在實現的層級上,我們可以有Data Set對應資料庫表格,Entity對應資料表格記錄,Model對應API資料模型,Service/Repository負責邏輯實現等等。

在後端技術選取中,資料庫相關的操作是一個不可逾越的門檻,有的框架使用類似EntityFramework的機制如.NetCore和PHP Laravel, 有的使用類似JPA Hibernate,Mybatis如Spring Boot,有的則直接使用JDBC SQL語句執行的方式,有的結合Stored Procedure。在這個地方,按照程式複雜度排序的話,由低到高分別是EntityFrameWork<JPA Hibernate+Mybatis< JDBC SQL < Stored Procedure。

當然,資料庫的設計,資料庫的升級Migration也都是關係到程式專案複雜度的因素。這個要結合具體的後端技術來談。在本文中我們就不展開了。

好了,本文我們主要探討了前後端分離的作用,如何進行前後端分離,如何解耦,有不足之處,請不吝指正。

點選關注,第一時間瞭解華為雲新鮮技