IT業界で気づいたことをこっそり書くブログ

くすぶってるアプリエンジニアが、日々気づいたことを適当に綴っていきます(受託→ベンチャー→フリー→大企業→ベンチャー→起業)

連番のボタン名がなぜ良くないかを言語化する

これ

b.hatena.ne.jp

元:

https://twitter.com/ohbashunsuke/status/1495900842389610498

 

何か凄い燃えそうだし斧投げすぎるの良くないかなと思ったんですが、テーマとして面白そうだったのでブログ書きます。

とりあえずコメントを見るに「どうやら皆良くないと思っているらしい」というのはわかるんですが、「なぜ良くないか」を言語化しようとすると難しいですよね。
案外きちんと反論できない人も多いのでは?

 

問題・テーマの一般化

問題の一般化からちょっと手こずるんですが。トライしてみます。

仕様変更に強い命名は大事だ。ボタンを「OKボタン」や「Noボタン」と名付けていたらヤバいかも。ゲーム開発に仕様変更はつきもの。開発中盤「OKボタンの色を使ってキャンセルボタンを作りたい」というケースもある。結論、用途ではなく機械的な名前をオススメ。後の参画メンバーの混乱は避けるべき。

「OKボタン」などの用途名はやめよう、「ボタン1」とかにしよう。という話です。
動機は仕様変更であり、「後で変わるかもしれないから」です。

 

あと、おそらくこれは共有パーツの話だと思います。
流石に特定画面内の1パーツを連番にしようという話ではないと思うんです。合ってるかな・・・?

 

なのでテーマとしては

テーマ:共通クラス名は、ある初期仕様における用途名で作るべきであなく、連番のような機械的な名前にするべき。は正しいか?

で合ってると思います。

 

具体的に課題に感じているのは

例えば「OKButton」と名付けたのに後々別の用途でも使う事になった。
名前変更がコストかつリスクである。

だと思います。

 

ちなみに前提として「最近のゲーム開発である」があります。

 

たぶん誤解されているテーマ

誤解というか、似た別の例として捉えている方が多い印象です。

・特定画面のパーツの名前を用途名にするか、機械的にするか?

・そもそも命名機械的であるべきか?

・データ側の命名規則機械的であるべきか?

・OK/Cancelを混同していいかという問題

 

これは汎用性の話

エンジニアという生き物は少ないルールで多くのことを表現したがります。
昨今の仕様が動くことを前提にした開発においては、たしかに汎用的に作った方が楽なように思えます。
さもないと、代わりに例外が増えます。例外が増加すると状態数が増えて訳がわからなくなります。

 

ボタンを汎用的に作りたいという要求→機械的な名前

例えば序盤の仕様では緑のOKボタンがあったとします。
それをOKButtonとしたら、次の仕様では「次へボタン」も同じ緑のボタンでした。
そこでOKButtonをPositiveButtonとリネームしました。
すると次の使用では「戻るボタン」も緑でした。
そこでPositiveButtonをGreenButtonとリネームしました。
すると「戻るボタン」は特定条件でオレンジに変化することがわかりました。

 

というようなことがあって、「じゃあ最初からButton_1でいいじゃん」という主張担ったんだと思います。
こういうの、皆さんはどうしていますか?

 

Button_1の致命的な問題

何のボタンかがわかりません。
これは本当に致命的です。
こうなると、いつどのボタンがButton_1になるのか、Button_1の正しい仕様は何で、正しくない動きは何かなどが分からなくなっていきます。
凝集度とかそういうレベルじゃなく、スパゲティコード(神クラス)になっていきます。

 

凝集度 - Wikipedia

God object - Wikipedia

 

後任者はButton_1を「どのように使われているか」でしか判断できなくなります。
(きちんとした外部ドキュメントがあれば別ですけど、まあ大体ないですよね)

 

※神クラスの厳密な定義からすると私の意図しているものとちょっとずれるかもしれません。支配的なクラスと言うより、何でも詰め込まれたFatなクラスというイメージで使っています。

 

どのように使われているかしか判断できない可読性最悪なクソClassが神クラスになる

これって何か名前ついてないんですかね?
私は過去十数年でこういうClassに何度も何度も何度も何度も出会ってきました。こいつに出会うと数日、下手したら数週間苦しみます。
今回の例では「青いボタン」のような共通した見た目のデザインがあるからいいですが、そうではない場合は本当にわかりません。

例えば、OKボタン、進むボタン、戻るボタン、で使用されていたButton_1があったとして、「同意するボタン」にはButton_1を適用するべきでしょうか?例えば、「同意するボタン」にButton_1を適用する場合、Button_1を少しカスタマイズしなければならないとしたらどうでしょうか?Button_1をカスタマイズしますか?ほら、神クラスの誕生です。

 

汎用的な名前をつけるとFatな神クラスができる

例えばiOSの界隈では数年前に「BaseViewController作るのやめよう」って流れあったんですが、あれです。
全ViewControllerがBaseViewControllerを継承しているという神クラス状態なのがまずいのと、あとは「Base」という汎用的な名前が危険というのが一点。

もっと端的に言うなら「単一責任の原則の逸脱を誘発する」からダメだと思います。

 

抽象度を上げると可読性が下がる

そもそもなんですけど、プログラミング全般において汎用性を上げるということは抽象度を上げるということであり、結果的に可読性は下がります。汎用性というのは色んなパターンに対応するということであり、読み手はそのクラスが取りうる全空間を理解しなければきちんと使いこなしたり改修することができません。

どういうわけか、最近周囲では抽象度を上げることに躍起になっており、可読性がかなり犠牲になっているんですが何故なんでしょうか?
すいません脇道でした。

機械的な名前というのは「抽象度を最大限取った」ということですよね。可読性は死にます。後任者はこちらの方が混乱すると思います。というか地獄。

 

結論

テーマ:共通クラス名は、ある初期仕様における用途名で作るべきであなく、連番のような機械的な名前にするべき。は正しいか?

正しくない。

・スパゲティコード化(神クラス化)を誘発するからよくない

・可読性がゼロだからよくない

 

対策

結論では具体的な課題は解決されていません。

 

例えば「OKButton」と名付けたのに後々別の用途でも使う事になった。
名前変更がコストかつリスクである。

 

これについて、ブコメでは命名の工夫などが挙げられました。
私も概ね賛成というか、ハードウェアレベルのコストでないのであれば随時名前変更した方が良いと思います。また、積極的に「似た異なるクラス」を作ってもいいと思います。1個で全てまかなおうとしないでください。

それ以前に、Mixinの仕組みが備わっているのであればClassを作成せずそれを活用するのが良いと思います。iOSで言えばextensionやprotocolです。

Mixin - Wikipedia
Swiftのprotocol extensionでmixin的なものを実現する - Qiita

 

それでも連番のような抽象的な名前が発生するケース

門外漢ですが。

例えばそもそも汎用的なハードウェアであれば、ボタン1、ボタン2、ボタン3、のような命名は致し方ないシーンがあると思います。
あとは公開APIのパラメータやデータベースのような、後で命名変更するコストが甚大なケースはしょうがないのかもしれません。
ただその場合もできるだけ具体名にすることを諦めるべきではないと思いますし、そもそもアジャイルな開発手法は向いていないと思います。

今回は「最近のゲーム開発」という文脈ですので、おそらく仕様変更に対応しやすい仕組みが導入されているのではないかと思いました。知らんけど。

 

おわりに

でも少し昔は普通にそういう実装多かったし今でもありますよね。
たぶん今回はみんなのトラウマを呼び起こしたんだと思います。
もうコードリーディングしたくない・・・