前后端不分離,是怎樣的?大概也只有我們這些『老古董』們,才對此有更多感受。不對,那些寫 React 的人,可能會對此也有一些體會。
今天,如果有一個前端工程師說,不知道前后端分離是什么。那么,要么是剛畢業(yè)不久的,要么是從老版的公司里出來的員工,要么是剛從時光機里出來的。
前后端分離
我剛開始接觸前后端分離的時候,正值它開始慢慢擴散的時候,也還沒有意識到它帶來的好處。覺得它甚是麻煩,當(dāng)我改一個接口的時候,我需要同時修改兩部分的代碼,以及對應(yīng)的測試。反而,還不如直接修改原有的模板來得簡單。
可是當(dāng)我去使用這個,由前后端分離做成的單頁面應(yīng)用時,我開始覺得這些是值得。當(dāng)頁面加載完后,每打開一個新的鏈接時,不再需要等網(wǎng)絡(luò)返回給我結(jié)果;我也能快速的回到上一個頁面,像一個 APP 一樣的體現(xiàn)這樣的應(yīng)用。整個過程里,我們只是不斷地從后臺去獲取數(shù)據(jù),不需要重復(fù)地請求頁面——因為這些頁面的模板已經(jīng)存在本地了,我們所缺少的只是實時的數(shù)據(jù)。
后來,當(dāng)我從架構(gòu)去考慮這件事時,我才發(fā)現(xiàn)這種花費是值得的。
什么是前后端分離?
前后端分離和微服務(wù)一樣,漸漸地影響了新的大型系統(tǒng)的架構(gòu)。微服務(wù)和前后端分離要解決是類似的問題,解耦——可以解耦復(fù)雜的業(yè)務(wù)邏輯,解耦架構(gòu)。可要是說相像吧,消息隊伍和前后端便相似一些,通過傳遞數(shù)據(jù)的形式來解耦組件。
前后端分離意味著,前后端之間使用 JSON 來交流,兩個開發(fā)團隊之間使用 API 作為契約進行交互。從此,后臺選用的技術(shù)棧不影響前臺。當(dāng)后臺開發(fā)人員選擇 Java 的時候,我可以不用 JSP 來編寫前端頁面,繼續(xù)使用我的 React 又或者 Angular。而我使用 React 時,也不影響后臺使用某一個框架。
概念我們已經(jīng)清楚了,但是還有一個問題:我們真的需要前后端分離嗎?
真的需要前后端分離嗎?
過去,聽說 TDD (Test-driven development,測試驅(qū)動開發(fā)) 可以改善代碼的質(zhì)量,我們便實施了 TDD;接著,聽說 BDD (Behavior-driven development,行為驅(qū)動開發(fā)) 可以交付符合業(yè)務(wù)需求的軟件,我們便實施了 BDD;后來,聽說 DDD (Domain-driven design,領(lǐng)域驅(qū)動設(shè)計) 可以分離業(yè)務(wù)代碼與基礎(chǔ)代碼,我們便實施了 DDD。今天,聽說了前后端分離很流行,于是我們就實施了前后端分離——這就是傳說中的 HDD(Hype-driven Development,熱鬧驅(qū)動開發(fā))。
前后端分離在過去的兩三年里,確實特別的熱鬧。但是我們怎么才能知道,是不是需要這樣的架構(gòu)呢?
- 頁面交互是否復(fù)雜 ? 是簡單的提供頁面給用戶瀏覽?或者想要支持復(fù)雜的用戶操作?
- 是否需要搜索引擎優(yōu)化?如果需要的話,那么從一開始我們就需要考慮后端渲染。
- 能提升開發(fā)效率嗎?如果不能有效的提升開發(fā)效率,為什么要作死呢?
- 是否會提供 API 給 APP?如果我們已經(jīng)有一個 API 提供給 APP,那么要做這件事就很容易了。如果未來會有的話,那么我們更應(yīng)該嘗試去分離。
- 前端的修改是不是非常頻繁?如果不需要經(jīng)常修改的話,那么這種優(yōu)化便沒有優(yōu)勢。
當(dāng)然了,如果老板說,我們需要前后端分離,那就做唄!很多時候,一些技術(shù)決策都會由于戰(zhàn)略原因,而發(fā)生一些有意思的變化。
前后端分離將遇到的那些挑戰(zhàn)
而,當(dāng)我們決定需要前后端分離時,我們?nèi)匀贿€需要面對一系列的問題:
- 是否足夠的安全?如果我們設(shè)計出來的架構(gòu)不夠安全,那么這一系列的操作都是白搭。我們怎么去存儲用戶數(shù)據(jù),使用 LocalStorage 的話,還要考慮加密。采用哪種認(rèn)證方式來讓用戶登錄,并保存相應(yīng)的狀態(tài)?
- 是否有足夠的技術(shù)來支撐前后端分離?有沒有能力創(chuàng)建出符合 RESTful 風(fēng)格的 API?
- 是否有能力維護 API 接口?當(dāng)前端或者后臺需要修改接口時,是否能輕松地修改。
- 前后端協(xié)作的成本高不高?前端和后臺兩個團隊是不是很容易合作?是不是可以輕松地進行聯(lián)調(diào)?
- 前后端職責(zé)是否能明確?即:后臺提供數(shù)據(jù),前端負(fù)責(zé)顯示。
- 是否建立了前端的錯誤追蹤機制?能否幫助我們快速地定位出問題。
當(dāng)我們在不同的項目組上嘗試時,就會發(fā)現(xiàn)主要的挑戰(zhàn)是溝通上的挑戰(zhàn),而非技術(shù)上的局限。
前后端分離的核心:后臺提供數(shù)據(jù),前端負(fù)責(zé)顯示
我曾經(jīng)有過使用 PHP 和 Java 開發(fā)后臺代碼的經(jīng)歷,仍然也主要是集中在前端領(lǐng)域。在這樣的傳統(tǒng)架構(gòu)里,編寫前端頁面可不是一件容易的事。后臺只會傳給前端一個 ModelAndView,然后前端就要撲哧撲哧地去豐富業(yè)務(wù)邏輯。
傳統(tǒng)的 MVC 架構(gòu)里,因為某些原因有相當(dāng)多的業(yè)務(wù)邏輯,會被放置到 View 層,也就是模板層里。換句話來說,就是這些邏輯都會被放到前端。我們看到的可能就不是各種if
、else
還有簡單的equal
判斷,還會包含一些復(fù)雜的業(yè)務(wù)邏輯,比如說對某些產(chǎn)品進行特殊的處理。
如果這個時候,我們還需要做各種頁面交互,如填寫表單、Popup、動態(tài)數(shù)據(jù)等等,就不再是簡單的和模板引擎打交道了。我們需要編寫大量的 JavaScript 代碼,因為業(yè)務(wù)的不斷增加,僅使用 jQuery 無法管理如此復(fù)雜的代碼。
輸出邏輯:數(shù)據(jù)顯示
而僅僅只是因為邏輯復(fù)雜的前端代碼,無法影響大部分團隊進行前后端分離——因為它沒有業(yè)務(wù)價值。實際上是先有了單頁面應(yīng)用,才會出現(xiàn)前后端分離。單頁面應(yīng)用可以讓用戶不需要下載 APP,就可以擁有相似的體現(xiàn)。并且與早期的移動網(wǎng)頁相比,擁有更好的體驗。
為了達到這樣的目的,后臺似乎返回對應(yīng)的 Model 即可,稍微修改一下 Controller 的邏輯,然后返回這些數(shù)據(jù)。
[{
"content": "",
"date": "2017-03-04",
"description": "前后端分離,你應(yīng)該知道的八件事\r\n\r\n前后端不分離,是怎樣的?大概也只有我們這些『老古董』們,才對此有更多感受。不對,那些寫 React 的人,可能會對此也有一些體會。",
"id": 1,
"slug": "iamafe-frontend-backend",
"title": "我的職業(yè)是前端工程師: 前后端分離,你應(yīng)該知道的八件事",
"user": ""
}]
前端在一個 API 請求之后,可以直接渲染這些數(shù)據(jù)成 HTML。在這個時候,我們?nèi)匀豢梢钥吹剑厦鏀?shù)據(jù)中的 date 字段值 2017-03-04 的格式,和我們?nèi)粘S玫?2017 年 3 月 4 號的不一樣。所以,我們需要在前端引入 moment
這樣的庫,然后解析這個值。如果僅僅是這樣的處理,那么應(yīng)該由后臺幫我們轉(zhuǎn)換這個值。
與此同時,后臺應(yīng)該按時間來對博客進行排序。前端只需要遍歷這個數(shù)組,隨后取出相應(yīng)的值顯示即可,不需要做任何的邏輯處理。
遺憾的是,在真正的項目中開發(fā)的時候,并不能達到這么完美的狀態(tài)。特別是,為了提高用戶體驗時,我們可能就會將數(shù)據(jù)存儲在本地,隨后直接操作這些數(shù)據(jù),對其進行排序,篩選等等的操作。除此,還有諸如表格、圖表等等的高級樣式,也需要處理這些數(shù)據(jù)。
而當(dāng)用戶需要提交數(shù)據(jù)的時候,這些邏輯就會落到前端上。
不可避免的前端邏輯:表單
如果一個前端應(yīng)用只顯示數(shù)據(jù)的話,那么這個應(yīng)用就沒有充足的理由,做成一個單頁面應(yīng)用——單頁面應(yīng)用是為了更好的交互而存在的。當(dāng)我們注冊、登錄、購買東西時,就需要開始與表單進行處理。
合理的表單驗證模式應(yīng)該是:雙向驗證。
前端在用戶輸入的過程中就需要實時地檢查,是否帶有特殊符號、值是否是在允許的范圍內(nèi)、是不是符合相應(yīng)的規(guī)范等等。而不是等用戶填寫完內(nèi)容并提交后,再由服務(wù)端來告訴用戶說,“你的用戶名不符合規(guī)范”。
服務(wù)在收到前端收到的數(shù)據(jù)后,不管前端有沒有進行驗證,都應(yīng)該按后臺的邏輯進行驗證。
于是乎在這個時候,這些邏輯就被無可避免地放到前臺里了。