🔫

会話形式で綴る「説明変数と要約変数」

2024/10/31に公開

登場人物

ワイ

  • 41歳プログラマー

後輩くん

  • ワイの後輩(20代)
  • 大きなタスクを分割して、ワイに指示をしてくれる

とあるシステム開発会社にて

ワイ「あ〜〜〜っ!」
ワイ「ワイの実装したバックエンドがバグってたせいで」
ワイ「大事な社員名簿システムのデータが消えてもうてるやん!」
ワイ「これじゃ、バックエンドやなくてバッドエンドやないけ!コラァ!」

後輩くん「(なんでキレてんねん...お前のせいやろ...)
後輩くん「せ、先輩、大丈夫ですか?」

ワイ「ぐぬぬ・・・取り乱してごめんやで」

後輩くん「先輩、気を取り直して行きましょう」
後輩くん「そのバッドエンド・・・じゃなくてバックエンドは僕が直しておきますから」
後輩くん「今日は一緒に、社員名簿システムのフロントエンド部分の実装を進めましょう!」

ワイ「せやな!」

後輩くん「今日はプロフィール編集ボタンを実装して行きましょう」
後輩くん「現状、ここまで出来てます!」

見た目

プロフィール編集ボタン

コード

    <Text fw="bold">氏名:無職やめ太郎</Text>
    <Button>プロフィールを編集</Button>

ワイ「おぉ、見た目は大体できとるな」
ワイ「そんで、今日は何をするんやっけ?」

後輩くん「今日は、このボタンを──」

  • 社員本人
  • 管理ユーザー

後輩くん「↑この人たちしか押せないように権限管理したいんです」

ワイ「なるほどな」
ワイ「他人のプロフィールを勝手に変えられんように、ってことやな」

後輩くん「はい!」

ワイ「ほな、こうやな!」

    <Button
+       disabled={!(loginUser.id === thisUser.id || loginUser.roles.includes(1))}
    >
        プロフィールを編集
    </Button>

ワイ「画面で確認してみると・・・」

プロフィール編集ボタン disabled

ワイ「よっしゃ、ちゃんとdisabledになっとるわ!」

後輩くん「先輩、マジでやめてください」

ワイ「ファッ!?」

後輩くんの指摘①「もっと説明してほしい」

後輩くん「条件が長すぎて読みづらいですし」
後輩くん「いきなりloginUser.roles.includes(1)とか書かれても」
後輩くん「わけ分かんないっす」

ワイ「いや、これは──」

  • ログイン中のユーザーが、管理ユーザーの役割(1)を持っている

ワイ「っていう意味やないか!」

後輩くん「じゃあ、それをちゃんと説明するコード書いてくださいよ」
後輩くん「後から読んだ人が困らないように!」

ワイ「むう、分かったやで」

    <Button
+       // ログイン中のユーザーが、管理ユーザーの役割(1)を持っていること!
        disabled={!(loginUser.id === thisUser.id || loginUser.roles.includes(1))}
    >
        プロフィールを編集
    </Button>

ワイ「↑こうやな!」

後輩くん「いやぁ、その説明コメントでもいいんですけど」
後輩くん「これくらいならコードだけで説明できそうなので」
後輩くん「説明変数を書きましょうよ」

ワイ「説明変数・・・?」

後輩くん「はい。つまり──」

const isAdminUser = loginUser.roles.includes(1);

後輩くん「↑こうしましょう」

ワイ「なるほど」
ワイ「パッと見で何か分からん値には、説明のために名前をつけてあげるんやな」

後輩くん「そうです!」
後輩くん「あと1っていう値もそのままじゃ分からないので」

const USER_ROLE_MAP = {
    ADMIN: 1,
    MEMBER: 2,
} as const;

後輩くん「↑こう、名前をつけてEnumっぽく管理してあげて」

const isAdminUser = loginUser.roles.includes(USER_ROLE_MAP.ADMIN);

後輩くん「↑こう使ってあげましょう」

ワイ「ふみふむ」

後輩くん「1とか2とかだと」
後輩くん「後からコードを読んだ人が──」

「なんやこの不思議な数字は?」

後輩くん「って思っちゃいますからね」
後輩くん「こういうのはマジックナンバーって言って、アンチパターンなんです」

ワイ「おお〜、了解やで!」

もう1つの条件も

後輩くん「あと、loginUser.id === thisUser.idっていう条件は」
後輩くん「自分自身のプロフィールかどうか、って意味だと思うんですけど」

ワイ「そうやでぇ」
ワイ「こっちはちゃんとloginUserとかthisUserとか」
ワイ「値の意味が分かるような名前がついとるから、問題ないやろ!」
ワイ「これ以上、説明変数にすることもできんやん!」

後輩くん「そうですね・・・でも・・・」

後輩くんの指摘②「もっと要約してほしい」

後輩くん「loginUser.id === thisUser.idも」
後輩くん「まだ要約できる余地があると思うんです」

ワイ「要約ぅ・・・?」

後輩くん「はい」

const isOwnProfile = loginUser.id === thisUser.id;

後輩くん「↑こうですね!」

ワイ「なるほどなぁ」
ワイ「loginUserとかthisUserとか」
ワイ「意味が分かる名前たちによって構成されている式でも」
ワイ「さらに要約して明記してあげることもできるんやな」

後輩くん「そうですね」
後輩くん「こういうのは要約変数と呼ばれます」

ワイ「要約変数かぁ」
ワイ「おおきに!勉強になったやで!」
ワイ「ほな──」

    <Button disabled={!(isOwnProfile || isAdminUser)}>
        プロフィールを編集
    </Button>

ワイ「↑これで完成やな!」

後輩くん「あと少しだけ要約しましょう!」

const canEditProfile = isOwnProfile || isAdminUser;

後輩くん「↑こうして──」

    <Button disabled={!canEditProfile}>
        プロフィールを編集
    </Button>

後輩くん「↑こうですね」

ワイ「なるほどぉ。つまり──」

要するに「プロフィールを編集できる」ってのは
自分自身のプロフィールである場合、もしくは管理ユーザーでログインしている場合やで!

ワイ「↑こんな風に要約して明記してあげるんやな」

後輩くん「その通りです!」

ワイ「こう、ちゃんと命名されて明記されてると──」

編集できない場合は、disabledになるんやで!

ワイ「↑って、当たり前なくらい読みやすくてええな!」

後輩くん「そうですね、わざわざ命名した方が」
後輩くん「条件ベタ書きよりも意図が伝わると思います」

ワイ「コード書いてるワイ本人も、混乱しにくくて良さそうやわ」

ツールチップも表示したい

後輩くん「権限がなくてボタンが押せない場合は」
後輩くん「マウスをホバーさせた時に、その理由も表示させてあげましょうか」
後輩くん「デザインで言うと──」

デザイン

プロフィール編集ボタン disabled ツールチップつき

後輩くん「↑こんな感じです」

ワイ「おお、ええ感じやな」
ワイ「こう表示されていれば、管理者に問い合わせたりできるもんな」

後輩「はい」

ワイ「ほな、コードとしては──」

+   <Tooltip label="本人または管理ユーザーだけが編集できます">
        <Button disabled={!canEditProfile}>
            プロフィールを編集
        </Button>
+   </Tooltip>

ワイ「↑こうやな!」
ワイ「これで、ホバー時にツールチップが表示されるわ!」

後輩くん「でも、これだと」
後輩くん「ボタンが押せる場合でもツールチップが表示されちゃいますよ」

ワイ「あぁ、そうやな」
ワイ「ほなTooltipコンポーネントに」
ワイ「disabledっていうpropsを渡してやらんとアカンな」
ワイ「ボタンを押せる場合には、ツールチップは非表示なわけやから・・・」
ワイ「あれ、頭こんがらがってきたけど──」

    <Tooltip
        label="本人または管理ユーザーだけが編集できます"
+       disabled={canEditProfile}
    >
        <Button disabled={!canEditProfile}>
            プロフィールを編集
        </Button>
    </Tooltip>

ワイ「↑こうやな!」

後輩くん「そうですね」

ワイ「でも、なんか・・・」

disabled={canEditProfile}

ワイ「↑この部分が・・・」
ワイ「disabledっていう名前のpropsなのに」
ワイ「canEditProfileっていう肯定形の変数がそのまま渡されてて」
ワイ「なんか・・・」

「無効なのか、できるのか、どっちやねん!」

ワイ「って気がしてしまう・・・!」
ワイ「それに・・・」

ボタンを押せる場合には、ツールチップは非表示なわけやから

ワイ「↑これが頭こんがらがるから、もっと説明したい・・・」
ワイ「・・・せや!」

const isTooltipDisabled = canEditProfile;

ワイ「↑こう明確に書いてあげよ!」

後輩くん「なるほど」

ボタンが押せるとき、ツールチップは見えないよ!

後輩くん「っていうことを明記してあげるんですね!」

ワイ「せや!」
ワイ「そんで──」

    <Tooltip
        label="本人または管理ユーザーだけが編集できます"
-       disabled={canEditProfile}
+       disabled={isTooltipDisabled}
    >
        <Button disabled={!canEditProfile}>
            プロフィールを編集
        </Button>
    </Tooltip>

ワイ「こうやな!」

後輩くん「おお〜」
後輩くん「先輩から能動的に説明・要約しに行くなんて」
後輩くん「素晴らしいです!」

ワイ「ガーファファファ!そうでもないでぇ!」

まとめ

  • 後から読む人にとって意味が分かりにくい値
    • 例: loginUser.roles.includes(1)など
      • 変数名をつけることで、説明してあげよう
  • 分かりやすい名前がついた変数によって構成されている式でも、まだ認知負荷を減らせそうな場合
    • さらにまとめて変数名をつけることで、要約してあげよう
  • わざわざ命名して明記しながら進む方が、書いてる本人も混乱しづらい

ワイ「↑っていうことやな!」

後輩くん「そうですね!」

〜完〜

※この記事は、書籍「リーダブルコード」を参考に書きました

株式会社ゆめみ

Discussion