見出し画像

バグを出しやすい人の考え方の特徴

チーム内で1人だけ品質の低い人がいる。

そんな状況になると、その人個人に嫌な視線が集中してしまいがち。
でも本人だって別に悪気があるわけじゃなし、そう強くも注意できない。
本人も周りも、どうしたらいいか分からない。

ときとして、開発チームはこんな悪循環にハマりがちです。
こんなこと、なぜ起こるんでしょうか――。

いつもお読みいただきありがとうございます。
または初めての方も、この記事を見つけてくださって嬉しいです。

私は、IT業界で20年だか30年だか働いております、エンジニアの中島と申します。
この 絶対バグらないシステム作ろうぜの会 では、バグの出ないシステム・問題を起こさないチーム運営・AIには作れない設計論などのコラムを、なるだけ面白く・分かりやすくお伝えする主旨で記事を配信しております。


1. バグを出しやす人の考え方の特徴

ケース1. “コードを書く”ことが目的化している

人間のアイデンティティは人それぞれ。
中には、ちょっと変わったことに自己肯定感をいだく人もいます。

道路の白線の上をまっすぐ歩けるのが自慢、電池の新旧を重さで言い当てるのが得意、とかね。
まぁ、そういう人もいるくらいですから、プログラマーが『ちょっといいコードが書ける』ことを自慢に思うくらいは普通でしょう。

が、だからって “コードを書く” ことそれ自体が目的化してしまうと、不具合に無頓着な人になってしまいます。
本来プログラムは “データを正しい状態にする” ために動かすものであって、プログラムを実行するのはその手段にすぎません。
人間はデータ処理を行いたいからコンピューターを使うのであって、コンピューターを使うこと自体が目的ではないのです。

それゆえコードを書くこと自体が目的化してしまうと、『中を流れるデータが正しい状態になるまで作りこむ』という作業が苦手になってしまいます。

ですが本人は、自分がそういう考え方を持っている意識がないこともあり、その場合は注意するだけでは直りません。
言葉で注意するだけでは、本人も何に気をつけたらいいか理解できません。

そういう人は、概要設計書に最終結果だけを載せて「最終的にこうなるように作れ」と指示するのではなく、計算の過程で必要になるはずのデータなども明示して(または本人に作らせて)、テストドリブン方式で開発させることが有用でしょう。
なぜなら、プログラムは “中を流れるデータが主役” で、コードはデータを正しく流すためのガイド役にすぎないからです。

ケース2. 変数の構造に無頓着

一般に、本番環境で最も頻出しがちなエラーは "Undefined Index" です。

とりわけスクリプト言語から発展した言語では、オブジェクト内のメンバー変数を自由に増やしたり減らしたりできてしまうものも多いです。
たとえば JavaScript では、連想配列のキーがオブジェクトメンバーであるかのように扱えますが、ぶっちゃけ言語仕様としてはめちゃくちゃ危険です。

ですが、実際にできてしまうものはしょうがないわけで、本来あるべきメンバーが存在しない状態がうっかり生まれてしまい、それが本番環境でエラーとなります。

一般に多くの場合、データの構造はテスト環境よりも本番環境の方がはるかに複雑です。
なのであらかじめテスト用に用意されたデータだけでは、『特定のオブジェクトの特定のキーが生成されないパターン』を完全には網羅しきれないのが普通です。
システムが大きければ大きいほど、また1つの業務フローに携わる画面の数が多ければ多いほど、「プログラマーがテスト仕様書を網羅的に作れば問題ない」という考え方は通用しなくなっていきます。

本番環境でのエラーが致命的と予め分かってる場合は型が厳密な言語を採用すればいいのですが、そういう言語は往々にして初心者向けではなく、新人が育ちにくい傾向があります。
ですので、厳密さよりもスピードが優先されるビジネスでは、どうしても型の曖昧な言語を使わざるをえません。

そのような言語でも品質を高めていくためには、プログラマー本人が変数の構造に無頓着ではいけません。

なぜなら、プログラムは “中を流れるデータが主役” なのであって、コードはデータを正しく流すためのガイド役にすぎないからです。
背景にばかりかかずらって主役に無頓着な監督が、素晴らしい映画が撮れるわけがないのです。

ケース3. 「違うけど似てる」部品を共通化したがる

システム設計者の中には、モジュール全体・システム全体のコード量を減らすことに熱意を燃やす人もいます。
コード量の少ないシステムが複雑な業務ができるということは、それだけ作業効率がいいということでもあるからです。

ですが残念ながら、これは複雑な業務システムでは通用しにくい考え方です。
リソースに制限のある古いシステムならともかく、今のシステムはメモリーもディスク容量も十分に潤沢なことが多いため、コード量の少なさが業務それ自体の効率とは必ずしも結びつきません。

モジュール・メソッドは、“似てるけど違う” んだったら2つに分けるべきです。
そういうモジュールを無理に共通化してしまうと、結果的に “内部に if 分岐がやたら多い” 状態を生み出してしまい、それが不具合の温床になるケースは非常に多いです。

もともと1つだったモジュールを2つに分けるか判断すべきときは、

  • 『似てるけど違う』のか

  • 『違うけど似てる』のか

その違いをしっかり見極めることが重要です。

ケース4. 「全ての情報をいっぺんに処理する」ようなロジックを好む

中には、あらゆる情報を1ヶ所に集約し、ワンステップで全てが終了するようなアルゴリズムを「美しい」と感じる人もいるでしょう。
そのような処理は、小さなコードで非常に複雑な業務を実現していることになるからです。

ですが実際には、そういうコードは “理想的な状態が常に維持できるなら美しい” という極めて条件の限定された美しさであって、現実には汚いコードの温床になるだけです。

コードをあまり無理に集約すると、“別人が手を入れると汚くなりやすい” コードになりがちです。
たとえ最初に作った時点では美しくても、時間とともに汚くなるスピードが早かったら、それは決して “美しいコード” とは呼べないでしょう。

たとえて言うなら、、、そうですね。
エリザベス女王1世が首に巻いている、ひだひだのカラー。
ありますよね。

エリザベス1世の肖像

あのカラーは、そのあまりの巨大さから『犬が首に巻くヤツ』に例えられがちで、現在ではむしろ犬が首に巻く方をエリザベスカラーと呼ぶほどです。

ですがあのカラー(正式には《ラフ》)は、実は発祥時点ではもっと小さく、デザイン的にも洗練された美しいものだったんです。
でも時代とともにどんどん大型化していき、貴族の見栄というしょうもないもののために、ファッションとしてのバランスも崩れていったのした。

最初にラフを考えた人からすれば、「おかしくした後世の人間が悪い」ということになるのでしょう。
「オレが最初に美しく作ったんだから、その美しさの継承は後世の義務だ」
システムを最初に作ったプログラマーがそう思いたくなること自体は、痛いほどよく分かります。

ですが最初のプログラマーにも、“巨大化しやすいデザインを採用しない” という選択肢があったはずです。
とりわけコンピューターシステムのような『美しい状態を長く保つ』ことが重要なケースでは、そういう観点も必要になってくるのです。

アルゴリズムは、まず『人間が手作業でやる場合の手順』がありきです。
そのような手順を《業務フロー》とか《サービスフロー》などと呼びます。

理屈の上では、人間が行うはずだった処理をそっくりそのままプログラム化したコードの方が、人間には不可能な複雑なロジックを使うよりも分かりやすくなります。

たしかに、人間にできないことをするのがコンピューターの仕事ですが、だからといってその中身まで常人に理解不能である必要はないのです。

ケース5. 実行速度にこだわりすぎる

実行速度にこだわる人がトラブルを多く出すことは、直感的にも自明のことのように感じます。
農耕トラクターの運転手とF1レーサー、どちらが重大事故を起こす可能性があるかを考えれば、速度と安全性はトレードオフであることが火を見るよりも明らかです。

そしてそれは、プログラムの世界でも変わりません。

プログラマーが天才であれば別ですが、そうでなければ実行速度と安定性は常に必ずトレードオフ。
これは絶対です。

ですから、速度と安定性が競合してしまったときにどちらを優先するか。
それをあらかじめ決めることはとても重要です。
そして決めきれない場合は、“実行速度を犠牲にしてでも安定性を求める” のが、世の中だいたい正しいです。

とりわけコンピューターに関する知識が少ない上司は、「部下が何とか両立してくれる」ことを前提にしてしてしまいがちです。
そんな曲芸みたいな両立ができる部下を持った経験なんて、実は1度もないにも関わらず、です。

ケース6. ソースコードの美しさにこだわりすぎる

ソースコードを美しく書こうとすること自体は、必ずしも問題があるとはいえません。
ただ問題は、何を持って「美しい」と感じるかが人それぞれってことです。

  • 縦横が綺麗にそろっていて、絵のようにデザインされて見える

  • 何をやっている処理なのかが一目で分かる

  • コードフォーマットが統一されている

  • 処理が速そうに見える

  • 複雑な処理がコンパクトにまとまっている

  • プログラムが作られた最終目的が一目で分かる

  • 上記がどれかに偏重することなくバランスよくまとまっている

思いつくだけでも、コードの美しさの定義はこれだけあります。

無論、コードは正しく動けば汚くても業務上は問題ないのですが、汚いコードはのちに別の担当者に引き継いだときにメンテナンス性を落とします。
最初に作ったプログラマーにとって美しく見えるコードが、引き継いだ相手に汚く見えるのもよくある話です。

だからこそコーディング規約はしっかりと作りこむ必要があるのであって、そしてそれはできれば、コードフォーマッターによって強制できるところはした方が望ましいといえます。
そうすることによって、メンテナンス性を向上させるためです。

コードの美しさはその人の感性・観点によって様々ではあります。
ですが、こと 《ビジネス》 という側面から見たときには、

『メンテナンスコストを減らしやすいコード』こそが美しいコード

です。

通常多くの場合、製造されたコードはプログラマー本人のものではなく、その製造を依頼した企業の所有物です。
ですので本人の主観による美しさを追求するのではなく、ビジネス的に美しいコードであった方が、より望ましいといえます。

メンテナンスコストを増加させないためには、フォーマットがそろっている状態を作るほかに、クラス構造・クラス同士の関係構造などもシンプルで追いかけやすい状態になっている必要があります。
そのことを無視して、自分好みの美しさにこだわるプログラマーは、そういう態度がメンテナンスコストを増大させているといえるのです。

ケース7. 処理をメソッド化すると使いまわしたくなる

処理の一部をメソッドとして切り出すと、当然ながらそのメソッドはスコープの範囲内で自由に呼ぶことができるようになります。

このとき、「せっかくメソッド化したのだから、どんどん使い回さなきゃもったいない」と感じる人もいるようです。
同じ処理を複数の状況で使い回せばば、その分だけコード量は少なくて済むことになりますからね。

でもこれも危険信号の1つです。

たしかに、処理というのは部分的に切り出してメソッド化することも多いですが、でもそれは使いまわすために切り出すのではありません
もちろんそういう目的でメソッド化することも当然ありますが、常にではありません

むしろ、メソッド化の多くは『ビジネスロジックとしての階層が違うから』という理由で切り出されることの方が圧倒的に多数です。
かつ、そのような理由で切り出されたメソッドは、本質的に “複数個所から同時に呼ばれるべきではありません”。

これは、異なる業務に要されるメソッドは、現時点では全く同じ処理内容であったとしても、将来的に段々異なってくる可能性が高いためです。
ですのでメソッドは、使い回さないともったいない、という話にはならないのです。

2. バグとは“コスト”である

バグとは、そもそも出したくて出すのではありません。
がんばってみたけどダメだったから出るんです。

ですので、メンバーがバグを出したとき、本人を直接責めてしまうリーダーは要注意です。
なぜならバグが出る原因が、チームとしての思想統一の不備が原因のこともあるからです。
少なくとも、その可能性を棚に上げてバグをメンバー各人のせいにしていいことなんてありません。

バグの出ないプログラミングを行うには、メンテナンスコストを最小にするという観点を持つことが不可欠です。
ですが末端の一番年若いのプログラマーなんかだと、そのような考え方を持てる状況にはなかったりします。

なぜならそのような人は、コスト意識を持つ訓練もやってなければ、コスト管理をする責任を負ってるわけでもないからです。

デバッグは『コスト』だという考え方を身に着け、どうすればこれを最小にできるかを日々模索することこそがバグを出さないために大切なんじゃないかなと、私なんかは思うわけです。

ではまた。

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