Web先後端分離開發思路

做者:戴嘉華前端

轉載請註明出處,保留原文連接和做者信息程序員


1. 問題的提出

開發一個Web應用的時候咱們通常都會簡單地分爲前端工程師和後端工程師(注:在一些比較複雜的系統中,前端能夠細分爲外觀和邏輯,後端能夠分爲CGI和Server)。前端工程師負責瀏覽器端用戶交互界面和邏輯等,後端負責數據的處理和存儲等。先後端的關係能夠淺顯地歸納爲:後端提供數據,前端負責顯示數據。ajax

在這種先後端的分工下,會常常有一些疑惑:既然前端數據是由後端提供,那麼後端數據接口尚未完成,前端是否就沒法進行編碼?怎麼樣才能作到先後端獨立開發?後端

考慮這麼一個場景:Alex和Bob是一對好基友,他們有個能夠顛覆世界的idea,準備把它實現出來,可是他們不須要程序員,由於他們就是程序員。說幹就幹,兩個就幹上了。Alex寫前端,Bob寫後端。跨域

Alex和Bob都通過良好的訓練,循序漸進地把產品的主要功能設計,交互原型,視覺設計作好了,而後他們根據產品功能和交互制定了一堆叼炸天的先後端交互的API,這套API就相似於一套先後端開發的「協議」,Alex和Bob開發的時候都須要遵照。例如其中一個發表評論的功能:瀏覽器

// API: Create New Comment v2
// Ajax, JSON, RESTful
url: /comments
type: POST
request: {content: "comment content.", userId: 123456}
response: 
    - status: 200
        data: {result: "SUCCESS", msg: "The comment has been created."}
    - status: 404
        data: {result: "failed", msg: "User is not found."}

Alex的前端須要向/comments這個url以POST的方式發送相似於{content: "comment content.", userId: 123456}這樣的JSON請求數據;Bob的服務端識別後之後,操做成功則返回200狀態和上面的JSON的數據,不一樣的操做狀態有不一樣的響應數據(爲了簡單起見只列出了兩種,200和404)。服務器

API制定完之後,Alex和Bob就開始編碼了。Alex把評論都外觀和交互寫完了,可是寫到發表評論功能就納悶了:Alex如今須要發Ajax過去,可是隻能把Ajax代碼寫好,由於是本地服務器,卻沒法獲取到數據:前端工程師

// jQuery Ajax
$.ajax({ // 這個ajax直接報錯,由於這個是Alex的前端服務器,請求沒法獲取數據;
    url: "/comments",
    type: "POST",
    data: {content: content, userId: userId},
    success: funtion(data) {
        // 這裏不會被執行
    }
})

相比起來Bob就沒有這個煩惱,由於後端是基於測試驅動開發,且後端能夠輕易地模擬前端發送請求,能夠對前端沒有依賴地進行開發和測試。app

Alex把這種狀況和Bob說了,Bob就說,要不咱們把代碼弄到你本地先後端鏈接一下,這不就能夠測試了嗎。Alex以爲Bob簡直是天才。前後端分離

他們把先後端代碼代碼都部署到Alex的本地服務器之後,通過一系列的測試,調試,終於把這個API鏈接成功了。可是他們發現這個方法簡直不科學:難道每寫一個API都要把先後端連接測試一遍嗎?並且,Alex的若是須要測試某個API,而Bob的這個API還沒寫好,Alex這個功能模塊的進度就「阻塞」了。

後面還有168個API須要寫,不能這麼作。Alex和Bob就開始思考這個問題的解決方案。

2. 解決思路

在這個場景下,先後端是有比較強的數據依賴的關係,後端依賴前端的請求,前端依賴後端的響應。然後端能夠輕鬆模擬前端請求(基本上能寫後端的語言均可以直接發送HTTP請求),前端沒有一個比較明顯的方案來能夠作到模擬響應,因此這裏的須要解決的點就是:如何給前端模擬的響應數據

先來一句很是形而上的話:若是兩個對象具備強耦合的關係,咱們通常只要引入第三個對象就能夠打破這種強耦合的關係。

+---------+              +---------+
|         |              |         |
| Object1 |  <-------->  | Object2 |
|         |              |         |
+---------+              +---------+

               Before               


+---------+              +---------+
|         |              |         |
| Object1 |  <-- ✕ --->  | Object2 |
|         |              |         |
+---+-----+              +-----+---+
    |                          |    
    |                          |    
    |                          |    
    |                          |    
    |                          |    
    |       +---------+        |    
    |       |         |        |    
    +-----> | Object3 | <------+    
            |         |             
            +---------+             

               After

在咱們上述開發的過程當中,先後端的耦合性太強了,咱們須要藉助額外的東西來打破它們的耦合性。因此,在先後端接口定下來之後,咱們根據接口構建另一個Server,這個Server會一一響應前端的請求,而且根據接口返回數據。固然這些數據都是假數據。咱們把這個Server叫作Mock Server,而Bob真正在開發的Server叫作Real Server

+-------------------+                     +-------------------+
|                   | +-------- ✕ ------> |                   |
|     Browser       |                     |    Real Server    |
|                   | <---+               |                   |
+--------------+----+     |               +-------------------+
               |          |                                    
               |          |                                    
               |          |                                    
               |          |                                    
           Request      Response                               
               |          |                                    
               |          |                                    
               |          |                                    
               |     +----+--------------+                     
               +---> |                   |                     
                     |    Mock Server    |                     
                     |                   |                     
                     +-------------------+

Mock Server是根據API實現的,可是是沒有數據邏輯的,只是很是簡單地返回數據。例如上面Alex和Bob的發表評論的接口在Mock Server上是這樣的:

// Mock Server
// Create New Comment API
route.post("/comments", function(req, res) {
    res.send(200, {result: "Success"});
})

Alex在開發的時候向Mock Server發出請求,而不是向Bob的服務器發出請求:

// Sending Request to Mock Server
// jQuery Ajax
$.ajax({ 
    url: config.HOST + "/comments",
    type: "POST",
    data: {content: content, userId: userId},
    success: funtion(data) {
        // OK
    }
})

注意上面的config.HOST,咱們把服務器配置放在一個全局共用的模塊當中:

// Front-end Configuration Module
var config = modules.exports;
config.HOST = "http://192.169.10.20" // Mock Server IP

那麼上面咱們實際上是向IP爲http://192.169.10.20的Mock Server發出請求http://192.169.10.20/comments發出POST的請求。

當Alex和Bob都代碼寫好了之後,須要鏈接調試了,Alex只要簡單地改一下配置文件便可把全部的請求都轉向Bob所開發的Real Server:

// Front-end Configuration Module
var config = module.exports;
// config.HOST = "http://192.169.10.20" // Mock Server IP
config.HOST = "http://changing-world-app.com" // Real Server Domain

而後Alex和Bob就能夠愉快地分離獨立開發,而最後只須要聯合調試就能夠了。

總結一下基本上先後端分離開發包括下面幾個步驟:

  1. 根據功能制定先後端接口(API)。
  2. 根據接口構建Mock Server工程及其部署。
  3. 先後端獨立開發,前端向Mock Server發送請求,獲取模擬的數據進行開發和測試。
  4. 先後端都完成後,先後端鏈接調試(前端修改配置向Real Server而不是Mock Server發送請求)。

固然要注意,若是接口修改了,Mock Server要同步修改。

3. 實現方案

Mock Server具體應該如何構建?應該存放在哪裏?應該怎麼維護?

先後端是不一樣的兩個工程,它們各自佔用一個倉庫。Mock Server應該和它們分離出來,獨立進行開發和維護,也就是說會有三個倉庫,Mock Server是一個單獨的工程。

Mock Server能夠部署在本地,也能夠部署到遠程服務器,二者之間各有優劣。


3.1 遠程Mock Server

作法:把Mock Server工程部署到一個遠程的always on的遠程服務器上,前端開發的時候向該服務器發請求。

優勢

  1. 沒有給原有的先後端工程增長負擔。
  2. 每一個前端開發人員向同一個Mock Server服務器發送請求,保持全部人獲取響應請求的一致性。

缺點

  1. 有跨域問題(思考:locahost如何向192.169.10.20發請求?)。
  2. 須要額外的遠程服務器支持。

(在寫這篇博客的時候,逛Hacker News,恰好看到有人作了一個開發輔助工具(http://reqr.es/),能夠用於開發時響應前端請求,其實也就是這裏所說的遠程Mock Server。真是不能再巧更多。)

3.2 本地Mock Server

作法:前端把Mock Server克隆到本地,開發的時候,開啓前端工程服務器和Mock Server,全部的請求都發向本地服務器,獲取到Mock數據。

優勢

  1. 節約資源,不須要依賴遠程服務器。環保節能。
  2. 沒有跨域問題。

缺點

  1. 增長前端工程開發流程複雜程度。
  2. 每一個前端開發人員本身部署服務器在本地,可能會有倉庫沒有及時更新致使API不一致的狀況。

Mock Server工程通常能夠由後端開發人員來維護。由於在開發的過程當中,後端由於各類緣由可能須要修改API,後端人員是最熟悉請求的響應數據和格式的人,能夠同步維護Mock Server和Real Server,更好保證數據的一致。Mock Server維護起來並不複雜,對於比較大多工程來講,這樣的前期準備和過程的維護是很是值得的。

最後

因此要點就是:根據API構建能夠模擬服務器響應的Mock Server,用於前端請求模擬數據進行測試

再重複總結一下先後端分離開發包括下面幾個步驟:

  1. 根據功能制定先後端接口。
  2. 根據接口構建Mock Server工程及其部署。
  3. 先後端獨立開發,前端向Mock Server發送請求,獲取模擬的數據進行開發和測試。
  4. 先後端都完成後,先後端鏈接調試。

當開發只有我一我的的時候,我更喜歡後端獨立開發,開發前端的時候開個Real Server來作響應。又爽又快。其實若是團隊的人是full-stack的話,徹底能夠按照功能模塊來劃分任務,而不是分爲前端工程師和後端工程師。

但通常來講仍是會選擇先後端職能劃分,對於這種狀況下的多人開發的工程來講,先後端分離開發的方式確實須要考慮和構建的,能夠更好幫助咱們構建一個高效,規範化,流程化的開發流程。

仍是那句話,沒有銀彈,全部的東西都須要根據實際狀況來構建獨特的流程。

References

(全文完)

相關文章
相關標籤/搜索