見出し画像

プログラムを書くときメソッドを使いまわすな!

皆さんこんにちは。
ぜったいバグらないシステム作ろうぜの会会長の中島です。

てか自分で考えといてナンだけど、会の名前が長いね。略そうか。
じゃあゼバ会で。
今日からゼバ会です。よし、完璧に覚えた。

さて今回のテーマは、「日本人エンジニアの9割が嫌う」という、とあるコーディングテクニックについてです。
これをやれば確実にバグ率が劇的に下がる。
なのに誰もやりたがらない。
そんな不思議なテクがあると、前回ケツでそのように申し上げました。

てなわけで正解は、、、? とても簡単。
「メソッドの使いまわしをしない」ということです。

たとえ全く同じコードであろうとも、用途が違うなら全く同じ内容の関数を2つ持つべきです。
そのような基準をチーム内で強制するだけで、バグ率はメチャクチャ下がります。
小指賭けてもええよ。マジだから。

、、、、で、これを読んでる人の大部分は、この段階で以下のうちどっちかを思ったはず。

・全く同じコードが2つあるなんて、普通にメモリーの無駄では?
・同じコードが2つあると、同じ改修をしなきゃいけなくなったとき漏れるじゃ?

そう。
これを主張すると、だいたいどこの現場でも同じ拒否反応が出ます。
その気持ち自体は感情論としてはよく分かります。
メンドいもんね。

でもさ、よく考えてみて?
うちは「ゼバ会」よ?
(あれ、ゼバって何の略だったっけ。えーと、そうそう、「ぜったいバグらないシステム作ろうぜ」の略だ)

効率のいいコンパクトなコードを書いて愉悦に浸る会じゃねぇの。
あなたの会社の開発方針だってそうでしょ? バグが出てもいいから効率よくコードを書こうっていう、そういう開発方針かい?
まぁ、実際そういう会社ならしょうがない。
そういうところにお勤めの方は、ここで袂を分かつとしましょう。

でも、世の中の9割9分以上の会社はそうじゃないはず。
自分の効率よりも安全性の方がよっぽど大事なはずですよね?
(え? 効率と安全性、どっちも重視しろって言われてる? そういうときはそいつ殴っとけ)

なおかつ、「全く同じコードが2つあるのはムダ」という主張は完全に語るに落ちています。
なぜならその主張には、その2つのコードは、未来永劫ずっと同じはずであるという前提があるからです。

ユースケースの違う複数の用途でそれぞれ用いるのにさ、飛魚のアーチをくぐって宝島が見えるまで、何も失わずに同じでいられると思う?
未来永劫ずっと変わらないものなんてないんだよ。

function getAllUsers() {
      $sql = 'select user_id, name from user';
      return execute($sql);
}

たとえば、ユーザーデータを取ってくるのに便利だからって使っていたこの関数。
いかにも使い出よさそうです。
ここでは、ある2つの処理で使いまわしていた、としましょう。

でもさ、あるとき、片方の処理の場合だけ「メールアドレスも欲しいよね」ってことになったりすると思わない?
そうなったとき、こうなるわけです。

function getAllUsers() {
        $sql = 'select user_id, name, email from user';
        return execute($sql);
}

はい。一部コードが追加になりました。
別に追加するのはいい。
でもこの処理さ、本当はメールアドレスなんかいらなかった方の処理にまでメアド渡しちゃうよね。
その結果、「メールアドレスが意図せず存在する」というセキュリティホールになっちゃったらどう責任とんのよ?
こんなことすんの?

function getAllUsers(boolean needEmail) {
        String sql = 'select user_id, name'
                        + (needEmail ? ', email ' : '')
                       + 'from user';
        return execute(sql);
}

これ、「メソッドを使いまわす」という目的のために、全箇所改修になっちゃうよね?
しかもこのコード、`needEmail = false` のときだけSQLエラー出るし。
さて、バグはどこ?

プロ歴10年の人とかならまだしも、1~2年目の新人君とか「from の前にスペースが必要」なんてパッと見じゃまず気づかんでしょ。

、、、ってことなわけですよ。
何とかなるかどうかの問題ではなく、メソッドを2つの処理で使いまわそうとさえしなければ、このような一連の無駄なやり取り自体必要なかったのです。

もちろん、「未来永劫ずっとコードを変える必要がない」という前提がちゃんとあるなら使いまわしていいと思います。
「文字列の一部を指定通りに置き換える」「アラートを出す」みたいな極めて汎用性の高いメソッドは、将来的にも変える必要性が生じにくいので使いまわせるでしょう。

でも、使いまわせるからって何でも使いまわせばいいってもんじゃないです。
世の中のロジックは大きく2つに分けると、人間が業務を行うときの手順に近い形をとる「ビジネスロジック」と、システムをコントロールするための実装である「システムロジック」に分かれます。(ただしこの2つに明確な境目はありません)
通常多くの場合、処理というのはビジネスロジックがシステムロジックを呼び出すという形式で実装されるはずです。

その際、未来永劫ずっと変わらない可能性が高いのは、どちらかといえばシステムロジックのことが多いです。
ビジネスロジックは、何年も変わらずに同じものが使えるケースはレアです。
レアどころじゃないですね。普通に激レアです。
なぜなら、経済社会とは、生きた人間が回しているものだからです。
ビジネスのやり方が日々移り変わっていくのは当たり前のことで、変わらない方が望ましいという考え方は「システムを組んでいる側の願望」でしかありません。

おまけコラム:
記事冒頭に「日本人が~」とかキャッチーな言葉書いちゃってますけど、この「1つのメソッドをなるだけ使いまわしたい」という欲望は何も日本人だけのものではなく、人類共通的な傾向です。
エンジニアを目指すような人の中には、「たった1つのトリガーで、様々な処理がキレイに完了するのが気持ちいい」と感じる人も多く、だからこそエンジニアを目指した、なんて人もいます。
そういうタイプの人は「1ヶ所の修正で全箇所の修正が完了する」状態を好む傾向があり、そういう人は世界中にいます。
ただ今回のコラムは、その考えを「諸刃の剣である」と言ってるわけです。

私個人の経験論からいえば、世の中のバグの3~4割はこの使いまわしの悪影響によるロジックの複雑化が原因です。
バグ率めっちゃ下がるとか大風呂敷を広げたのは、そういう理由です。
特に、モジュール単位で盛大に使いまわしてるケースなんかは、特定の上位モジュールから呼ばれたときだけ専用のコードが if で入る率も非常に高く、「分かっちゃいるけど分離しようにもできない」ことも多くてマジおっそろしかとです。
(なおかつ、コード量が多いと分離はできないという意識から、実は使いまわしちゃいけなかったとチーム内の誰も思っていないこともあります)

てなわけで皆さん、使いまわさない選択肢があるなら使いまわしは絶対にやめましょう。
上記で述べた通り、正直メリットが全くありません!!

、、、、っとっとっと。え? メリットまだある? 残ってる?
そうは言ってもやっぱり使いまわししたい?

そうね。
記事冒頭ではメソッドを使いまわすメリットを2つ挙げましたが、その1つ「改修時に漏れを防げる」というメリットについて、まだ否定できていません。
できないからやらなかったんじゃないんだよ?
だって、改修時の漏れをなくすなんて簡単だもん。
簡単すぎてポッキンパラリのプーよ。

そもそもテーブル名に user なんてありきたりな単語使うから検索で漏れんのよ。
こんなシンプルな単語、どっっっっこにでも使うでしょ。
下手したらドキュメントの内部にまで大量に登場するでしょ。

そりゃあそんな単語、検索で把握とかできるわけないさ。
変数名やテーブル名に限らず、名前というものは「その概念を特定できるように」って付けるものなんだよ。
概念を特定する必要がないなら、そもそも名前なんか必要ないでしょ?
つまり検索時に情報を特定できない名前は名前になってるとは言えないのです。

てか、自分で作っといてなんだけど、この user ってテーブルいったい何者?
ユーザーに関する情報を何でもかんでもカオスにブッコんで良いテーブル
んーなテーブルあるわけねぇぇぇぇぇぇぇ!!!!!(絶叫)
飼ってるインコ全匹にピーちゃんて名づけんな!!!!!(絶叫×2)

次回予告

てなわけで次回は、「名前は気分でつけるな ~ネーミングルールの在り方について」でお送りします。
お楽しみに!

この記事が気に入ったらサポートをしてみませんか?