編寫高質量可維護的代碼:數據建模

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼是數據建模"}]},{"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":"數據建模是一種用於定義和分析數據的要求和其需要的相應支持的信息系統的過程。"}]},{"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":"隨着前端頁面的交互變得更加細膩複雜,原本存放於服務端的狀態放置在了前端,類似 flux、redux、mobx、dva、rematch、vuex 的狀態管理庫也成了每個項目的標配。"}]},{"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":"因爲分層理念的普及,前端工程師們需要把更多精力放在數據管理上,數據建模也成了基本功。"}]},{"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":"而建模的產物是"},{"type":"text","marks":[{"type":"strong"}],"text":"數據模型"},{"type":"text","text":",數據模型是定義數據如何輸入和輸出的一種模型,其主要作用是爲信息系統提供數據的定義和格式。"}]},{"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":"數據模型包括"},{"type":"text","marks":[{"type":"strong"}],"text":"數據結構、數據操作、數據完整性約束條件"},{"type":"text","text":"這三要素。"}]},{"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":"簡單理解就是數據模型提供了一個“模具”,數據按照預先的設計和約束進行放置。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"三要素"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"數據完整性約束條件"}]},{"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":"好的數據結構必須要有約束,例如描述同一個狀態的字段有時候是字符串,有時候是數字,這樣的話就容易造成預期之外的情況。添加約束可以最大限度保障這份數據是乾淨整齊的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\/\/ status 是字符串的時候不通過\nif (status === 1) {\n  ...\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\/\/ 按照一定約束\nmodel.define(\n  'user',\n  {\n    name: { \n      field: 'name',\n      type: STRING(64),\n      allowNull: false, \n      comment: '姓名',\n },\n    sex: {\n   field: 'sex',\n      type: INTEGER(1),\n      allowNull: false,\n      comment: '性別',\n    }\n  }\n);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"數據結構"}]},{"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":"描述模型本身的性質之外,還需通過某些字段表達模型(表)和模型之間的關聯。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"數據操作"}]},{"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":"在數據結構上對數據或者數據之間的關聯關係的操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"領域驅動設計"}]},{"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":"在圍繞着數據模型進行應用開發的時候,我們會思考如何進行建模呢?"}]},{"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":"實際上,軟件開發行業中已經積累了一些方法論,例如領域驅動設計 (DDD) 就被廣泛採用。"}]},{"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":"在進行軟件開發前,通常需要先進行業務知識梳理,而後到達軟件設計的層面,最後纔是開發。而在業務知識梳理的過程中,我們必然會形成某個領域知識。根據領域知識來一步步驅動軟件設計,就是領域驅動設計的基本概念。簡單來說領域驅動設計就是"},{"type":"text","marks":[{"type":"strong"}],"text":"關注精簡的業務模型及實現的匹配"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"分層架構"}]},{"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":"按照領域驅動設計的分層架構可以將應用進行分層"}]},{"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":"UI 層:負責向用戶展現信息以及解釋用戶命令。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"應用層:用來協調應用的活動。它不包含業務邏輯;它不保留業務對象的狀態;但它保有應用任務的進度狀態。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域層:業務軟件的核心所在。在這裏保留業務對象的狀態,對業務對象和它們狀態的持久化被委託給了基礎設施層。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基礎設施層:爲其他層的支撐庫存在。它提供了層間的通信,實現對業務對象的持久化,包含對用戶界面層的支撐庫等作用。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/3e\/3eed82fa5bf35e5877089e99dc087aa1.png","alt":"Image","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":"按照這個分層,越往左邊代碼變動越頻繁。隨着業務複雜,應用層和領域層的邊界變得模糊,領域之間也容易交錯在一起。"}]},{"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":"良好的設計應該避免層與層之間產生過多依賴,如果代碼沒有被清晰隔離到某層中,它會迅即混亂和難以維護。"}]},{"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":"通過分層架構和高內聚低耦合的設計思想,最終實現系統與需求有較好的一致性,在業務迭代中快速響應需求變更。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"實體"}]},{"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":"實體在領域模型中是必需的對象,並且它們應該在建模過程開始時就被考慮。例如要實現一個“貓”的概念,我們可能會去創造一個 Cat 的類,這個 Cat 可能包含名稱、性別、品種等屬性,但是這些屬性都不足以區分這隻貓,所以我們需要創建一個唯一不重複的 ID 來區分他們,也就區分實體的標識符。"}]},{"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":"創建 ID 的方式有很多種,它可以是主鍵、可以來自外部、也可以由系統自己產生,但它必須符合模型中的身份差別。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"值對象"}]},{"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":"用來描述領域的特殊方面,且沒有標識符的一個對象,叫做值對象。例如畫布上的一個點 Customer 會跟姓名、省份、城市、區、街道相關。最好是將地址分離出來,保留對地址的引用,因爲它們都是同一個址屬性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/17\/17195964507dbae70e81b5e5927920e4.png","alt":"Image","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":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"服務"}]},{"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":"你可以簡單地將行爲理解成一種服務。例如你去商店購買商品,你的朋友也可以去購買商品。如果將購買這個能力作爲一個屬性放在 Person 這個實體裏顯然有點不對勁,因爲“去購買”這個功能並不屬於你和你的朋友(實體或者值對象),同時去購買也可能涉及到商品對象。"}]},{"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":"保證服務的單一性和隔離非常重要,注意區分領域服務和應用服務。決定一個服務所應歸屬的層是非常困難的事情,我們在設計階段建立模型時,需要確保領域層保持從其他層中隔離開來。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"模塊"}]},{"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":"模塊是一種被用來作爲組織相關概念和任務以便降低複雜性的方法,通常情況下由功能或者邏輯上屬於一體的元素構成,以保證高內聚,同時通過接口的形式暴露給第三方以降低模塊之間的耦合。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"聚合"}]},{"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":"聚合是針對數據變化可以考慮成一個單元的一組相關對象。聚合基於(有且僅有)一個實體(根),聚合通過這個根被外部訪問,它可以引用任意聚合或者被其他聚合引用。以下是一個簡單的聚合例子:客戶作爲聚合的根,其他信息都是客戶內部的,如果需要地址則將地址的拷貝傳遞出去( Javascript 中特別需要注意)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e4\/e4605e9075c43b97c49b7ef2e76b0648.png","alt":"Image","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":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"工廠"}]},{"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":"工廠用來封裝對象創建所必需的知識,它們對創建聚合特別有用。工廠方法是一個對象的方法,包含並隱藏了創建其他對象的必要知識。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"資源庫"}]},{"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":"資源庫作爲一個全局可訪問對象的存儲點而存在。它是一個獨立的層,介於領域層與數據映射層(數據訪問層)之間。它的存在讓領域層感覺不到數據訪問層的存在,它提供一個類似集合的接口,提供給領域層進行領域對象的訪問。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"前端的數據建模"}]},{"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":"數據建模和後端的工作關聯較爲緊密,前端的數據模型更多是依賴後端傳遞的數據傳輸對象(DTO)進行二次構建。無論二次構建是發生在服務端聚合階段還是用戶端 AJAX 請求完成階段,前端都需要參與一定的數據清洗,並應用到前端的數據模型之上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"領域劃分"}]},{"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":"現在你可以開始嘗試劃分你應用內的業務領域。以一個商城爲例子,它可能會包括用戶、商品、貨架、訂單、結算、賬戶等內容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/7c\/7c22dcdea6901ad7f726005bbbfeaea9.png","alt":"Image","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":"每一個業務領域都可以至少拆分成一個領域,按照業務領域來組織代碼,例如在交易領域中按照以下目錄結構劃分:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"src\n modules\n ...\n trading # 交易領域\n components\/ # 組件\n models\/ # models\n pages\/ # 頁面\n redux\/ # redux\n services\/ # 交易模塊相關api\n styles\/ # 交易模塊樣式\n index.ts\n ...\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"概念模型"}]},{"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":"數據建模的前提是對業務的充分理解,充分理解業務相當於在更高的視角去看待業務之間的關係,有利於更好地完成模型建設。"}]},{"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":"嘗試回想一下你所維護的業務(應用)場景,你是否清晰業務場景和業務對象之間的關係以及具體交互?"}]},{"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":"使用思維導圖梳理出概念模型,這個階段可以不用嚴格遵守三要素,目標清晰表達現實世界就行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/45\/452ced003fda4447455c457f2584561f.webp","alt":"Image","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":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"定義模型"}]},{"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":"定義模型可以依據概念模型,補充細節和關聯關係,例如簡單定義一個營銷商品:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ee\/eebe1e72ba653f819e47bb04f70b1ee1.png","alt":"Image","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":"以上展示了商場貨架上劃分的一塊活動區域,規則是滿 XX 減 XX,再將參與該活動的商品在區域內進行上架。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"降低複雜度"}]},{"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":"在大部分情況下,特別是展示邏輯這塊,前端不應該是重邏輯的。"}]},{"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":"以商品爲例,不同商品的營銷類型背後隱藏着複雜的價格體系,儘管是同一種營銷類型,商品在不同的狀態展示的價格也不一定相同。你可以想象這背後的字段,以及計算規則。"}]},{"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":"假如後端把這些字段、各種 "},{"type":"codeinline","content":[{"type":"text","text":"price"}]},{"type":"text","text":" 和規則一股腦拋給你,先不談前後端對稱問題,光挑字段都能讓你目瞪狗呆。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ed\/ed77bb3db890773542c504b2cae5a785.webp","alt":"Image","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":"遇到類似情況更好的辦法是:"},{"type":"text","marks":[{"type":"strong"}],"text":"儘量避免在前端(用戶端)去處理複雜的業務判斷"},{"type":"text","text":",在聚合層或者讓後端同學給你處理好這些展示邏輯。"}]},{"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":"特別是在 C 端場景下,數據直出顯得更加重要,同時前端同學也有更多時間去做性能優化(早點下班不香麼?)。"}]},{"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":"另外一個好處是假如出現展示問題,你只要確定讀取的字段正確,剩下的僅需一個人排查就夠了;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"\/\/ Bad\nconst switchPrice = product => {\n switch(product.status) {\n case 0:\n return product.priceA;\n case 1:\n return product.priceB;\n case 2:\n return product.priceB;\n default:\n return product.priceBase;\n }\n}\n\n \n\/\/ Good\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"邏輯分層"}]},{"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":"設計上需要區分應用邏輯(業務邏輯)和展示邏輯。應用層注重對領域層的調度,是業務邏輯的實現,展示層專注渲染和交互動作。"}]},{"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":"在一個大型項目中,同一個 Model 可能被多處引用,你很難確定誰最終會對同一份數據進行怎樣的操作。"}]},{"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":"同時 Model 中僅保留數據源的抽象結構,而不修改數據源的內容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\/\/ 在視圖層只做展示邏輯處理\n\/\/ 組件A\n...\n<>\n 日期:{format(res.date, 'YYYY-MM-DD')}\n\n\n\/\/ 組件B\n...\n<>\n 日期:{format(res.date, 'YYYY-MM')}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"統一字段"}]},{"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":"在設計模型的時候,儘可能與後端保持統一字段。比如某些表單場景在回顯和提交的時候要多一層轉換,後期維護會帶來多一層心智負擔。在前後端分離的開發模式下,不一定能保證後端會先給出字段,我的習慣是標記字段,等聯調的時候全局替換一下就行了。"}]},{"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":"簡化字段、明確語義、改變不合理的前後端交互是做好數據建模的基礎,否則你將花費大量時間去理解這些字段背後的含義和計算規則。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"小結"}]},{"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":"沒有一個十全十美的數據模型可以適用任何需求場景,模型的落地需要綜合考慮業務實際場景和技術選型。在構建模型的過程中,鍛鍊系統性思考能力、從更高的視角看待業務,才能創造出一個生命週期更長的模型。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"頭圖:Unsplash"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者:村雨"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文:https:\/\/mp.weixin.qq.com\/s\/RLuIX4O31PhcPCgMWivi7w"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文:編寫高質量可維護的代碼:數據建模"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來源:政採雲前端團隊 - 微信公衆號 [ID:Zoo-Team]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"轉載:著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章