とある休日
娘(5歳)「パパ、今日はお休みだから一緒にゲームしよ?」
ワイ「ええで!なんのゲームする?」
ワイ「スーパー正男ブラザーズでもやろか?」
娘「ううん」
娘「コードジャンケンしよ!」
ワイ「なんや、その恐ろしそうな名前のゲームは。。。」
娘「なんか仕様を決めて、どっちが読みやすいコードで実装できるか勝負するの!」
ワイ「おお、ええで」
ワイ「流石に5歳児には負けへんで!」
ワイ「6歳児だと危ういけどな!」
娘「じゃあ、ママ」
娘「何か仕様をちょうだい!」
よめ太郎「ええで」
仕様: 数値を文字列に変換する
よめ太郎「仕様、考えたで」
よめ太郎「数値を文字列に変換する、っちゅう内容や!」
【いま考えた仕様書】
- とあるAPIから
0〜2
の数値が返ってくるとする0〜2
の数値は、ユーザーの申込進捗状況を表しているものとする0〜2
の数値は、それぞれ以下の状態を表している
0
→ 申込書到着1
→ 申込手続中2
→ 申込完了- 画面上では、数値ではなく文字列として表示する必要がある。
上記の数値を、画面表示用の文字列に変換する処理を実装せよ。
ワイ「ほう・・・ユーザーの申込進捗状況ねぇ」
ワイ「要するに・・・」
ワイ「APIから0
が返ってきたら、画面には'申込書到着'
って表示する」
ワイ「APIから1
が返ってきたら、画面には'申込手続中'
って表示する」
ワイ「APIから2
が返ってきたら、画面には'申込完了'
って表示する」
ワイ「そのための、数値から文字列への変換処理を書けってことやな?」
よめ太郎「そういうことや」
ワイ「クッソ簡単やん」
ワイ「こんなん、誰が書いても同じやろ」
娘「言語はTypeScriptでいい?」
ワイ「ええで!」
ワイ「ほな勝負や!」
ワイのコード
ワイ「書けたで!」
const userStatuses: Array<string> = [
'申込書到着',
'申込手続中',
'申込完了'
]
ワイ「↑こうや!」
よめ太郎「なるほどな」
よめ太郎「数値は0
か1
か2
な訳やから」
よめ太郎「配列を用意しておいて、その数値でアクセスすればいいって訳か」
ワイ「せや」
console.log(userStatuses[0])
// -> '申込書到着'
console.log(userStatuses[1])
// -> '申込手続中'
console.log(userStatuses[2])
// -> '申込完了'
ワイ「↑こんな感じや!」
よめ太郎「なるほどな、シンプルやな」
5歳娘ちゃんのコード
娘「私も書けたよ!」
type ApiValue = 0 | 1 | 2
type DisplayText = string
const userStatusTextMap: Map<ApiValue, DisplayText> =
new Map([
[0, '申込書到着'],
[1, '申込手続中'],
[2, '申込完了']
])
娘「↑こんな感じ!」
よめ太郎「ほうほう」
よめ太郎「まずは・・・」
type ApiValue = 0 | 1 | 2
よめ太郎「なるほど」
型「APIから返ってくる値は、
0
か1
か2
のどれかやで!」
よめ太郎「↑ってことを表しているんやな」
娘「うん!」
よめ太郎「説明的でええやないか」
よめ太郎「ほんで、次の行は・・・」
type DisplayText = string
よめ太郎「string
型に、別名を付けてあげてる訳か」
娘「うん!」
型「ここでの
string
は、画面に表示するための文字列ですよ!」
娘「ってことを表現してみたの」
よめ太郎「ああー」
よめ太郎「単にstring
だと、なんのための文字列なのかってことまでは分からへんもんな」
よめ太郎「せやから、もう少し意味のある型名を付けてあげた訳やな」
よめ太郎「素敵やん」
よめ太郎「そんで、その次は・・・」
const userStatusTextMap: Map<ApiValue, DisplayText> =
new Map([
[0, '申込書到着'],
[1, '申込手続中'],
[2, '申込完了']
])
よめ太郎「なるほどな」
よめ太郎「この・・・」
Map<ApiValue, DisplayText>
よめ太郎「っていう型がエエ感じやな」
型「APIから取得した値と表示用テキストの対応表ですよ!」
よめ太郎「↑こんな感じが滲み出てるな」
ワイ「ああ〜、そうか」
ワイ「Mapって対応表って意味やもんな」
娘「うん」
娘「それで、こんな感じで使うの」
console.log(userStatusTextMap.get(0))
// -> '申込書到着'
console.log(userStatusTextMap.get(1))
// -> '申込手続中'
console.log(userStatusTextMap.get(2))
// -> '申込完了'
console.log(userStatusTextMap.get(3))
// -> コンパイルエラー!!!
よめ太郎「おお〜」
よめ太郎「ApiValue
の値を0
か1
か2
に制限してあるから」
よめ太郎「3
のぶんを取得しようとすると、ちゃんとコンパイルエラーが起きるんやな」
よめ太郎「ええやん」
娘「てへへ」
よめ太郎「こういうのも、型の旨みやもんな」
勝敗判定中
よめ太郎「娘ちゃんのコードは、全体的に説明的で良いな」
よめ太郎「コードを読んだだけでも・・・」
「こんな仕様書だったんやろな〜」
よめ太郎「っていうことが、なんとなく想像できるわ」
よめ太郎「このコードを後から保守する人も・・・」
保守担当「むむ?」
保守担当「Map<ApiValue, DisplayText>
とな?」
保守担当「なるほど、これは・・・」
保守担当「APIから取得した値と表示用テキストの対応表ってことか」
よめ太郎「って感じで、型の意図を読み取りやすそうやな」
よめ太郎「修正フェーズや保守フェーズで価値を発揮しそうなコードやな」
娘「うん、そこは意識してみたよ」
娘「この部分のコードだけ読んでも、できるだけ意味や意図が分かるように、って」
よめ太郎「なるほどな」
娘「小さなプロジェクトなら、仕様書を全部読んで、コードも型も全部読んで」
娘「全部理解してから修正すればいいけど」
娘「大規模な案件だと、全ての仕様を理解して、全体のコードを読んでから修正するとか」
娘「頭がパンクしちゃうもん」
よめ太郎「まあ、できれば全体を把握した方がええんやろうけど」
よめ太郎「一部分だけを見ても分かりやすい、説明的な型やコードが書かれてると」
よめ太郎「あとから読む人は、すごく助かるよな!」
娘「そうだね!」
娘「型は、ドキュメントの役割もするからね!」
ワイ「(型はドキュメント・・・?)」
ワイ「(何を言うてんの・・・?)」
ワイ「(でも・・・)」
ワイ「せやな!型はドキュメントや!」
ワイ「(一応言うとこ・・・!)」
よめ太郎「かたや、やめ太郎のコードは・・・」
const userStatuses: Array<string> = [
'申込書到着',
'申込手続中',
'申込完了'
]
ワイ「う〜ん、まさに」
型「APIから取得した値と表示用テキストの対応表ですよ!」
ワイ「って、型が語りかけてきてる感じがするな!」
よめ太郎「いやどこがやねん」
よめ太郎「どこから感じたねん」
よめ太郎「エスパーか」
ワイ「ぐぬぬ・・・」
よめ太郎「Array<string>
という型から分かるんは」
型「文字列が入った配列やで」
よめ太郎「それだけやろ」
ワイ「確かに・・・」
結果発表
よめ太郎「ほな、結果発表するで」
ワイ「ワクワク・・・!」
よめ太郎「ようワクワクできるな」
ワイ「ぐぬぬ」
よめ太郎「勝者は・・・」
よめ太郎「娘ちゃんや!」
ワイ「まぁ、知ってたわ・・・」
よめ太郎「せやろな」
よめ太郎「勝因としては・・・」
- 型や命名で、できる限り仕様を説明していた
よめ太郎「ってとこやな」
ワイ「なるほどな・・・」
ワイ「型はドキュメント・・・」
ワイ「そういうことか・・・」
よめ太郎「しかも、型で書いた通りに実装せんと」
よめ太郎「エラーが出て前に進めない・・・」
よめ太郎「強制力のあるドキュメントやな」
ワイ「確かに」
ワイ「コメントはワンチャン間違っとるかもしれんけど」
ワイ「型は、間違っとったらコンパイルエラーで進めへんもんな」
よめ太郎「せや」
よめ太郎「テストコードと並んで、一番信頼できるドキュメントと言えるかもしれん」
まとめ
- 型の付け方で仕様を説明できると素敵やね
- 元々ある型に別名を付けて説明してあげるのもええね
- 型はドキュメント的な役割も果たすんやね
ワイ「↑こういうことやな!」
ワイ「これで、さらにコメントもちゃんと書けば」
ワイ「だいぶリーダブルなコードになりそうやな」
よめ太郎「せやな」
よめ太郎「あ!でも一点だけ・・・」
Map<ApiValue, DisplayText>
よめ太郎「↑ここは」
ReadonlyMap<ApiValue, DisplayText>
よめ太郎「↑こうの方がええかもな」
娘「あ、そっか」
娘「ReadonlyMap
型のほうがよかったね」
よめ太郎「ReadonlyMap
にしておけば、上書きできひんから・・・」
userStatusTextMap.set(2, '死亡')
console.log(userStatusTextMap.get(2))
// -> '死亡'
よめ太郎「↑こういう事故が防げるもんな」
娘「そうだね」
娘「それに・・・」
型「上書きする必要のない、読み取り専用の対応表やで!」
娘「ってことも伝わるしね」
娘「あー、そうすればよかったなぁ」
ワイ「そうかぁ」
ワイ「ってことは・・・ワイの勝ちかな?」
よめ太郎「いやちゃうやろ」
〜おしまい〜