510
221

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ゆめみAdvent Calendar 2020

Day 15

5歳娘「パパ、型はドキュメントだよ?」

Last updated at Posted at 2020-12-14

とある休日

娘(5歳)「パパ、今日はお休みだから一緒にゲームしよ?」

ワイ「ええで!なんのゲームする?」
ワイ「スーパー正男ブラザーズでもやろか?」

娘「ううん」
娘「コードジャンケンしよ!」

ワイ「なんや、その恐ろしそうな名前のゲームは。。。」

娘「なんか仕様を決めて、どっちが読みやすいコードで実装できるか勝負するの!」

ワイ「おお、ええで」
ワイ「流石に5歳児には負けへんで!」
ワイ「6歳児だと危ういけどな!」

娘「じゃあ、ママ」
娘「何か仕様をちょうだい!」

よめ太郎「ええで」

仕様: 数値を文字列に変換する

よめ太郎「仕様、考えたで」
よめ太郎「数値文字列に変換する、っちゅう内容や!」

【いま考えた仕様書】

  • とあるAPIから0〜2の数値が返ってくるとする
  • 0〜2の数値は、ユーザーの申込進捗状況を表しているものとする
  • 0〜2の数値は、それぞれ以下の状態を表している
    • 0 → 申込書到着
    • 1 → 申込手続中
    • 2 → 申込完了
  • 画面上では、数値ではなく文字列として表示する必要がある

上記の数値を、画面表示用の文字列に変換する処理を実装せよ。

ワイ「ほう・・・ユーザーの申込進捗状況ねぇ」
ワイ「要するに・・・」
ワイ「APIから0が返ってきたら、画面には'申込書到着'って表示する」
ワイ「APIから1が返ってきたら、画面には'申込手続中'って表示する」
ワイ「APIから2が返ってきたら、画面には'申込完了'って表示する」
ワイ「そのための、数値から文字列への変換処理を書けってことやな?」

よめ太郎「そういうことや」

ワイ「クッソ簡単やん」
ワイ「こんなん、誰が書いても同じやろ」

娘「言語はTypeScriptでいい?」

ワイ「ええで!」
ワイ「ほな勝負や!」

ワイのコード

ワイ「書けたで!」

wai.ts
const userStatuses: Array<string> = [
    '申込書到着',
    '申込手続中',
    '申込完了'
]

ワイ「↑こうや!」

よめ太郎「なるほどな」
よめ太郎「数値は012な訳やから」
よめ太郎「配列を用意しておいて、その数値でアクセスすればいいって訳か」

ワイ「せや」

wai.ts
console.log(userStatuses[0])
// -> '申込書到着'

console.log(userStatuses[1])
// -> '申込手続中'

console.log(userStatuses[2])
// -> '申込完了'

ワイ「↑こんな感じや!」

よめ太郎「なるほどな、シンプルやな」

5歳娘ちゃんのコード

娘「私も書けたよ!」

musume.ts
type ApiValue = 0 | 1 | 2
type DisplayText = string

const userStatusTextMap: Map<ApiValue, DisplayText> =
    new Map([
        [0, '申込書到着'],
        [1, '申込手続中'],
        [2, '申込完了']
    ])

娘「↑こんな感じ!」

よめ太郎「ほうほう」
よめ太郎「まずは・・・」

musume.ts
type ApiValue = 0 | 1 | 2

よめ太郎「なるほど」

型「APIから返ってくる値は、012のどれかやで!」

よめ太郎「↑ってことを表しているんやな」

娘「うん!」

よめ太郎「説明的でええやないか」
よめ太郎「ほんで、次の行は・・・」

musume.ts
type DisplayText = string

よめ太郎「string型に、別名を付けてあげてる訳か」

娘「うん!」

型「ここでのstringは、画面に表示するための文字列ですよ!」

娘「ってことを表現してみたの」

よめ太郎「ああー」
よめ太郎「単にstringだと、なんのための文字列なのかってことまでは分からへんもんな」
よめ太郎「せやから、もう少し意味のある型名を付けてあげた訳やな」
よめ太郎「素敵やん」
よめ太郎「そんで、その次は・・・」

musume.ts
const userStatusTextMap: Map<ApiValue, DisplayText> =
    new Map([
        [0, '申込書到着'],
        [1, '申込手続中'],
        [2, '申込完了']
    ])

よめ太郎「なるほどな」
よめ太郎「この・・・」

musume.ts
Map<ApiValue, DisplayText>

よめ太郎「っていう型がエエ感じやな」

型「APIから取得した値表示用テキスト対応表ですよ!」

よめ太郎「↑こんな感じが滲み出てるな」

ワイ「ああ〜、そうか」
ワイ「Mapって対応表って意味やもんな」

娘「うん」
娘「それで、こんな感じで使うの」

musume.ts
console.log(userStatusTextMap.get(0))
// -> '申込書到着'

console.log(userStatusTextMap.get(1))
// -> '申込手続中'

console.log(userStatusTextMap.get(2))
// -> '申込完了'

console.log(userStatusTextMap.get(3))
// -> コンパイルエラー!!!

よめ太郎「おお〜」
よめ太郎「ApiValueの値を012に制限してあるから」
よめ太郎「3のぶんを取得しようとすると、ちゃんとコンパイルエラーが起きるんやな」
よめ太郎「ええやん」

娘「てへへ」

よめ太郎「こういうのも、型の旨みやもんな」

勝敗判定中

よめ太郎「娘ちゃんのコードは、全体的に説明的で良いな」
よめ太郎「コードを読んだだけでも・・・」

「こんな仕様書だったんやろな〜」

よめ太郎「っていうことが、なんとなく想像できるわ」
よめ太郎「このコードを後から保守する人も・・・」

保守担当「むむ?」
保守担当「Map<ApiValue, DisplayText>とな?」
保守担当「なるほど、これは・・・」
保守担当「APIから取得した値表示用テキスト対応表ってことか」

よめ太郎「って感じで、型の意図を読み取りやすそうやな」
よめ太郎「修正フェーズ保守フェーズで価値を発揮しそうなコードやな」

娘「うん、そこは意識してみたよ」
娘「この部分のコードだけ読んでも、できるだけ意味や意図が分かるように、って」

よめ太郎「なるほどな」

娘「小さなプロジェクトなら、仕様書を全部読んで、コードも型も全部読んで」
娘「全部理解してから修正すればいいけど」
娘「大規模な案件だと、全ての仕様を理解して、全体のコードを読んでから修正するとか」
娘「頭がパンクしちゃうもん」

よめ太郎「まあ、できれば全体を把握した方がええんやろうけど」
よめ太郎「一部分だけを見ても分かりやすい、説明的な型やコードが書かれてると」
よめ太郎「あとから読む人は、すごく助かるよな!」

娘「そうだね!」
娘「型は、ドキュメントの役割もするからね!」

ワイ「(型はドキュメント・・・?)」
ワイ「(何を言うてんの・・・?)」
ワイ「(でも・・・)」
ワイ「せやな!型はドキュメントや!
ワイ「(一応言うとこ・・・!)」

よめ太郎「かたや、やめ太郎のコードは・・・」

wai.ts
const userStatuses: Array<string> = [
    '申込書到着',
    '申込手続中',
    '申込完了'
]

ワイ「う〜ん、まさに」

型「APIから取得した値表示用テキスト対応表ですよ!」

ワイ「って、型が語りかけてきてる感じがするな!」

よめ太郎「いやどこがやねん
よめ太郎「どこから感じたねん」
よめ太郎「エスパーか」

ワイ「ぐぬぬ・・・」

よめ太郎「Array<string>という型から分かるんは」

型「文字列が入った配列やで」

よめ太郎「それだけやろ」

ワイ「確かに・・・」

結果発表

よめ太郎「ほな、結果発表するで」

ワイ「ワクワク・・・!」

よめ太郎「ようワクワクできるな」

ワイ「ぐぬぬ」

よめ太郎「勝者は・・・」
よめ太郎「娘ちゃんや!

ワイ「まぁ、知ってたわ・・・」

よめ太郎「せやろな」
よめ太郎「勝因としては・・・」

  • 型や命名で、できる限り仕様を説明していた

よめ太郎「ってとこやな」

ワイ「なるほどな・・・」
ワイ「型はドキュメント・・・」
ワイ「そういうことか・・・」

よめ太郎「しかも、型で書いた通りに実装せんと」
よめ太郎「エラーが出て前に進めない・・・」
よめ太郎「強制力のあるドキュメントやな」

ワイ「確かに」
ワイ「コメントはワンチャン間違っとるかもしれんけど」
ワイ「型は、間違っとったらコンパイルエラーで進めへんもんな」

よめ太郎「せや」
よめ太郎「テストコードと並んで、一番信頼できるドキュメントと言えるかもしれん」

まとめ

  • 型の付け方で仕様を説明できると素敵やね
  • 元々ある型に別名を付けて説明してあげるのもええね
  • 型はドキュメント的な役割も果たすんやね

ワイ「↑こういうことやな!」
ワイ「これで、さらにコメントもちゃんと書けば」
ワイ「だいぶリーダブルなコードになりそうやな」

よめ太郎「せやな」
よめ太郎「あ!でも一点だけ・・・」

musume.ts
Map<ApiValue, DisplayText>

よめ太郎「↑ここは」

musume.ts
ReadonlyMap<ApiValue, DisplayText>

よめ太郎「↑こうの方がええかもな」

娘「あ、そっか」
娘「ReadonlyMap型のほうがよかったね」

よめ太郎「ReadonlyMapにしておけば、上書きできひんから・・・」

musume.ts
userStatusTextMap.set(2, '死亡')

console.log(userStatusTextMap.get(2))
// -> '死亡'

よめ太郎「↑こういう事故が防げるもんな」

娘「そうだね」
娘「それに・・・」

型「上書きする必要のない、読み取り専用の対応表やで!」

娘「ってことも伝わるしね」
娘「あー、そうすればよかったなぁ」

ワイ「そうかぁ」
ワイ「ってことは・・・ワイの勝ちかな?」

よめ太郎「いやちゃうやろ

〜おしまい〜

510
221
17

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
510
221

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?