作者:vivo 網際網路大資料團隊-Wang Lei
本文是vivo網際網路大資料團隊《BI資料視覺化平臺建設》系列文章第2篇 -篩選器元件。
本文主要介紹了BI資料視覺化平臺建設中比較核心的篩選器元件, 涉及元件分類、元件庫開發等升級實踐經驗,透過分享一些對互動和業務耦合度高的元件開發迭代的思考,希望可以給正在做元件重構解耦的讀者帶來啟發。
往期系列文章:BI 資料視覺化平臺建設(1)—交叉表元件演變實戰
一、引言
BI產品通常包含大量複雜的資料資訊,需要對其進行快速和準確的處理和分析。篩選器可以幫助BI產品的使用者快速地定位所需資訊,並從海量資料中篩選出有用的資料,以便進行深入的分析和決策。敏捷BI作為公司內部使用者數最多的視覺化平臺,隨著平臺的業務增長和版本迭代,其篩選器功能也越來越豐富和完善,舊的設計架構也顯得越來越臃腫且難以維護,為了提高篩選器使用的穩定性和降低後續迭代維護成本,篩選器的架構升級已經不可避免了,本文主要給大家介紹一下篩選器元件的架構升級實踐經驗。
二、前期設計
2.1 元件選型
前期篩選器元件的職責和互動比較簡單,主要是對圖表資料進行單向的資料過濾,並沒有應用到其他的業務場景中,所以前期的元件設計主要以 業務元件 的思路進行開發實現。
2.2 元件分類
元件型別主要可以分為業務元件和通用元件兩種,它們在元件的狀態管理和介面渲染的設計和實現上是完全不同的。
但無論是業務元件或者通用元件都具備元件本質所包含的三個性質 擴充套件、通用、健壯:
-
擴充套件性:在原有元件基礎上可 二次封裝 擴充套件成新的元件符合設計的開閉原則。
-
通用性:根據元件接受的引數和元件中與業務的解耦比來衡量元件的通用性,並不是通用性佔比100%的元件就是最好的元件,需要根據 不同的場景 分析。
-
健壯性:避免元件中引數處理和函式執行過程可能出現的奔潰和錯誤導致程式的直接結束通話,單測以對元件內部 做好邊界處理,異常錯誤的捕獲來衡量這一標準。
因此兩種元件型別沒有絕對優劣之分,重要的是在保證元件設計的基本原則不變的情況下,根據不同的業務場景和需求選擇合適的型別 。無論哪種元件,隨著不斷擴充套件,使其通用性提升,必然就會降低元件的易用性質;而不斷豐富一個元件,也會導致其元件程式碼過長、元件使命不單一、不易讀、不易維護;因此元件設計除了要保證元件的基本性質,還要透過明確元件職責、元件拆分粒度以及良好的程式碼結構和Api設計規範對元件的迭代進行約束,避免程式碼邏輯的過度疊加和膨脹。
2.3 背景痛點
舊版篩選器元件設計存在維護成本高且問題BUG多等問題,主要由兩個原因造成,第一個是業務發展,隨著業務的快速增長,篩選器元件的功能也越來越豐富和完善,由原來的單一功能升級成可以支援資料預警、個性化分析等多種業務場景的核心模組;第二個是缺乏規範約束,主要是缺少良好的程式碼結構和清晰的元件職責等規範約束,導致業務邏輯過度疊加,粒度拆分不合理,檔案多,且檔名不規範。最終導致了篩選器元件的穩定性越發不可控。
由於前期設計不合理和缺乏規範約束,篩選器元件經過了一段時間的野蠻式迭代擴充套件帶來了以下的痛點問題:
-
重複程式碼多,複用性差:相同的業務邏輯需要維護多份程式碼,導致出現bug的機率大大增加,後期維護成本增加;
-
業務耦合度高,缺乏設計模式進行管理:更新迭代過程中處理邏輯需要相容多種場景程式碼越來越複雜,導致問題難以跟蹤,難以定位問題意味著你可能需要花大部分的時間處理問題;
-
編碼風格不一致,維護成本高: 專案主要技術棧是Vue,但是程式碼風格有大部分格使用的React的jsx形式進行開發;專案存在多人維護,個人技術參差不齊;導致後續學習成本增加;
-
元件巢狀層級深,存在雙向資料流:不符合Vue 單向資料流狀態管理理念,無法追蹤區域性狀態的變化,增加了出錯時 debug 的難度,經常出現修改一個模組bug而引起其他模組bug的情況。
三、新版架構設計
3.1 設計思路
舊版的元件隨著業務發展迭代,已經混雜著大量的業務邏輯,元件耦合嚴重,職責也越發不清晰,因此為了合理的劃分元件職責和清晰程式碼結構,新的架構設計將基於 通用元件 的設計思路,將篩選器元件抽離出BI業務;從BI專案的架構、技術選型、文件使用等多個方面進行考慮,在原來的基礎上改造太複雜,可行性低,所以搭建了一個新的專案,將之前所有的篩選器元件遷移到新專案上,穩定後替換BI專案上所有舊版篩選器元件,後續統一隻需維護一個元件庫(bi-filters)。
3.2 實現方案
篩選器元件庫(bi-filters)主要 基於Vue CLI 的 開發/構建目標/庫 能力以及 Lerna 包管理工具 進行設計開發,這種元件庫設計整合了以下特點:
-
按需引入:每個UI元件都是一個npm包,多語言、工具和樣式都是自成體系的npm包,可被業務或UI元件靈活引用,同時天然支援按需載入。
-
配置簡單:如果需要進行構建處理,那麼每個npm包可單獨進行構建配置,配置變得更加簡單。結合Vue CLI的構件庫能力,對於簡單UI元件的構建幾乎可以做到webpack零配置。
-
獨立部署:元件庫的版本迭代可以更快,不需要進行整體構建,每個元件可單獨快速釋出。
1. 利用 Lerna工具進行多包管理,快速對元件庫進行版本釋出
元件庫目錄結構:
2. 元件設計和實現
參考 裝飾器設計模式,對元件進行抽象設計,從而達到業務狀態與 UI 狀態隔離,UI 狀態與互動呈現隔離的目的。具體實現是先按功能將元件拆成展示層,邏輯層,容器層,達到元件分層可複用。再透過
$attrs/$listeners對antd元件進行二次封裝,抽離成在篩選器元件庫內的公共元件,達到互動可組合。最終使得元件邊界清晰,符合設計規範中提到的開閉原則、單一職責原則、里氏替換原則。
以文字下拉篩選器元件(TextDropDownFilter)實現為例:
(1)按功能將元件拆分成 容器層、邏輯層(搜尋框邏輯層、 下拉選單邏輯層 )、展示層(搜尋框展示層、下拉選單展示層):
(2)BI專案中使用 :引入篩選器元件後, 在BI應用層處理業務場景,將處理業務後的狀態資訊透過 Vue 插槽(Slots)的方式傳遞給底層的篩選器元件 。
<!-- page.vue一 -->
<TextDropDownFilter>
<template #addonSearchAfter>
<!-- 業務場景一 -->
<a-tooltip v-if="xxx">
<BIIcon type="icon-jilian" class="btn-jilian" v-show="xxx"></BIIcon>
</a-tooltip>
<!-- 業務場景二 -->
<a-tooltip v-if="xxx">
<AIcon type="warning" theme="filled" class="btn-warning"></AIcon>
</a-tooltip>
</template>
</TextDropDownFilter>
(3)搜尋框邏輯層:接收業務處理後的狀態,進行不同的UI組合展示
<!-- SearchHandler.vue一 -->
<template>
<div class="bd-search" :class="{ 'active': inputActive }">
<!-- 基礎搜尋框元件 一 -->
<Search
v-bind="$attrs"
:searchValue="searchValue"
:placeholder="placeholder"
@searchItem="handleSearchItem"
@pressEnter="handlePressEnter"
@focus="handleFocus"
@blur="handleBlur"
>
</Search>
<!-- 業務層傳入的UI 一 -->
<slot name="addonSearchAfter"></slot>
</div>
</template>
(4)搜尋框展示層:由 antd 基礎元件組成,提供互動單一且可複用的UI元件
<!-- Search.vue一 -->
<template>
<AInput
class="common-search-input"
:placeholder="placeholder"
:value="searchValue"
allow-clear
@change="change"
v-on="$listeners"
@pressEnter="$emit('pressEnter', $event)"
>
<AIcon slot="prefix" type="search" />
</AInput>
</template>
3. 最後利用 Vue CLI 的構建庫功能,對不同型別的篩選器元件進行單獨構建打包
vue cli 的構建庫能力可以透過 --target 選項指定不同的構建目標。它允許你將相同的原始碼根據不同的用例生成不同的構建。
在元件庫專案的 packages 目錄下,每一個篩選器元件的目錄下都需要建立 package.json檔案,用於元件的構建資訊配置:
{
"name": "@bigdata/TextDropDownFilter", //包名
"version": "0.0.0", // 版本號
"private": false, // 為true時不會被髮布
"main": "dist/編譯檔名.umd.min.js",
"scripts": {
"build": "vue-cli-service build --target lib --name 編譯檔名 --dest dist ./index.js",
"lint": "",
"test:unit": ""
},
"files": [
"dist"
],
"author": "",
"license": "ISC",
"description": ""
}
四、效果收益
1. BI專案整體程式碼量減少,元件目錄結構清晰,只需要專注維護業務邏輯
2. BI業務抽離後,篩選器元件可進行獨立維護迭代,減少程式碼耦合,只需專注功能互動和效能最佳化,提高元件穩定性。
五、總結
從上述的升級過程可以看出,元件的抽象與抽象粒度是沒有一成不變的統一標準,也沒有對與錯。元件的設計更多的應該去關注如何適配不同的業務場景和需求要求,追求更多的是“適合”。有的時候,同樣的業務場景,元件粒度的標準也會隨業務場景變化而變化,甚至可能隨場景增加而持續重構,因此為了程式碼更好的維護和分層,以及避免程式碼邏輯的過度疊加和膨脹,必須制定一些元件抽象的規範加以約束。總的來說,元件開發的方法論可能是相對中立和普適的,但元件庫的整體建設方案,與所在的行業和業務有很大的關係。不同的行業領域,對互動展現的掌控程度是不一樣的,因此設計元件庫方案的時候,應該優先從產品專案的整合關係角度出發看待問題,這樣可以保證業務的擴充和可用性儘可能不被技術方案限制。