iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0

今天我們會用以下表單作為範例來設計資料模型。

https://ithelp.ithome.com.tw/upload/images/20230919/201586154RgovqoReW.png

需求介紹

  • 課程名稱與課程說明只能有英文與數字,1到50字
  • 結束日期必須大於開始日期,開始日期大於現在日期
  • 課程名稱、日期、說明 ,如果輸入不符合規定要有包含錯誤原因的錯誤訊息
  • 如果使用者輸入是空的,停用 Add 按鈕
  • 輸入完使用者名稱後按 Add,如果查的到就新增到上方,如果查不到就顯示錯誤訊息
  • 如果選取的使用者是空的,顯示錯誤訊息
  • 如果課程名稱、日期、說明 ,不符合規定或是沒有使用者,停用 Submit 按鈕
  • 按下 Submit 按鈕的時候,如果有錯誤,要跳出錯誤提醒
  • 使用者開始編輯前每個欄位都是空的,沒有預設值,也不會有錯誤訊息

為甚麼要設計資料模型 ?

domain modeling (資料模型設計)的過程其實就是解析需求的過程 ,藉由一些技巧把需求大致上如何解決在設計草稿上過一遍,這樣就能在草稿階段用很低的修改成本把可能遇到的問題先解決掉一些,減少真的寫下去了發現錯誤又要修改的可能性。

https://ithelp.ithome.com.tw/upload/images/20230919/2015861521guPLS2La.png
來源

在進行領域驅動開發團隊合作的時候,通常還會有腦力激盪、建立共用心智模型 (shared mental model) 的過程,詳細可以參考Think in Domain-Driven Design 系列

關於如何設計資料模型我也正在學習中,有時候還是會遇到寫到一半才發現當初沒設計好的情形,真的是說起來簡單做起來難呀( ´•̥ו̥` )

開始設計資料模型 !

我們先用課程名稱當範例。

一個課程名稱有三種可能性 - 合格、不合格、初始狀態,這時候我們可以用 union type 來拆解它

union type
表示一個型別是多個型別的其中一種

type CourseName = ValidCourseName | InvalidCourseName | InitialCourseName 

不合格的課程名稱由 valuereason 組成,這時候我們可以用 product type 來拆解它

product type
表示一個型別由多個型別組成

interface InitialCourseName { 
	value: '',
}

interface ValidCourseName { 
	value: string,
}

interface InvalidCourseName { 
	value: string,
	reason: string,
}

有了 union typeproduct type 其實還不太夠,這是因為實務上還常常會需要知道「 課程名稱到底是哪一種課程名稱」並做相應的處理,但比較遺憾的是 TS 難以幫助我們從上面的範例做到這件事情,所以我們要給它一個 _tag來輔助 TS 做型別推演,也就是 建立 sum type

https://ithelp.ithome.com.tw/upload/images/20230919/20158615EgXtiA140X.png
來源

sum type
可以做型別推演的、有 tag 的 union type

interface InitialCourseName { 
	_tag: 'InitialCourseName',
	value: '',
}

interface ValidCourseName { 
	_tag: 'ValidCourseName',
	value: string,
}

interface InvalidCourseName { 
	_tag: 'InvalidCourseName',
	value: string,
	reason: string,
}

藉由 sum typeproduct type,參考以上範例以此類推,最終我們就可以把表單模型建立出來

AddCourseForm

interface AddCourseForm { 
	name: CourseName
	dateRange: DateRane
	description: CourseDescription
	users: CourseUsers
}

這邊再額外提供一個 DateRange 範例給大家參考,剩下的欄位大家有興趣可以練習看看!

DateRange

type DateRange = ValidDateRange | InvalidDateRange | InitialDateRange

interface ValidDateRange {
	_tag: "ValidDateRange"
	start: Date
	end: Date
}

interface InvalidDateRange {
	_tag: "InvalidDateRange"
	start: Date
	end: Date
	reason: string
}

interface InitialDateRange {
	_tag: "InitialDateRange"
}


上一篇
D03 - 建立靜態網頁
下一篇
D05 - 設計工作流程
系列文
從 Next.js 開始的 Functional Programming30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言