1. 程式人生 > 其它 >瘋了吧!這幫人居然用 Go 寫“前端”?(一)

瘋了吧!這幫人居然用 Go 寫“前端”?(一)

作者 | 鄭嘉濤(群青)
來源 | 爾達 Erda 公眾號

無一例外,談到前後端分離“必定”是 RESTful API,算是定式了。但我們知道 REST 在資源劃分上的設計總是與 UI 大相徑庭,大量專用、特異、古怪的介面就像永遠拾不盡的菌菇,你費力剷除它們,但一場雷雨便又枯樹復披。另一方面介面越來越通用,最後卻只剩下 CRUD,美其名曰後端只考慮穩定和效能,大量業務邏輯卻全權“丟”給了前端,不禁讓人懷疑,這真的是前後端分離了嗎?

Erda 作為企業一站式雲原生 PaaS 平臺,也存在著大量面向使用互動的佈局各色的介面:從個人後臺到部署總覽再到專案設定;從叢集管理到監控大盤再到成員管理。我們從 REST 開始做起,但也逐漸發生變化。本文將從頭講述我們如何從確實問題切入,逐步建設和完善 Erda 的前後端分離框架。

由於整個框架牽涉到太多內容,所以我計劃以系列文章的形式來進行詳細解讀。本文主要介紹其產生的緣由以及設計思路,更多相關的細節會在後續文章中進行展開,包括但不限於:

  • 框架實現細節
  • 使用框架後測試如何展開?
  • 穩定性和工程管理
  • ······

簡要介紹一下本文的主要結構:

  • 樸素的想法
  • 互動 vs 業務
  • 迴歸經典
  • 元件及協議

前面三個部分主要介紹了我們建設框架的背景以及方案分析,“元件及協議”部分則整體闡述了框架的核心設計理念。如果你趕時間,建議直接閱讀“元件及協議”部分。

樸素的想法

所有軟體公司都會遇到的困境,那就是分工。老派開發者會信奉單打獨鬥全棧的能力,但軟體變得複雜之後,分工是不可避免的,而最為顯著的就是前後端的分工。

Erda 的前端資源一直是緊缺的,最誇張的時候前後端比例可以達到 1:8,大部分情況下,工程的瓶頸在於前端。我們很樸素的認為,改變這個局面需要後端承擔更多的工作,以釋放前端的人力。

互動 vs 業務

所謂前後端的分工,從根本上來說是互動和業務的劃分。

下圖是最通用的場景,前端關注視覺、體驗等,後端關注 CRUD、安全、穩定等。而業務流程、許可權等則是散落在前端和後端,我們很難說清楚一個具體的業務邏輯究竟是前端實現的,還是後端實現的。

由上文描述可以預見,這樣的劃分會導致一些問題:

  • 重複性工作:進而系統開發會在某些位置產生疏忽(比如前端實現了鑑權,導致後端的鑑權邏輯得不到很好的驗證)。
  • 前後端對接面積大:帶來溝通成本,往往這個成本由前端同學承擔,這也是前端資源短缺的原因之一。

試想一下,你是否經常會看到這樣的場景:後端寫完介面後拍拍屁股走人,獨留下前端默默猜測介面的引數意義。包括後來測試出的 BUG,也“總”被認為是前端的問題。

面對上面的問題,業界也存在很多種解決方法,比如採用 NodeJS:

如上圖所示,通過 js 實現來囊括業務流程、許可權等邏輯。使得這些邏輯事實上全部納入前端範疇,而後端則被空心化,也就只剩下大家熟悉的 CRUD。

這種做法在某種程度上是高效的,也符合前端界“大一統”的思潮,但對於前端資源不足的現狀來講,該舉措無疑是雪上加霜。

同時,也有激進派會採用低程式碼平臺“一勞永逸”,乾脆不需要前端開發,基於平臺的配置和少量的後端流程程式碼彷彿呈現了一個可能的未來:

不過現有的低程式碼平臺大多仍處於發展階段,完全摒棄前端則會導致互動或者 UI 呈現比較死板和固定,簡單來講就是不夠“炫酷”。這也是為什麼目前低程式碼平臺大多支撐的是中後臺系統。

我們看到業界也有走“復古”路線的,比如 hey.com 就是如此(https://www.hey.com/how-it-works/):


所謂“復古”,指的是頁面邏輯大量運用後端渲染,前端只用少量簡單的程式碼(css,js)實現互動細節。就好比古早的 php 以及 jsp 等開發模式,基本上所有的業務邏輯都實現在後端。可以說這種實踐是當下對前端框架越來越龐大、nodejs 盛行現狀的一種“反叛”。

不過我們也欣喜的看到,即使是所謂“過時”的開發模式,開發出的仍然是包含當代審美的“炫酷”產品、仍有著十分卓越的互動體驗。

全棧的可取之處

hey.com 所用的開發模式,從某種角度上看也可以認為是全棧。

一個人開發前端和後端,這件事情有很大的誘惑力。這也意味著:

  • 前後端的溝通成本大量減少,即使前後端都需要熟知業務細節。
  • 介面除錯成本大量減少,即使介面設計經過充分的評審。
  • 放到更長遠的角度,功能變更和迭代的成本也趨於減少。

但是,全棧的要求過高,個人很難做到前後端都精通。不過這種一個人負責到底的思想,倒是非常可取。

迴歸經典

Web 的基礎是 HTTP。HTTP 請求的目標(target)是資源(resource)。我們訪問的所有頁面都是資源,頁面的連結則是資源定位符(URI)。

如下圖所示,整個流程是這樣的:

  1. 瀏覽器發起請求,當請求得到處理,服務端傳輸資料給瀏覽器以呈現介面(這個資料一般為 HTML,一種描述呈現方式的語言)。
  2. 以表單為例,在呈現為表單的介面上進行操作,按照協議和瀏覽器的實現,則會發起一次新的資源請求(HTTP)。
  3. 這次請求需要伺服器進行資源更改,成功後則會重新返回資料給瀏覽器以呈現修改後的介面。
<form action="/users/1">
  <label>Name:</label>
  <input type="text" name="name" value="Bob">
  <input type="submit" value="Submit">
</form>

傳統的 web 只有最低限度的彈窗、確認、scroll 等瀏覽器定義的互動元素,提交(submit)則是互動的終結。不過,隨著 web 和 js 的發展,互動有了更多的可能,同時 html5、css3 也為互動提供了更大的基礎。

現在,我們最直觀的感受就是網站越來越“炫酷”了,同時也越來越“重”了。站在開發者的角度,前端 js 工程的打包速度甚至比後端工程還要更慢。

有沒有一種可能,讓我們所有的技術都回歸到經典 web,迴歸到面向資源(resource)進行操作,迴歸到上個世紀重新思考互動?我們進而可以擴充瀏覽器的互動元素,而不用通過 js 框架實現複雜互動;擴充 HTTP 請求使其更適應瀏覽器呈現和互動。

舉個例子,我們正要開發一個工作看板,如果瀏覽器已經提供了一個通用的看板互動元素,我們是不是就可以像使用表單 form 一樣,只需要利用這個互動元素再“配置”上業務資訊,就能夠在不使用額外 js 的情況下,完成這個功能呢?

基於以上,我們得出了這樣的構思:

  1. 沉澱出一個通用的元件庫(來擴充瀏覽器互動元素),並且這個元件庫數量是固定的,我們將其稱之為“通用元件”。
  2. 利用通用元件填充進業務資料後可以配置呈現出業務功能,比如登入表單、專案建立表單等;通用元件複合業務屬性後,我們稱之為“業務元件”,業務元件個數會隨著業務增長而膨脹。
  3. 需要有一個協議來響應互動,達成上述 form 表單的互動流程,但是這個協議需要足夠強大不僅能支援元件庫所有元件的互動流程,還需要支援多元件聯動的複雜場景;這個協議執行在 HTTP 之上,但是與 RESTful 的區別在於,REST 只關注資料且它是無狀態的,而我們設想的協議需要感知介面呈現以及支援完整的互動流程。

如上圖所示,通過元件庫和協議,可以承載前端一半以上的工作,同時將部分減少後端與前端重疊的工作,並且前後端仍保有其自身的靈活性。

元件及協議

綜上,落實我們得出的三點構思,需要達成三個層次的事情:

  • 豐富的通用元件庫
  • 元件渲染能力,將業務元件渲染成通用元件
  • 協議渲染能力,以處理複雜互動

我們設計了這樣一個渲染框架,分兩個部分(上圖綠色部分):

  • 業務元件渲染器:核心是處理業務資料到通用元件的轉化,以及通用元件操作(operation)的處理(handle)。
  • 場景協議渲染器:核心是將一堆元件編排成為一個場景(可以理解為一個頁面,如上圖右側的頁面結構)以及場景中元件之間的資料繫結,在有互動產生操作(operation)時,負責決策下派以及操作生效後的重新渲染。

上圖中間的通用元件庫,則是由前端進行定義和維護的,前端的關注點在於要豐富這個通用元件庫,以及將每個元件的互動和 UI 做到極致(後面會講到,這些工作即是前端呈現器)。

這樣的設計初衷旨在大量減少前端工作,尤其是前後端對接方面,甚至可以認為對接是“反轉”的,體現在兩個層面:介面定義的反轉和開發時序的變化。

介面定義的反轉

介面的定義上,傳統的由後端主導轉向為前端主導。

傳統(或者說現在主流)的後端實現為 RESTful API,而前端直接對接這些散落的 API,並且理解介面內結構體的含義。但在元件化的背景下,所謂“前後端對接”被拆成了兩部分:渲染和呈現。

前面所說的渲染框架(後端)實現了業務到通用元件的渲染,前端定義維護了通用元件庫,並實現通用元件的“呈現器”,它將通用元件的資料呈現為視覺化的形式。

在渲染和呈現之間的是標準化的通用元件結構(Component Data),我們可以認為通用元件即為前端主導定義的介面,後端由原先甩手一個 RESTful API,演變成要“被迫”理解通用元件的資料結構以實現業務邏輯,整個形勢發生了反轉。

有趣的是,由於通用元件的數量是確定的,我們可以將通用元件開發移植到其他不同呈現介質,甚至可以開發出 CLI 介面的呈現器,且後端程式碼無需修改。

開發時序的變化

由傳統的後端開發完成後前端聯調,轉向為前端先完成開發而後端配合聯調。

“呈現器”使得前端只需要關注通用元件的開發,業務邏輯可以徹底歸為後端。如此職責的劃分讓前端跳出對後端的依賴,可以獨立完成設計、開發和除錯(只需要 mock 元件資料)。元件的高度複用,前端甚至可以搖身一變成為設計師,跳過高保真設計稿,直接交付實物,而這個時候的後端可能還在與表結構設計苦苦掙扎。

更重要的不僅僅是前端的開發時間縮短。

我們可以類比 RESTful API 形式的前後端分離,同樣都是通過“介面”來標準化對接以實現解耦。REST 介面顯然是會隨著業務而膨脹的,通用元件的真正優勢在於徹底剝除業務,使得它的數量相對恆定且極少。我們都知道少即是美(simple is better),實踐證明元件越少越能保證每個元件的質量,而前端通過這些高質量元件完成的功能,幾乎可以認為,除錯的工作都在後端了。

更多

  • 業務元件真的能隔離業務嗎?互動怎麼辦?
  • 協議渲染真的能替換 REST 嗎?我只能二選一嗎?
  • ……

在下篇文章中,我們將會詳細地介紹元件渲染和協議渲染的執行邏輯,以及我們是如何做到讓前端徹底不關心業務的?

歡迎參與開源

Erda 作為開源的一站式雲原生 PaaS 平臺,具備 DevOps、微服務觀測治理、多雲管理以及快資料治理等平臺級能力。點選下方連結即可參與開源,和眾多開發者一起探討、交流,共建開源社群。歡迎大家關注、貢獻程式碼和 Star!