<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          編寫高質(zhì)量可維護的代碼:數(shù)據(jù)建模

          共 4357字,需瀏覽 9分鐘

           ·

          2020-08-31 23:09

          什么是數(shù)據(jù)建模

          數(shù)據(jù)建模是一種用于定義和分析數(shù)據(jù)的要求和其需要的相應(yīng)支持的信息系統(tǒng)的過程。

          隨著前端頁面的交互變得更加細膩復(fù)雜,原本存放于服務(wù)端的狀態(tài)放置在了前端,類似 flux、redux、mobx、dva、rematch、vuex 的狀態(tài)管理庫也成了每個項目的標(biāo)配。

          因為分層理念的普及,前端工程師們需要把更多精力放在數(shù)據(jù)管理上,數(shù)據(jù)建模也成了基本功。

          而建模的產(chǎn)物是數(shù)據(jù)模型,數(shù)據(jù)模型是定義數(shù)據(jù)如何輸入和輸出的一種模型,其主要作用是為信息系統(tǒng)提供數(shù)據(jù)的定義和格式。

          數(shù)據(jù)模型包括數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)操作、數(shù)據(jù)完整性約束條件這三要素。

          簡單理解就是數(shù)據(jù)模型提供了一個“模具”,數(shù)據(jù)按照預(yù)先的設(shè)計和約束進行放置。

          三要素

          數(shù)據(jù)完整性約束條件

          好的數(shù)據(jù)結(jié)構(gòu)必須要有約束,例如描述同一個狀態(tài)的字段有時候是字符串,有時候是數(shù)字,這樣的話就容易造成預(yù)期之外的情況。添加約束可以最大限度保障這份數(shù)據(jù)是干凈整齊的。

          //?status?是字符串的時候不通過
          if?(status?===?1)?{
          ??...
          }
          //?按照一定約束
          model.define(
          ??'user',
          ??{
          ????name:?{?
          ??????field:?'name',
          ??????type:?STRING(64),
          ??????allowNull:?false,?
          ??????comment:?'姓名',
          ?},
          ????sex:?{
          ???field:?'sex',
          ??????type:?INTEGER(1),
          ??????allowNull:?false,
          ??????comment:?'性別',
          ????}
          ??}
          );

          數(shù)據(jù)結(jié)構(gòu)

          描述模型本身的性質(zhì)之外,還需通過某些字段表達模型(表)和模型之間的關(guān)聯(lián)。

          數(shù)據(jù)操作

          在數(shù)據(jù)結(jié)構(gòu)上對數(shù)據(jù)或者數(shù)據(jù)之間的關(guān)聯(lián)關(guān)系的操作。

          領(lǐng)域驅(qū)動設(shè)計

          在圍繞著數(shù)據(jù)模型進行應(yīng)用開發(fā)的時候,我們會思考如何進行建模呢?

          實際上,軟件開發(fā)行業(yè)中已經(jīng)積累了一些方法論,例如領(lǐng)域驅(qū)動設(shè)計 (DDD) 就被廣泛采用。

          在進行軟件開發(fā)前,通常需要先進行業(yè)務(wù)知識梳理,而后到達軟件設(shè)計的層面,最后才是開發(fā)。而在業(yè)務(wù)知識梳理的過程中,我們必然會形成某個領(lǐng)域知識。根據(jù)領(lǐng)域知識來一步步驅(qū)動軟件設(shè)計,就是領(lǐng)域驅(qū)動設(shè)計的基本概念。簡單來說領(lǐng)域驅(qū)動設(shè)計就是關(guān)注精簡的業(yè)務(wù)模型及實現(xiàn)的匹配

          分層架構(gòu)

          按照領(lǐng)域驅(qū)動設(shè)計的分層架構(gòu)可以將應(yīng)用進行分層

          • UI 層:負責(zé)向用戶展現(xiàn)信息以及解釋用戶命令。
          • 應(yīng)用層:用來協(xié)調(diào)應(yīng)用的活動。它不包含業(yè)務(wù)邏輯;它不保留業(yè)務(wù)對象的狀態(tài);但它保有應(yīng)用任務(wù)的進度狀態(tài)。
          • 領(lǐng)域?qū)樱簶I(yè)務(wù)軟件的核心所在。在這里保留業(yè)務(wù)對象的狀態(tài),對業(yè)務(wù)對象和它們狀態(tài)的持久化被委托給了基礎(chǔ)設(shè)施層。
          • 基礎(chǔ)設(shè)施層:為其他層的支撐庫存在。它提供了層間的通信,實現(xiàn)對業(yè)務(wù)對象的持久化,包含對用戶界面層的支撐庫等作用。

          按照這個分層,越往左邊代碼變動越頻繁。隨著業(yè)務(wù)復(fù)雜,應(yīng)用層和領(lǐng)域?qū)拥倪吔缱兊媚:I(lǐng)域之間也容易交錯在一起。

          良好的設(shè)計應(yīng)該避免層與層之間產(chǎn)生過多依賴,如果代碼沒有被清晰隔離到某層中,它會迅即混亂和難以維護。

          通過分層架構(gòu)和高內(nèi)聚低耦合的設(shè)計思想,最終實現(xiàn)系統(tǒng)與需求有較好的一致性,在業(yè)務(wù)迭代中快速響應(yīng)需求變更。

          實體

          實體在領(lǐng)域模型中是必需的對象,并且它們應(yīng)該在建模過程開始時就被考慮。例如要實現(xiàn)一個“貓”的概念,我們可能會去創(chuàng)造一個 Cat 的類,這個 Cat 可能包含名稱、性別、品種等屬性,但是這些屬性都不足以區(qū)分這只貓,所以我們需要創(chuàng)建一個唯一不重復(fù)的 ID 來區(qū)分他們,也就區(qū)分實體的標(biāo)識符。

          創(chuàng)建 ID 的方式有很多種,它可以是主鍵、可以來自外部、也可以由系統(tǒng)自己產(chǎn)生,但它必須符合模型中的身份差別。

          值對象

          用來描述領(lǐng)域的特殊方面,且沒有標(biāo)識符的一個對象,叫做值對象。例如畫布上的一個點 Customer 會跟姓名、省份、城市、區(qū)、街道相關(guān)。最好是將地址分離出來,保留對地址的引用,因為它們都是同一個址屬性。

          服務(wù)

          你可以簡單地將行為理解成一種服務(wù)。例如你去商店購買商品,你的朋友也可以去購買商品。如果將購買這個能力作為一個屬性放在 Person 這個實體里顯然有點不對勁,因為“去購買”這個功能并不屬于你和你的朋友(實體或者值對象),同時去購買也可能涉及到商品對象。

          保證服務(wù)的單一性和隔離非常重要,注意區(qū)分領(lǐng)域服務(wù)和應(yīng)用服務(wù)。決定一個服務(wù)所應(yīng)歸屬的層是非常困難的事情,我們在設(shè)計階段建立模型時,需要確保領(lǐng)域?qū)颖3謴钠渌麑又懈綦x開來。

          模塊

          模塊是一種被用來作為組織相關(guān)概念和任務(wù)以便降低復(fù)雜性的方法,通常情況下由功能或者邏輯上屬于一體的元素構(gòu)成,以保證高內(nèi)聚,同時通過接口的形式暴露給第三方以降低模塊之間的耦合。

          聚合

          聚合是針對數(shù)據(jù)變化可以考慮成一個單元的一組相關(guān)對象。聚合基于(有且僅有)一個實體(根),聚合通過這個根被外部訪問,它可以引用任意聚合或者被其他聚合引用。以下是一個簡單的聚合例子:客戶作為聚合的根,其他信息都是客戶內(nèi)部的,如果需要地址則將地址的拷貝傳遞出去( Javascript 中特別需要注意)。

          工廠

          工廠用來封裝對象創(chuàng)建所必需的知識,它們對創(chuàng)建聚合特別有用。工廠方法是一個對象的方法,包含并隱藏了創(chuàng)建其他對象的必要知識。

          資源庫

          資源庫作為一個全局可訪問對象的存儲點而存在。它是一個獨立的層,介于領(lǐng)域?qū)优c數(shù)據(jù)映射層(數(shù)據(jù)訪問層)之間。它的存在讓領(lǐng)域?qū)痈杏X不到數(shù)據(jù)訪問層的存在,它提供一個類似集合的接口,提供給領(lǐng)域?qū)舆M行領(lǐng)域?qū)ο蟮脑L問。

          前端的數(shù)據(jù)建模

          數(shù)據(jù)建模和后端的工作關(guān)聯(lián)較為緊密,前端的數(shù)據(jù)模型更多是依賴后端傳遞的數(shù)據(jù)傳輸對象(DTO)進行二次構(gòu)建。無論二次構(gòu)建是發(fā)生在服務(wù)端聚合階段還是用戶端 AJAX 請求完成階段,前端都需要參與一定的數(shù)據(jù)清洗,并應(yīng)用到前端的數(shù)據(jù)模型之上。

          領(lǐng)域劃分

          現(xiàn)在你可以開始嘗試劃分你應(yīng)用內(nèi)的業(yè)務(wù)領(lǐng)域。以一個商城為例子,它可能會包括用戶、商品、貨架、訂單、結(jié)算、賬戶等內(nèi)容。

          每一個業(yè)務(wù)領(lǐng)域都可以至少拆分成一個領(lǐng)域,按照業(yè)務(wù)領(lǐng)域來組織代碼,例如在交易領(lǐng)域中按照以下目錄結(jié)構(gòu)劃分:

          src
          modules
          ...
          trading # 交易領(lǐng)域
          components/ # 組件
          models/ # models
          pages/ # 頁面
          redux/ # redux
          services/ # 交易模塊相關(guān)api
          styles/ # 交易模塊樣式
          index.ts
          ...

          概念模型

          數(shù)據(jù)建模的前提是對業(yè)務(wù)的充分理解,充分理解業(yè)務(wù)相當(dāng)于在更高的視角去看待業(yè)務(wù)之間的關(guān)系,有利于更好地完成模型建設(shè)。

          嘗試回想一下你所維護的業(yè)務(wù)(應(yīng)用)場景,你是否清晰業(yè)務(wù)場景和業(yè)務(wù)對象之間的關(guān)系以及具體交互?

          使用思維導(dǎo)圖梳理出概念模型,這個階段可以不用嚴(yán)格遵守三要素,目標(biāo)清晰表達現(xiàn)實世界就行。

          定義模型

          定義模型可以依據(jù)概念模型,補充細節(jié)和關(guān)聯(lián)關(guān)系,例如簡單定義一個營銷商品:

          以上展示了商場貨架上劃分的一塊活動區(qū)域,規(guī)則是滿 XX 減 XX,再將參與該活動的商品在區(qū)域內(nèi)進行上架。

          降低復(fù)雜度

          在大部分情況下,特別是展示邏輯這塊,前端不應(yīng)該是重邏輯的。

          以商品為例,不同商品的營銷類型背后隱藏著復(fù)雜的價格體系,盡管是同一種營銷類型,商品在不同的狀態(tài)展示的價格也不一定相同。你可以想象這背后的字段,以及計算規(guī)則。

          假如后端把這些字段、各種 price 和規(guī)則一股腦拋給你,先不談前后端對稱問題,光挑字段都能讓你目瞪狗呆。

          遇到類似情況更好的辦法是:盡量避免在前端(用戶端)去處理復(fù)雜的業(yè)務(wù)判斷,在聚合層或者讓后端同學(xué)給你處理好這些展示邏輯。

          特別是在 C 端場景下,數(shù)據(jù)直出顯得更加重要,同時前端同學(xué)也有更多時間去做性能優(yōu)化(早點下班不香么?)。

          另外一個好處是假如出現(xiàn)展示問題,你只要確定讀取的字段正確,剩下的僅需一個人排查就夠了;

          //?Bad
          const?switchPrice?=?product?=>?{
          ??switch(product.status)?{
          ????case?0:
          ?????return?product.priceA;
          ????case?1:
          ?????return?product.priceB;
          ????case?2:
          ?????return?product.priceB;
          ????default:
          ?????return??product.priceBase;
          ??}
          }

          ?????
          //?Good
          <Price?value={product.price}/>

          邏輯分層

          設(shè)計上需要區(qū)分應(yīng)用邏輯(業(yè)務(wù)邏輯)和展示邏輯。應(yīng)用層注重對領(lǐng)域?qū)拥恼{(diào)度,是業(yè)務(wù)邏輯的實現(xiàn),展示層專注渲染和交互動作。

          在一個大型項目中,同一個 Model 可能被多處引用,你很難確定誰最終會對同一份數(shù)據(jù)進行怎樣的操作。

          同時 Model 中僅保留數(shù)據(jù)源的抽象結(jié)構(gòu),而不修改數(shù)據(jù)源的內(nèi)容。

          //?在視圖層只做展示邏輯處理
          //?組件A
          ...
          <>
          ?<span>日期:{format(res.date, 'YYYY-MM-DD')}span>


          //?組件B
          ...
          <>
          ?<span>日期:{format(res.date, 'YYYY-MM')}span>


          統(tǒng)一字段

          在設(shè)計模型的時候,盡可能與后端保持統(tǒng)一字段。比如某些表單場景在回顯和提交的時候要多一層轉(zhuǎn)換,后期維護會帶來多一層心智負擔(dān)。在前后端分離的開發(fā)模式下,不一定能保證后端會先給出字段,我的習(xí)慣是標(biāo)記字段,等聯(lián)調(diào)的時候全局替換一下就行了。

          簡化字段、明確語義、改變不合理的前后端交互是做好數(shù)據(jù)建模的基礎(chǔ),否則你將花費大量時間去理解這些字段背后的含義和計算規(guī)則。

          小結(jié)

          沒有一個十全十美的數(shù)據(jù)模型可以適用任何需求場景,模型的落地需要綜合考慮業(yè)務(wù)實際場景和技術(shù)選型。在構(gòu)建模型的過程中,鍛煉系統(tǒng)性思考能力、從更高的視角看待業(yè)務(wù),才能創(chuàng)造出一個生命周期更長的模型。


          ??看完三件事

          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:

          1. 點贊,讓更多的人也能看到介紹內(nèi)容(收藏不點贊,都是耍流氓-_-)
          2. 關(guān)注公眾號“前端勸退師”,不定期分享原創(chuàng)知識。
          3. 也看看其他文章

          勸退師個人微信:huab119

          也可以來我的GitHub博客里拿所有文章的源文件:

          前端勸退指南:https://github.com/roger-hiro/BlogFN一起玩耍呀

          瀏覽 55
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  另类视频网站 | 天天撸在线播放 | 免费观看日本污的视频 | 大鸡巴在线播放 | 亚洲av电影院 |