天天看點

企業級應用搭建平台是如何設計資産體系的?

作者 | 绯一
企業級應用搭建平台是如何設計資産體系的?

搭建系統行業現狀

面向領域提供解決方案,提高生産效率
企業級應用搭建平台是如何設計資産體系的?

via 雲鳳蝶可視化搭建的推導與實作

搭建系統并不是一個稀奇的概念,從 Dreamweaver 開始,有大量的産品試圖用裝配式的開發解決應用生産的效率問題。它們面向特定場景做抽象、沉澱出最佳實踐,再通過産品封裝來加速整個制作過程。

比如 Dreamweaver 認為 HTML 樹是不重要的,應該通過所見即所得的自由拖拽生成;比如 SwiftUI 認為移動場景下,資料的流向與更新應該被高度簡化,于是提供簡潔的互動來快速建立元件與模型間響應式的資料流。

搭建系統要解決什麼問題?

一言以蔽之,缺人。

前端沉重的上手門檻導緻招聘培養非常困難,前端資源逐漸成為項目瓶頸,無法跟上爆發式的業務增長。現場我做了一個調查,寫過前端頁面的人中隻有 1/3 是專職前端,剩下的大家都是被逼的沒辦法:服務早就寫好了,但沒前端資源,隻能撸起袖子自己把頁面做了。

企業級應用搭建平台是如何設計資産體系的?

via How it feels to learn JavaScript in 2016

如何解決問題?

參考制造業的最佳實踐

作為高精尖産品 iPhone,通過标準化手機的制作程式,将大量生産外包。蘋果有 200 多個零部件供應商,400 多道組裝工序,終端的富士康鄭州工廠每天可以生産 50 萬部 iPhone,零部件拆分和流水線的組裝大大提升産能,蘋果通過這種方式書寫了普通勞工批量制造高精尖産品的神話。

企業級應用搭建平台是如何設計資産體系的?

iPhone 的供應鍊,紅框内是富士康 via 雲鳳蝶中台研發提效實踐

汽車行業将整車拆分為零部件,外包給專業的零部件生産商,再通過流水線的組裝完成最後一步。這些組裝汽車的人,可能對汽車一竅不通,但隻需要在流水線,按部就班的重複再重複就行了。

企業級應用搭建平台是如何設計資産體系的?

傳統研發 vs 搭建研發 via 雲鳳蝶中台研發提效實踐

還有我們所熟悉的每一個快餐店:

企業級應用搭建平台是如何設計資産體系的?

論如何制作漢堡包

通過上面幾種抽象,傳統的生産過程被重新解構為:

  • 擅長生産零部件的沉澱為領域專家:比如相機、螺絲、輪胎、面包和炸雞,在領域内不斷突破降低成本
  • 在終端門檻極低的流水線組裝:可以招聘大量普通勞工擴大生産,實作效率的不斷提升

雲鳳蝶的實踐經驗

企業級應用制作平台

在如今的 Web 領域,無論是大公司還是小公司,都很少會從 span、div 标簽寫起,大家都會有自己的一套元件庫,對于 Web 研發我們似乎也可以使用這樣的思路來解決問題。

在螞蟻集團,有 36% 的中背景應用以這種方式搭建,應用的平均複雜度在 20 個頁面,上百個元件的量級。我們通過對中背景應用的抽象,結合設計規範,希望能重新定義應用的制作方式,解決三個問題:

  • 降門檻:非專業前端也能搭建,拓展新的角色在終端「組裝汽車」,可以大量外包用工
  • 提效率:結合設計規範,簡化應用制作的各種概念,比如樣式、布局、資料流、網絡請求
  • 60 分:很多中背景應用缺乏産品和設計,體驗參差不齊。之前 Ant Design 的作者曾提過一個觀點,antd 最大的價值是保證應用可以達到一個最低及格分

自然搭建系統在發展中也會面臨各種問題,本文主要結合在雲鳳蝶的實踐經驗,聊一聊對于一個搭建系統來說,如何通過元件化的思路應對搭建系統發展上面臨的各種挑戰。

一個搭建系統要面臨怎樣的挑戰?

支援的業務複雜度提升,搭建系統的複雜度也會提升

每個人應該都寫過最樸素的搭建系統,它的形式類似一個營銷搭建系統。在業務開發中,我們會把頁面中經常變化的内容抽象為模版的配置項,并在模版外進行配置,每當配置變化,模版無需重新建構和驗證即可快速疊代,此時一個應用由一個巨大的模版組成,如下圖 1。

随着需求複雜度的提升,搭建系統需要做更細粒度的拆分。比如雙 11 有多個活動頁面,頁面間有一些共享子產品,比如簽到和抽獎。從複用和維護性的角度,我們會面向功能封裝出一些業務元件,此時搭建系統也相應要進化為樓層式搭建,對業務元件做二次編排和配置。

原本的一個配置項變為配置項數組,按照順序描述每個元件暴露的接口,此時的搭建系統已經能夠承載一定對複用的需求,有了元件化的雛形,如下圖 2。

企業級應用搭建平台是如何設計資産體系的?

搭建系統的演進過程

再往後發展,頁面出現了更自由的組合關系:導航欄、父子嵌套、彈窗、表單表格,這是典型的中背景應用。我們必須進一步拆分,并且多數元件已經無法針對具體應用重新開發,必須沉澱更細粒度的通用型元件,把原本大量内置到模版的邏輯,拆出來表達為元件間關系,才能支撐業務的持續增長,如上圖 3。

從最簡單的營銷搭建到中背景搭建,整個元件體系在技術上有很多挑戰:

企業級應用搭建平台是如何設計資産體系的?

元件體系 1.0 - 鑄型

要建立一個怎樣的元件體系,才能應對這些挑戰呢?

元件從哪裡來?

首先要回答一個問題,去哪找元件?

NPM 是社群非常有生命力的元件中心,複用 NPM 的基礎設施是一個理想的選擇:

  • 重新造一套元件的成本太高了,Ant Design 一個元件的平均成本在一個月左右
  • NPM 上有大量的高品質元件,可以快速補充元件内容
  • 不同的業務會有自己的一套元件庫,無法全部内置到平台,必須要「開放」
  • 當業務出現自定義需求,可以封裝 NPM 完成最後一公裡
企業級應用搭建平台是如何設計資産體系的?

和 NPM 的關系

而元件的生産必須與平台解耦,再通過元件規範建立連接配接,這樣才能快速建立元件生态,完成面向元件的拓展。

1、對元件進行抽象和模組化

建立元件規範:NPM 和搭建系統的連接配接

前面我們提到,對應用的配置可以分解對多個元件的配置。一個典型的元件編輯的場景如下,我們要能找到元件向外暴露的接口,并通過圖形化的方式編輯他們。

企業級應用搭建平台是如何設計資産體系的?

編輯元件

再以主流的前端架構來看,一個元件是什麼?

企業級應用搭建平台是如何設計資産體系的?

元件的抽象

UI 就是元件最終的渲染效果,f 是元件的實作,而 props 就是元件向外暴露的接口,以 React 的代碼為例,上面的可視化編輯和下面的代碼相對應:

<Button type="primary" loading={false} children="我是一個按鈕" />           

2、從類型出發找到元件

根據 NPM 的規範,我們可以從

package.json.typings

類型檔案出發,通過 AST 解析找到所有的子產品導出,并提取出其中符合

UI = F(props)

抽象的元件和屬性定義。

比如在 React 技術棧下,

React.ComponentReact.FCReact.PureComponent

都是符合要求的。

企業級應用搭建平台是如何設計資産體系的?

解析元件和 Props

3、識别/提取元件的元資訊

找到元件後,我們可以深入挖掘他的元資訊,比如如下的類型聲明,我們很容易推測幾件事情:

/**
 * @title 尺寸
 */
size: "small" | "middle" | "large";

/**
 * @format icon
 */
beforeIcon: string;

children?: React.ReactNode;           
  • size

    的中文描述是尺寸
  • size

    隻有三種取值,語義類似枚舉,适合用下拉選擇來編輯
  • beforeIcon

    的類型是

    string

    ,但

    format

    icon

    ,适合用圖示選擇器來編輯

将這些對元資訊的推測規則沉澱下來,我們可以得到一個渲染引擎驅動的屬性面闆。在元件無需任何額外定義的情況下,盡可能的提升元件編輯效率。

4、一些複雜的編輯意圖推斷

除了上面對基礎類型的簡單推斷,我們還可以做一些更深入的分析推斷。

比如

nullable

通常用來表達可關閉的編輯意圖。表格的分頁屬性可以配置為

Object

類型資料表達分頁詳細資訊,也可以将值設為

false

來關閉整個分頁功能,我們可以使用下面這種互動:

Table.pagination: false | Pagination           
企業級應用搭建平台是如何設計資産體系的?

nullable

unionType

通常用來表達分支情況。元件的提示資訊有三種類型,每種類型都會一些特定配置項,在不同分支切換時,需要删除前一個分支的值,并為新的分支設定預設值。

tips: Text | Card | Popconfirm           
企業級應用搭建平台是如何設計資産體系的?

unionType

元件如何加載、預覽

應用如何處理 f 的依賴?

在寫代碼的模式裡,我們把依賴安裝到本地,再通過 Webpack 類似的工具對檔案進行打包,每當代碼修改/依賴發生變化,應用會重新建構,最終釋出時,應用會把所有依賴的代碼打包到一起。

但對于搭建系統來說,改一行文字等 5s 顯然是不能接受的,我們要提供實時預覽的方案。

企業級應用搭建平台是如何設計資産體系的?

一個簡單的依賴關系

常見的玩法是,每個元件提前獨立打 umd 包,應用隻建構自己的代碼,再通過 loader 遠端加載所有外部元件依賴,形成一個 distMap,最終做元件渲染,這裡 Map 的值就是上面我們提到的

UI = f(props)

裡的 f。

{
  Button: eval(request(buttonDist)),
  Card: eval(request(CardDist)),
}

React.createElement(map['Button'], ...);           

但把所有依賴都打包進去的方法會導緻 A 被重複打包多次,如上圖,如果 A、B、C 分别打一個 umd 包,應用會有三個 A 的打包體積,并且對于

React.Context

等場景還會帶來不同執行個體資料不通的問題。

我們需要有更細粒度的子產品打包方式,能夠支援按照版本規則對 A 進行複用。

1、Bundless 技術方案

NPM 包次元提前打包 & 實時依賴計算

元件在第一次進入到系統時,會按照依賴樹遞歸的做 NPM 級打包,并将結果存儲到 Assets CDN 上。

目前端應用的依賴發生變化時,通過請求 Assets CDN,按照版本合并 A & C 的所有依賴,并通過一次網絡請求加載回來,再拆分給 loader 裝載到 distMap 上。

企業級應用搭建平台是如何設計資産體系的?

元件導入 & 依賴加載

2、TreeShaking

上面的場景中,提前打包的粒度是 NPM 包級,這會導緻一個問題,應用隻使用了

lodash.get

但卻加載了整個

lodash

,體積還是很大。如下圖,使用了

antd

ButtonMenuTable

,最後加載了整個

antd

企業級應用搭建平台是如何設計資産體系的?

按需 TreeShaking

我們還需要做一些動态的處理,在應用釋出時,根據應用對元件的實際使用情況,自動 TreeShaking 掉未使用的子產品,建立一個虛拟的

antd

來降低體積。

這裡有一些衍生的問題,如何保證依賴計算的速度、為什麼 treeShaking 是安全的,以及為什麼不做檔案級的 Bundless?後續會有文章專門介紹。

元件體系 2.0 - 演進

「偷」來的元件不夠好用怎麼辦?

通過一鍵導入 NPM 可以幫我們快速補充元件内容,但 NPM 上是相對松散的元件,距離在搭建系統上好用還有很大距離,我們需要對他們做一些封裝,并且建立能持續疊代和治理的方案。

橫向封裝

1、彈窗類元件難以使用

彈窗類元件通常有一個受控屬性來控制顯示隐藏,如果設為可見,會擋住其他所有元件的編輯;如果設為不可見則無法編輯彈窗本身。

我們嘗試抽象彈窗元件的特性,結合編輯态大綱樹選中狀态這一互動做一些封裝:

  • 大綱樹上選中

    visible: true

  • 取消選擇

    visible: false

企業級應用搭建平台是如何設計資産體系的?

2、dataEntry 類元件雙向綁定成本過高

輸入框等元件的值也是受控模式,在輸入框輸入後需要手動在

onChange

方法裡把新的值同步回

value

上,這使得表單類元件在搭建系統下使用效率很低。

我們同樣去抽象這類元件的特征,在元件接入時,讓元件回答幾個問題:

  • 是否為表單類元件
  • 表達值的屬性名是什麼(比如 value)
  • 同步資料的事件是什麼(比如 onChange)

這樣我們可以建立一個虛拟的

store

,在

onChange

事件觸發時,自動完成事件參數到

value

的資料同步。在産品上的展現就是雙向綁定,使用者隻需要為表單類綁定一個變量,資料同步就自動完成了。

企業級應用搭建平台是如何設計資産體系的?

3、面向特征做能力切面的拓展

類似上面兩種的封裝方式還有很多,這種面向元件特征而不是具體的元件做抽象,有幾個非常明顯的好處:

  • 橫行提升表達力:此類元件都能使用,能力是有限的,但元件是無限的
  • 降低耦合:系統群組件解耦,通過能力描述建立關聯
  • 統一心智:通用行為集中在與元件無關的配置區
企業級應用搭建平台是如何設計資産體系的?

元件表現力 = 元件數量 x 橫向能力

舉個例子,一個普通的頭像元件,經過大量通用能力的描述可以變為帶徽标的頭像數組。

資産沉澱

除了用導入 NPM 的方式生産元件,我們還可以在搭建系統沉澱一些元件嗎?

1、畫布元件

如果一個應用中有多個地方都使用了相似的布局,我們可以把這部分内容提取為畫布元件,并像 React 那樣,向外暴露一些屬性,實作一處維護、多處使用的目的。

如下,我們把使用者資訊的展示封裝為一個元件,而使用者資訊作為外部參數傳入,這種局部複用的思路和 NPM 是一緻的,隻是生産元件的方式不僅局限于寫代碼,還可以通過搭建。

企業級應用搭建平台是如何設計資産體系的?

封裝畫布元件

2、JSXBox 最後一公裡

除了使用已有的元件進行搭建外,有些場景可能更适合用代碼,比如根據資料動态嵌套渲染,或是繪制一個複雜的圖表。我們可以在頁面上挖一個洞,讓使用者寫代碼的方式,完成這部分定制化的需求。

它的形态有些類似 CodeSandbox,寫一段 React 代碼,最終和其他元件混合跑在一個頁面上。

企業級應用搭建平台是如何設計資産體系的?

JSXBox

3、資産包

在持續發展中,每條業務線都會沉澱自己适用的業務資産,可能是一系列 NPM 包,也可能是我們可以提到的搭建系統内的資産。在産品形态上,我們可以引入資産大包的概念,業務線的開發可以聚合比如 UI 元件、工具函數、服務等,整合到資産包内,再釋出給其他應用使用,通過這種方式完成業務資産沉澱和定向的二次效率提升。

并且無論是畫布元件、代碼元件、JSXBox 都是遵循同樣一套元件規範,我們可以直接将搭建系統内沉澱的資産包釋出到 NPM。

适合搭建的走搭建、适合代碼的寫代碼。使用者可以通過 NPM 完成各自的互相融合研發。

企業級應用搭建平台是如何設計資産體系的?

沉澱資産包

版本治理

隻要有版本,就會有版本碎片
企業級應用搭建平台是如何設計資産體系的?

antd 的版本碎片分布 & antd4 changeLog

當搭建系統封裝元件給應用使用時,必然會出現版本,也就必然面臨版本碎片問題。版本碎片無論對元件的開發者還是使用者都是巨大的成本,對于搭建系統來說,如何解決這個問題?

一次 API 不相容變更

我們來看一個具體的例子,Menu 早期用 Boolean 表達水準/垂直布局,但新的設計規範引入第三種布局,Boolean 無法承載,需要更新為 String 枚舉,從 API 上來看,确實是一次不相容更新。

企業級應用搭建平台是如何設計資産體系的?

Menu1.0 -> Menu2.0

但元件的 API 發生變化,能力并未發生變化,也就是 Menu2.0 仍然支援水準/垂直的布局能力,隻是舊的 Boolean 資料不再适用新的元件實作,需要更新。

而搭建平台下,元件的使用是嚴格受控的,是一份結構化的資料,我們完全可以通過精準的 Codemod 來将所有舊版本的資料更新為新版本,即:

delete $props.vertical
create $props.layout: $before.vertical ? 'vertical' : 'horizontal'           

通過這種方式,我們可以将大部分元件不相容的版本更新上來,元件始終可以保持向前相容,0 版本碎片。

分享一個資料,去年 antd 從 3 到 4 的更新,使用雲鳳蝶搭建的幾百個應用全程無感覺,隻需要點一下更新等上一會就行了。

實作開放與收斂

有生命力的資産體系
企業級應用搭建平台是如何設計資産體系的?

通過上面各種手段,我們實作了一個無序的 NPM 元件到搭建系統的資産的過度,在這個過程:

  • 一鍵導入:讓原來的元件都能用
  • 橫向封裝:讓原來的元件在搭建系統下更好用
  • codemod:讓使用者始終用最新的元件

同時,面向元件規範、能力切面的抽象,使得在支撐更複雜業務的同時,搭建系統本身的複雜度可以得到收斂。通過底層的各種功能子產品支撐,建立起一個有生命力的資産體系。

one more thing

如何評價程式員 50% 的時間都在寫表單表格?

就算搭建系統再好用,資産再有生命力,使用者仍然還是要一個表單項一個表單項配置表單、表格、進階搜尋,處理雙向綁定、字段映射等重複工作,面對有大量規律可循的增删改查中背景應用,我們能不能抽象一些套路,把程式員從千篇一律的工作中解脫出來呢?

實際上我們觀察 API 文檔可以發現,接口格式和最終的表單、表格有非常大的關聯關系:

  • GET /api/use

    查詢使用者清單,大機率會使用表格,表格列和傳回值有高度的對應關系
  • POST /api/user

    新增使用者資訊,大機率會使用表單,表單項和入參數有高度的對應關系
  • name: string

    大機率在表單中使用輸入框,在表格中使用文本

這些推斷來源于對 API 元資訊的了解、按照能力切面為元件做的封裝,以及中背景應用在設計上的最佳實踐。

企業級應用搭建平台是如何設計資産體系的?

傳統 vs 智能向導

有了智能向導的幫助,使用者隻需要選擇接口、勾選他們想要的字段,再做一些簡單的映射配置,即可生成帶有完整邏輯功能的表單、表格頁面,在雲鳳蝶應用中,有 53% 的等效代碼由機器自動生成。

點選檢視視訊

寫在最後

The dignity of movement of an ice-berg is due to only one-eighth of it being above water.

Ernest Hemingway

企業級應用搭建平台是如何設計資産體系的?

最後以一張經典冰山圖作為結尾,實際上我們看到的很多酷炫功能,為了保障他的正常運作,在看得到的冰山下,有大量看不見的工具鍊路、渲染引擎、設計規則在悄悄運轉。

作者:绯一 ,就職于螞蟻集團體驗技術部(AFX),專注于工程領域。曾參與元件規範、建構工具、應用架構、研發平台等基礎設施的研發工作。目前主要負責低代碼搭建平台的資産體系設計,緻力于打造下一代 Web 研發平台「雲鳳蝶」。
企業級應用搭建平台是如何設計資産體系的?

繼續閱讀