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

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5b/5bf30b61a6ed0238548f898d10251010.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者 | 鄭嘉濤(羣青)來源 | ","attrs":{}},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/MZHb5ABaebfzuiuslvWAtA","title":"","type":null},"content":[{"type":"text","text":"爾達 Erda 公衆號","attrs":{}}]},{"type":"text","text":"​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"無一例外,談到前後端分離“必定”是 RESTful API,算是定式了。但我們知道 REST 在資源劃分上的設計總是與 UI 大相徑庭,大量專用、特異、古怪的接口就像永遠拾不盡的菌菇,你費力剷除它們,但一場雷雨便又枯樹復披。另一方面接口越來越通用,最後卻只剩下 CRUD,美其名曰後端只考慮穩定和性能,大量業務邏輯卻全權“丟”給了前端,不禁讓人懷疑,這真的是前後端分離了嗎?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Erda 作爲企業一站式雲原生 PaaS 平臺,也存在着大量面向使用交互的佈局各色的界面:從個人後臺到部署總覽再到項目設置;從集羣管理到監控大盤再到成員管理。我們從 REST 開始做起,但也逐漸發生變化。本文將從頭講述我們如何從確實問題切入,逐步建設和完善 Erda 的前後端分離框架。​由於整個框架牽涉到太多內容,所以我計劃以系列文章的形式來進行詳細解讀。本文主要介紹其產生的緣由以及設計思路,更多相關的細節會在後續文章中進行展開,包括但不限於:​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"框架實現細節","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用框架後測試如何展開?","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"穩定性和工程管理","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"······","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡要介紹一下本文的主要結構:​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"樸素的想法","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"交互 vs 業務","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"迴歸經典","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"組件及協議","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面三個部分主要介紹了我們建設框架的背景以及方案分析,“組件及協議”部分則整體闡述了框架的核心設計理念。如果你趕時間,建議直接閱讀“組件及協議”部分。​","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"樸素的想法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有軟件公司都會遇到的困境,那就是分工。老派開發者會信奉單打獨鬥全棧的能力,但軟件變得複雜之後,分工是不可避免的,而最爲顯著的就是前後端的分工。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Erda 的前端資源一直是緊缺的,最誇張的時候前後端比例可以達到 1:8,大部分情況下,工程的瓶頸在於前端。我們很樸素的認爲,改變這個局面需要後端承擔更多的工作,以釋放前端的人力。​","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"交互 vs 業務","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所謂前後端的分工,從根本上來說是交互和業務的劃分。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下圖是最通用的場景,前端關注視覺、體驗等,後端關注 CRUD、安全、穩定等。而業務流程、權限等則是散落在前端和後端,我們很難說清楚一個具體的業務邏輯究竟是前端實現的,還是後端實現的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/48/48ad358423939dc1c1b607e0e1a44efc.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由上文描述可以預見,這樣的劃分會導致一些問題:​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重複性工作:進而系統開發會在某些位置產生疏忽(比如前端實現了鑑權,導致後端的鑑權邏輯得不到很好的驗證)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前後端對接面積大:帶來溝通成本,往往這個成本由前端同學承擔,這也是前端資源短缺的原因之一。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"試想一下,你是否經常會看到這樣的場景:後端寫完接口後拍拍屁股走人,獨留下前端默默猜測接口的參數意義。包括後來測試出的 BUG,也“總”被認爲是前端的問題。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"面對上面的問題,業界也存在很多種解決方法,比如採用 NodeJS:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fe/fefaf2c59c4cd28e6bed264c0cecf9f4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖所示,通過 js 實現來囊括業務流程、權限等邏輯。使得這些邏輯事實上全部納入前端範疇,而後端則被空心化,也就只剩下大家熟悉的 CRUD。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種做法在某種程度上是高效的,也符合前端界“大一統”的思潮,但對於前端資源不足的現狀來講,該舉措無疑是雪上加霜。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同時,也有激進派會採用低代碼平臺“一勞永逸”,乾脆不需要前端開發,基於平臺的配置和少量的後端流程代碼彷彿呈現了一個可能的未來:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cb/cbe8ef4497119194c0d0824e1c38ff23.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不過現有的低代碼平臺大多仍處於發展階段,完全摒棄前端則會導致交互或者 UI 呈現比較死板和固定,簡單來講就是不夠“炫酷”。這也是爲什麼目前低代碼平臺大多支撐的是中後臺系統。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們看到業界也有走“復古”路線的,比如 hey.com 就是如此(","attrs":{}},{"type":"link","attrs":{"href":"https://www.hey.com/how-it-works/","title":"","type":null},"content":[{"type":"text","text":"https://www.hey.com/how-it-works/","attrs":{}}]},{"type":"text","text":"):","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9b/9b579f3231707ed8f3ab2958d3e0be19.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/93/93ac2e92108a8ec10bc91dcb7be36b1d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所謂“復古”,指的是頁面邏輯大量運用後端渲染,前端只用少量簡單的代碼(css,js)實現交互細節。就好比古早的 php 以及 jsp 等開發模式,基本上所有的業務邏輯都實現在後端。可以說這種實踐是當下對前端框架越來越龐大、nodejs 盛行現狀的一種“反叛”。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不過我們也欣喜的看到,即使是所謂“過時”的開發模式,開發出的仍然是包含當代審美的“炫酷”產品、仍有着十分卓越的交互體驗。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"全棧的可取之處","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"hey.com 所用的開發模式,從某種角度上看也可以認爲是全棧。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個人開發前端和後端,這件事情有很大的誘惑力。這也意味着:​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前後端的溝通成本大量減少,即使前後端都需要熟知業務細節。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接口調試成本大量減少,即使接口設計經過充分的評審。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"放到更長遠的角度,功能變更和迭代的成本也趨於減少。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是,全棧的要求過高,個人很難做到前後端都精通。不過這種一個人負責到底的思想,倒是非常可取。​","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"迴歸經典","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Web 的基礎是 HTTP。HTTP 請求的目標(target)是資源(resource)。我們訪問的所有頁面都是資源,頁面的鏈接則是資源定位符(URI)。​如下圖所示,整個流程是這樣的:​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"瀏覽器發起請求,當請求得到處理,服務端傳輸數據給瀏覽器以呈現界面(這個數據一般爲 HTML,一種描述呈現方式的語言)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"以表單爲例,在呈現爲表單的界面上進行操作,按照協議和瀏覽器的實現,則會發起一次新的資源請求(HTTP)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"這次請求需要服務器進行資源更改,成功後則會重新返回數據給瀏覽器以呈現修改後的界面。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2c/2cda04754fcfa4c3455ace6354fcafa4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n \n \n \n
\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"傳統的 web 只有最低限度的彈窗、確認、scroll 等瀏覽器定義的交互元素,提交(submit)則是交互的終結。不過,隨着 web 和 js 的發展,交互有了更多的可能,同時 html5、css3 也爲交互提供了更大的基礎。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們最直觀的感受就是網站越來越“炫酷”了,同時也越來越“重”了。站在開發者的角度,前端 js 工程的打包速度甚至比後端工程還要更慢。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有沒有一種可能,讓我們所有的技術都回歸到經典 web,迴歸到面向資源(resource)進行操作,迴歸到上個世紀重新思考交互?我們進而可以擴充瀏覽器的交互元素,而不用通過 js 框架實現複雜交互;擴充 HTTP 請求使其更適應瀏覽器呈現和交互。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉個例子,我們正要開發一個工作看板,如果瀏覽器已經提供了一個通用的看板交互元素,我們是不是就可以像使用表單 form 一樣,只需要利用這個交互元素再“配置”上業務信息,就能夠在不使用額外 js 的情況下,完成這個功能呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於以上,我們得出了這樣的構思:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"沉澱出一個通用的組件庫(來擴充瀏覽器交互元素),並且這個組件庫數量是固定的,我們將其稱之爲“通用組件”。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"利用通用組件填充進業務數據後可以配置呈現出業務功能,比如登錄表單、項目創建表單等;通用組件複合業務屬性後,我們稱之爲“業務組件”,業務組件個數會隨着業務增長而膨脹。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"需要有一個協議來響應交互,達成上述 form 表單的交互流程,但是這個協議需要足夠強大不僅能支持組件庫所有組件的交互流程,還需要支持多組件聯動的複雜場景;這個協議運行在 HTTP 之上,但是與 RESTful 的區別在於,REST 只關注數據且它是無狀態的,而我們設想的協議需要感知界面呈現以及支持完整的交互流程。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a5/a5213b48cbc02d3b0666ea845bb02781.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖所示,通過組件庫和協議,可以承載前端一半以上的工作,同時將部分減少後端與前端重疊的工作,並且前後端仍保有其自身的靈活性。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"組件及協議","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"綜上,落實我們得出的三點構思,需要達成三個層次的事情:​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"豐富的通用組件庫","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"組件渲染能力,將業務組件渲染成通用組件","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"協議渲染能力,以處理複雜交互","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0d/0d7271ac162bfbf516ca236c81ee4e25.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們設計了這樣一個渲染框架,分兩個部分(上圖綠色部分):​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業務組件渲染器:核心是處理業務數據到通用組件的轉化,以及通用組件操作(operation)的處理(handle)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"場景協議渲染器:核心是將一堆組件編排成爲一個場景(可以理解爲一個頁面,如上圖右側的頁面結構)以及場景中組件之間的數據綁定,在有交互產生操作(operation)時,負責決策下派以及操作生效後的重新渲染。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上圖中間的通用組件庫,則是由前端進行定義和維護的,前端的關注點在於要豐富這個通用組件庫,以及將每個組件的交互和 UI 做到極致(後面會講到,這些工作即是前端呈現器)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣的設計初衷旨在大量減少前端工作,尤其是前後端對接方面,甚至可以認爲對接是“反轉”的,體現在兩個層面:接口定義的反轉和開發時序的變化。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"接口定義的反轉","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接口的定義上,傳統的由後端主導轉向爲前端主導。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"傳統(或者說現在主流)的後端實現爲 RESTful API,而前端直接對接這些散落的 API,並且理解接口內結構體的含義。但在組件化的背景下,所謂“前後端對接”被拆成了兩部分:渲染和呈現。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/de/deaaf1dc70b817a2febe06a8b4bb257e.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面所說的渲染框架(後端)實現了業務到通用組件的渲染,前端定義維護了通用組件庫,並實現通用組件的“呈現器”,它將通用組件的數據呈現爲可視化的形式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在渲染和呈現之間的是標準化的通用組件結構(Component Data),我們可以認爲通用組件即爲前端主導定義的接口,後端由原先甩手一個 RESTful API,演變成要“被迫”理解通用組件的數據結構以實現業務邏輯,整個形勢發生了反轉。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有趣的是,由於通用組件的數量是確定的,我們可以將通用組件開發移植到其他不同呈現介質,甚至可以開發出 CLI 界面的呈現器,且後端代碼無需修改。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"開發時序的變化","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由傳統的後端開發完成後前端聯調,轉向爲前端先完成開發而後端配合聯調。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“呈現器”使得前端只需要關注通用組件的開發,業務邏輯可以徹底歸爲後端。如此職責的劃分讓前端跳出對後端的依賴,可以獨立完成設計、開發和調試(只需要 mock 組件數據)。組件的高度複用,前端甚至可以搖身一變成爲設計師,跳過高保真設計稿,直接交付實物,而這個時候的後端可能還在與表結構設計苦苦掙扎。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更重要的不僅僅是前端的開發時間縮短。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以類比 RESTful API 形式的前後端分離,同樣都是通過“接口”來標準化對接以實現解耦。REST 接口顯然是會隨着業務而膨脹的,通用組件的真正優勢在於徹底剝除業務,使得它的數量相對恆定且極少。我們都知道少即是美(simple is better),實踐證明組件越少越能保證每個組件的質量,而前端通過這些高質量組件完成的功能,幾乎可以認爲,調試的工作都在後端了。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"更多","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業務組件真的能隔離業務嗎?交互怎麼辦?","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"協議渲染真的能替換 REST 嗎?我只能二選一嗎?","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"……","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在下篇文章中,我們將會詳細地介紹組件渲染和協議渲染的運行邏輯,以及我們是如何做到讓前端徹底不關心業務的?​","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"歡迎參與開源","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Erda 作爲開源的一站式雲原生 PaaS 平臺,具備 DevOps、微服務觀測治理、多雲管理以及快數據治理等平臺級能力。","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"點擊下方鏈接即可參與開源","attrs":{}},{"type":"text","text":",和衆多開發者一起探討、交流,共建開源社區。","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"歡迎大家關注、貢獻代碼和 Star!","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"​","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Erda Github 地址:","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/erda-project/erda","title":"","type":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"https://github.com/erda-project/erda","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Erda Cloud 官網:","attrs":{}},{"type":"link","attrs":{"href":"https://www.erda.cloud/","title":"","type":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"https://www.erda.cloud/","attrs":{}}]}]}]}],"attrs":{}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章