💡退屈な言い方をするなら、「要件を実装可能な状態にする作業」
要求からビジネスモデルを定義づける設計と実現するために必要な実装設計は分けて考える
💡設計ではビジネスの本質を押さえることを意識する
💡将来的に実装方法が変わったとしてもそのまま使える設計がよい設計
→ 誰にでも誤解なくわかる
= 誰でも理解できる状態
→ 書いた人にだけわかる
= 設計した人しか理解できない
💡技術的に優れていても、過度に高度な手法で実現するのは悪い設計
→ そのためにドキュメントとして残す
💡いにしえの古文書でも解読できたらありがたいことがある
設計段階で不具合がないことを証明したい
“おまえたちの作っているものはプログラムではない。バグだ。”
過去に検証を専門にしている人に言われた言葉
💡実装設計ではとにかくシンプルに実現すること
fac :: Integer -> Integer
fac 0 = 1
fac n | n > 0 = n * fac (n-1)
collatz :: Int -> [Int]
collatz 1 = 1 : []
collatz n | n `mod` 2 == 0 = n : collatz (n `div` 2)
| otherwise = n : collatz (n * 3 + 1)
💡設計、実装設計ともに記述すべき仕様の一つ
$$ \tiny{ \begin{equation} \begin{aligned} \{n=8\} \\ EightQueens(n) \{ \\ {\forall}_{i,j}.1{\leq}i{\leq}n{\land}1{\leq}j{\leq}n {\Rightarrow} (X(i,j)=0{\lor}X(i,j)=1){\land} \\ \textstyle\sum_{k=1}^n(\sum_{m=1}^nX(k,m))=n {\land} \\ {\forall}_{i}.1{\leq}i{\leq}n {\Rightarrow} \textstyle\sum_{k=1}^nX(i,k)=\sum_{k=1}^nX(k,i)=1 {\land} \\ {\forall}_{k}.3{\leq}k{\leq}{n+1} {\Rightarrow} \textstyle\sum_{i=1}^{k-1}X(i,k-i){\leq}1 {\land} \\ {\forall}_{k}.2{\leq}k{\leq}{n-1} {\Rightarrow} \textstyle\sum_{i=k}^nX(i,k+n-i){\leq}1 {\land} \\ {\forall}_{k}.1{\leq}k{\leq}{n-1} {\Rightarrow} \textstyle\sum_{i=1}^{n+1-k}X(i,i+k-1){\leq}1 {\land} \\ {\forall}_{k}.2{\leq}k{\leq}{n-1} {\Rightarrow} \textstyle\sum_{i=1}^{n+1-k}X(k+i-1,i){\leq}1 \} \end{aligned} \end{equation} } $$
$$ \tiny{ {\forall}_{i,j}.1{\leq}i{\leq}n{\land}1{\leq}j{\leq}n {\Rightarrow} (X(i,j)=0{\lor}X(i,j)=1) } $$
$$ \tiny{ \textstyle\sum_{k=1}^n(\sum_{m=1}^nX(k,m))=n } $$
$$ \tiny{ {\forall}_{i}.1{\leq}i{\leq}n {\Rightarrow} \textstyle\sum_{k=1}^nX(i,k)=\sum_{k=1}^nX(k,i)=1 } $$
$$ \tiny{ {\forall}_{k}.3{\leq}k{\leq}{n+1} {\Rightarrow} \textstyle\sum_{i=1}^{k-1}X(i,k-i){\leq}1 } $$
$$ \tiny{ {\forall}_{k}.2{\leq}k{\leq}{n-1} {\Rightarrow} \textstyle\sum_{i=k}^nX(i,k+n-i){\leq}1 } $$
$$ \tiny{ {\forall}_{k}.1{\leq}k{\leq}{n-1} {\Rightarrow} \textstyle\sum_{i=1}^{n+1-k}X(i,i+k-1){\leq}1 } $$
$$ \tiny{ {\forall}_{k}.2{\leq}k{\leq}{n-1} {\Rightarrow} \textstyle\sum_{i=1}^{n+1-k}X(k+i-1,i){\leq}1 } $$
import Control.Monad (foldM)
import Data.List ((\\))
main :: IO ()
main = mapM_ print $ queens 8
queens :: Int -> [[Int]]
queens n = foldM f [] [1..n] where
f qs _ = [q:qs | q <- [1..n] \\ qs, q `notDiag` qs]
q `notDiag` qs = and [abs (q - qi) /= i | (qi, i) <- qs `zip` [1..]]
💡設計の正しさがプログラムの正しさにつながる
DSM は要素間の依存を明らかにし、順序関係、フィードバック、構造をモデル化して整理できる
屋根 | 壁 | 柱 | 基礎 | 床 | 窓 | |
---|---|---|---|---|---|---|
屋根 | - | x | x | x | ||
壁 | - | x | x | |||
柱 | - | x | ||||
基礎 | - | |||||
床 | x | - | ||||
窓 | x | x | x | - |
基礎 | 床 | 柱 | 壁 | 窓 | 屋根 | |
---|---|---|---|---|---|---|
基礎 | - | |||||
床 | x | - | ||||
柱 | x | - | ||||
壁 | x | x | - | |||
窓 | x | x | x | - | ||
屋根 | x | x | x | - |
基礎 | 床 | 柱 | 壁 | 窓 | 屋根 | |
---|---|---|---|---|---|---|
基礎 | - | |||||
床 | x | - | ||||
柱 | x | - | ||||
壁 | x | x | - | x | ||
窓 | x | x | x | - | ||
屋根 | x | x | x | - |
基礎 | 床 | 柱 | 壁 | 窓 | 屋根 | |
---|---|---|---|---|---|---|
源三 | x | |||||
源九郎 | x | x | ||||
カンナ | x | |||||
八波 | x | |||||
刃渡 | x |
基礎 | 床 | 柱 | 壁 | 窓 | 屋根 | 源三 | 源九郎 | カンナ | 八波 | 刃渡 | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|
基礎 | - | |||||||||||
床 | x | - | ||||||||||
柱 | x | - | ||||||||||
壁 | x | x | - | |||||||||
窓 | x | x | x | - | ||||||||
屋根 | x | x | x | - | ||||||||
源三 | x | - | x | x | x | |||||||
源九郎 | x | x | - | |||||||||
カンナ | x | - | x | x | ||||||||
八波 | x | x | - | x | ||||||||
刃渡 | x | x | x | - |
💡「いつか見るかも」という参照しないドキュメントは作らない
💡経緯などあまりにも時系列が離れる場合は、そのときに判断すればよいことが多い
→ だったら、もう実装した方がよい
💡「設計する意味がわからない」「時間の無駄」という人はだいたい設計がこのタイプ
例)期末にタレマネで人事考課を開始する
1. 人事部が事前に期のイベントを設計/開始する
- ○○期人事考課
- 対象者、評価フロー、承認者
2. イベント中に複数のタスクがある
- 自己評価、一次面談、最終評価
3. タスクは条件を満たすまで開始できない
- 前段のタスクの完了、期日など
4. タスクは差し戻しができる
- 自身による引き戻しはできない
- 一度開始したタスクは削除できない
5. 被評価者は後続のタスクの進捗のみが分かる
6. 被評価者は後続のタスクの中身は参照できない
7. 最終評価者が開示許可したものを被評価者は参照できる
8. 全体の人事考課が終わると人事はイベントを終了させる
1. イベントを開始ボタンで開始する
2. イベント内の最初のタスクが自動的に開始される
3. 最初のタスクが入力可能な状態になる
4. タスクに入力すると次のタスクが入力可能になる
5. どこまでタスクが進んだか進捗が分かる
6. 最後のタスクが完了したらイベントの終了ボタンを押す
💡実現方法が固定化されたり、実装方法が入り込む場合は特に注意
💡「50年後、別の実現手段が現れたときにそのまま使えること」を意識する
💡ここで初めて、状態遷移図、ユースケース定義、シーケンス図が必要、といった話になる
イベント情報
タイトル
概要
期間
タスクフロー
タスク情報
タスクのつながり情報
組織情報
社員情報
進捗状況
💡この時点でシステム側の「専門用語が出てきてないか?」は注意する
💡ビジネス上の専門用語は注釈を置く
イベントの期間は日付としての情報を持つ
有効な開始日か検証することができる
終了日が開始日より以前になることはない
評価値は使える固定の値を持つ
評価値には順序がある
これ以外の評価値は許容しない
💡これを意識しないとロジックを分散させてベタに書く傾向になる
From/To | イベント開始前 | イベント中 | タスク1 | タスク2 | … | タスクN-1 | タスクN | イベント終了 | イベント完了 |
---|---|---|---|---|---|---|---|---|---|
イベント開始前 | - | 開始ボタン | - | - | - | - | - | - | - |
イベント中 | - | - | 自動開始 | - | - | - | - | - | - |
タスク1 | - | - | - | 入力 | - | - | - | 終了ボタン | - |
タスク2 | - | - | 差し戻し | - | 入力 | - | - | 終了ボタン | - |
… | - | - | - | 差し戻し | - | 入力 | - | 終了ボタン | - |
タスクN-1 | - | - | - | - | 差し戻し | - | 入力 | 終了ボタン | - |
タスクN | - | - | - | - | - | 差し戻し | - | 終了ボタン | - |
イベント終了 | - | - | - | - | - | - | - | - | 完了ボタン |
イベント完了 | - | - | - | - | - | - | - | - | - |
💡if文で管理せず、オブジェクトで管理する
💡主に自分自身の値に関する制約を持つ
評価値の値域は?使える文字は?
評価値の順序関係はどう設定する?
任意の評価値は許容するか?
型は文字列か数値か?
数値も文字列で扱うか?
文字数/桁数制限は?
編集・閲覧権限は?
タスクの状態との関係は?
入力された評価値の検証方法は?
評価値の値を文字列で持つ
評価値の種類は最大10パターンまで
一つの評価値は全角16文字まで
評価値の順序を画面上から設定できる
イベント開始時に設定した評価値はイベント完了まで変更できない
イベント完了後には編集できない
💡こうした制約からどのようなデザインパターンにすればよいか検討する
💡品質の担保が難しい言語を選択するときは注意
💡開発者が言語に精通してミスしない修練が必要
「一部の機能を独立させて別のサービスにしたい」ができるか
「こうなっているとうれしい」から考える
こういうものが必要そうから考える
💡よりよい設計ライフを!