作者:vivo 互聯(lián)網大數據團隊-Wang Lei
本文是vivo互聯(lián)網大數據團隊《BI數據可視化平臺建設》系列文章第2篇 -篩選器組件蔬将。
本文主要介紹了BI數據可視化平臺建設中比較核心的篩選器組件, 涉及組件分類夭谤、組件庫開發(fā)等升級實踐經驗,通過分享一些對交互和業(yè)務耦合度高的組件開發(fā)迭代的思考束铭,希望可以給正在做組件重構解耦的讀者帶來啟發(fā)炭分。
往期系列文章:BI 數據可視化平臺建設(1)—交叉表組件演變實戰(zhàn)
一蒋院、引言
BI產品通常包含大量復雜的數據信息亏钩,需要對其進行快速和準確的處理和分析。篩選器可以幫助BI產品的用戶快速地定位所需信息欺旧,并從海量數據中篩選出有用的數據姑丑,以便進行深入的分析和決策。敏捷BI作為公司內部用戶數最多的可視化平臺辞友,隨著平臺的業(yè)務增長和版本迭代栅哀,其篩選器功能也越來越豐富和完善,舊的設計架構也顯得越來越臃腫且難以維護称龙,為了提高篩選器使用的穩(wěn)定性和降低后續(xù)迭代維護成本留拾,篩選器的架構升級已經不可避免了,本文主要給大家介紹一下篩選器組件的架構升級實踐經驗鲫尊。
二痴柔、前期設計
2.1 組件選型
前期篩選器組件的職責和交互比較簡單,主要是對圖表數據進行單向的數據過濾马昨,并沒有應用到其他的業(yè)務場景中竞帽,所以前期的組件設計主要以 業(yè)務組件 的思路進行開發(fā)實現(xiàn)。
2.2 組件分類
組件類型主要可以分為業(yè)務組件和通用組件兩種鸿捧,它們在組件的狀態(tài)管理和界面渲染的設計和實現(xiàn)上是完全不同的。
但無論是業(yè)務組件或者通用組件都具備組件本質所包含的三個性質 擴展疙渣、通用匙奴、健壯:
擴展性:在原有組件基礎上可 二次封裝 擴展成新的組件符合設計的開閉原則。
通用性:根據組件接受的參數和組件中與業(yè)務的解耦比來衡量組件的通用性妄荔,并不是通用性占比100%的組件就是最好的組件泼菌,需要根據 不同的場景 分析谍肤。
健壯性:避免組件中參數處理和函數執(zhí)行過程可能出現(xiàn)的奔潰和錯誤導致程序的直接掛斷,單測以對組件內部 做好邊界處理哗伯,異常錯誤的捕獲來衡量這一標準荒揣。
因此兩種組件類型沒有絕對優(yōu)劣之分,重要的是在保證組件設計的基本原則不變的情況下焊刹,根據不同的業(yè)務場景和需求選擇合適的類型 系任。無論哪種組件,隨著不斷擴展虐块,使其通用性提升俩滥,必然就會降低組件的易用性質;而不斷豐富一個組件贺奠,也會導致其組件代碼過長霜旧、組件使命不單一、不易讀儡率、不易維護挂据;因此組件設計除了要保證組件的基本性質,還要通過明確組件職責儿普、組件拆分粒度以及良好的代碼結構和Api設計規(guī)范對組件的迭代進行約束棱貌,避免代碼邏輯的過度疊加和膨脹。
2.3 背景痛點
舊版篩選器組件設計存在維護成本高且問題BUG多等問題箕肃,主要由兩個原因造成婚脱,第一個是業(yè)務發(fā)展,隨著業(yè)務的快速增長勺像,篩選器組件的功能也越來越豐富和完善障贸,由原來的單一功能升級成可以支持數據預警、個性化分析等多種業(yè)務場景的核心模塊吟宦;第二個是缺乏規(guī)范約束篮洁,主要是缺少良好的代碼結構和清晰的組件職責等規(guī)范約束,導致業(yè)務邏輯過度疊加殃姓,粒度拆分不合理袁波,文件多,且文件名不規(guī)范蜗侈。最終導致了篩選器組件的穩(wěn)定性越發(fā)不可控篷牌。
由于前期設計不合理和缺乏規(guī)范約束,篩選器組件經過了一段時間的野蠻式迭代擴展帶來了以下的痛點問題:
重復代碼多踏幻,復用性差:相同的業(yè)務邏輯需要維護多份代碼枷颊,導致出現(xiàn)bug的概率大大增加,后期維護成本增加;
業(yè)務耦合度高夭苗,缺乏設計模式進行管理:更新迭代過程中處理邏輯需要兼容多種場景代碼越來越復雜信卡,導致問題難以跟蹤,難以定位問題意味著你可能需要花大部分的時間處理問題题造;
編碼風格不一致傍菇,維護成本高: 項目主要技術棧是Vue,但是代碼風格有大部分格使用的React的jsx形式進行開發(fā)界赔;項目存在多人維護丢习,個人技術參差不齊;導致后續(xù)學習成本增加仔蝌;
組件嵌套層級深泛领,存在雙向數據流:不符合Vue 單向數據流狀態(tài)管理理念,無法追蹤局部狀態(tài)的變化敛惊,增加了出錯時 debug 的難度渊鞋,經常出現(xiàn)修改一個模塊bug而引起其他模塊bug的情況。
三瞧挤、新版架構設計
3.1 設計思路
舊版的組件隨著業(yè)務發(fā)展迭代锡宋,已經混雜著大量的業(yè)務邏輯,組件耦合嚴重特恬,職責也越發(fā)不清晰执俩,因此為了合理的劃分組件職責和清晰代碼結構,新的架構設計將基于 通用組件 的設計思路癌刽,將篩選器組件抽離出BI業(yè)務役首;從BI項目的架構、技術選型显拜、文檔使用等多個方面進行考慮衡奥,在原來的基礎上改造太復雜,可行性低远荠,所以搭建了一個新的項目矮固,將之前所有的篩選器組件遷移到新項目上,穩(wěn)定后替換BI項目上所有舊版篩選器組件譬淳,后續(xù)統(tǒng)一只需維護一個組件庫(bi-filters)档址。
3.2 實現(xiàn)方案
篩選器組件庫(bi-filters)主要 基于Vue CLI 的 開發(fā)/構建目標/庫 能力以及 Lerna 包管理工具 進行設計開發(fā),這種組件庫設計集成了以下特點:
按需引入:每個UI組件都是一個npm包邻梆,多語言守伸、工具和樣式都是自成體系的npm包,可被業(yè)務或UI組件靈活引用确虱,同時天然支持按需加載含友。
配置簡單:如果需要進行構建處理替裆,那么每個npm包可單獨進行構建配置校辩,配置變得更加簡單窘问。結合Vue CLI的構件庫能力,對于簡單UI組件的構建幾乎可以做到webpack零配置宜咒。
獨立部署:組件庫的版本迭代可以更快惠赫,不需要進行整體構建,每個組件可單獨快速發(fā)布故黑。
1. 利用 Lerna工具進行多包管理儿咱,快速對組件庫進行版本發(fā)布
組件庫目錄結構:
2. 組件設計和實現(xiàn)
參考 裝飾器設計模式,對組件進行抽象設計场晶,從而達到業(yè)務狀態(tài)與 UI 狀態(tài)隔離混埠,UI 狀態(tài)與交互呈現(xiàn)隔離的目的。具體實現(xiàn)是先按功能將組件拆成展示層诗轻,邏輯層钳宪,容器層,達到組件分層可復用扳炬。再通過
listeners對antd組件進行二次封裝吏颖,抽離成在篩選器組件庫內的公共組件,達到交互可組合恨樟。最終使得組件邊界清晰半醉,符合設計規(guī)范中提到的開閉原則、單一職責原則劝术、里氏替換原則缩多。
以文本下拉篩選器組件(TextDropDownFilter)實現(xiàn)為例:
(1)按功能將組件拆分成 容器層、邏輯層(搜索框邏輯層养晋、 下拉列表邏輯層 )衬吆、展示層(搜索框展示層、下拉列表展示層):
(2)BI項目中使用 :引入篩選器組件后匙握, 在BI應用層處理業(yè)務場景咆槽,將處理業(yè)務后的狀態(tài)信息通過 Vue 插槽(Slots)的方式傳遞給底層的篩選器組件 。
<!-- page.vue一 -->
<TextDropDownFilter>
<template #addonSearchAfter>
<!-- 業(yè)務場景一 -->
<a-tooltip v-if="xxx">
<BIIcon type="icon-jilian" class="btn-jilian" v-show="xxx"></BIIcon>
</a-tooltip>
<!-- 業(yè)務場景二 -->
<a-tooltip v-if="xxx">
<AIcon type="warning" theme="filled" class="btn-warning"></AIcon>
</a-tooltip>
</template>
</TextDropDownFilter>
(3)搜索框邏輯層:接收業(yè)務處理后的狀態(tài)圈纺,進行不同的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>
<!-- 業(yè)務層傳入的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 目錄下,每一個篩選器組件的目錄下都需要創(chuàng)建 package.json文件蛔琅,用于組件的構建信息配置:
{
"name": "@bigdata/TextDropDownFilter", //包名
"version": "0.0.0", // 版本號
"private": false, // 為true時不會被發(fā)布
"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": ""
}
四胎许、效果收益
- BI項目整體代碼量減少,組件目錄結構清晰,只需要專注維護業(yè)務邏輯
2. BI業(yè)務抽離后辜窑,篩選器組件可進行獨立維護迭代钩述,減少代碼耦合,只需專注功能交互和性能優(yōu)化穆碎,提高組件穩(wěn)定性牙勘。
五、總結
從上述的升級過程可以看出所禀,組件的抽象與抽象粒度是沒有一成不變的統(tǒng)一標準方面,也沒有對與錯。組件的設計更多的應該去關注如何適配不同的業(yè)務場景和需求要求色徘,追求更多的是“適合”恭金。有的時候,同樣的業(yè)務場景褂策,組件粒度的標準也會隨業(yè)務場景變化而變化横腿,甚至可能隨場景增加而持續(xù)重構,因此為了代碼更好的維護和分層辙培,以及避免代碼邏輯的過度疊加和膨脹蔑水,必須制定一些組件抽象的規(guī)范加以約束⊙锶铮總的來說搀别,組件開發(fā)的方法論可能是相對中立和普適的,但組件庫的整體建設方案尾抑,與所在的行業(yè)和業(yè)務有很大的關系歇父。不同的行業(yè)領域,對交互展現(xiàn)的掌控程度是不一樣的再愈,因此設計組件庫方案的時候榜苫,應該優(yōu)先從產品項目的集成關系角度出發(fā)看待問題,這樣可以保證業(yè)務的拓展和可用性盡可能不被技術方案限制翎冲。