プリンシプル オブ プログラミング

プログラマの3大美徳

プログラマは「怠慢」「短気」「傲慢」であれ

プログラマの3大美徳は、できるプログラマの特性を、3つの「美徳」としてまとめたものです。

その3つの美徳とは「怠慢」「短気」「傲慢」です。定義は、以下のようになります。

怠慢

全体の労力を減らすために、手間を惜しまない気質です。後で皆が楽できるように、今役立つコードを書いてしまいます。

短気

コンピュータがさぼっている時に、怒りを感じる気質です。コンピュータが十分効率的に働いていなかったり、意図通りに働いていなかったら、ただちにコードを書き直してしまいます。

また、今ある問題に留まらず、今後起こりうる問題を想定したコードを書いておきます。

傲慢

神罰が下るほどの、過剰な自尊心を持つ気質です。高いプライドを持ち、人様に対して恥ずかしくないコードを書きます。

「怠慢」「短気」「傲慢」で作業を仕組み化

3大美徳は、一見「悪徳」のように思えます。逆の言葉である、「勤勉」「寛容」「謙虚」の方が、倫理的には正しい気がします。

しかしプログラマにとっては、「怠慢」「短気」「傲慢」の方が理に適っているのです。それぞれに正当な理由があります。

怠慢

怠慢と言っても、怠け心を持ち、仕事がしたくないのではありません。

日常には、面倒な仕事、何回も繰り返す仕事がたくさんあります。そのような仕事は自分でやらず、「怠惰」になれるよう、ソフトウェアを作って自動化します。つまり、コンピュータに仕事をやらせてしまうのです。

そうすることで、多くの人が何回も繰り返す作業であれば、時間が大幅に節約されます。また、作業の正確性も保証されます。

短気

怒ると言っても、コンピュータに怒鳴り散らすわけではありません。

確かに、コンピュータが、こちらが望むような働きをしてくれない時があります。
そんな時は、「短気」になり、こちらの思い通りに動いてくれるように、コードを書
き換えてしまうのです。

そうすることで、我慢している時間が、快適な時間に変わります。作業の品質、作業にかかる時間も改善されます。

傲慢

自尊心を持つと言っても、周りに威張り散らすわけではありません。

自分のコードを、誰に見られても恥ずかしくないように書くのです。そのコードに対して責任を持ちます。仕事の成果については「傲慢」になり、プロフェッショナルの意識を持って仕事に取り組みます。

そうすることで、コードをきれいに保つ習慣が身に付きます。

ソフトウェアは必ず保守していかなければなりません。その時、コードが読みやすく、修正しやすくなっていれば、要望に応えやすくなります。また、そのスピードも速くなります。

「自動化」「ひな形化」「モジュール化」

具体的には、以下のように行動しましょう。

怠慢

繰り返しの仕事を「仕組み化」しましょう。

手作業については、コードを書いて、ツールを作って、自動化します。この時ポイントになるのが、いきなり自動化しないことです。まず、手作業の手順を明確にしてから、自動化できそうなところを自動化するやり方が効率的です。自動化の効果の高いところを見極めてから、自動化していきます。どんな時でも、自分の仕事の中にある繰り返しを見つけたら、ツールで自動化することを考えましょう。

また、ドキュメントについても、仕組み化は適用できます。ドキュメントを一度作成したら、フォーマットを残し、再利用しましょう。この時のポイントは、ファイルを「整理」しないことです。重要なのは、整理ではなく、検索できることです。したがって、そのドキュメントを検索する時に使いそうなキーワードを、思いつく。限りファイルの中身や名前に詰め込んでおきます。フォルダ分けより、全文検索の方が効率的です。

短気

起こりうる問題を「想定して」仕事をしましょう。先回りして、要望が出てきそうな部分を考え、クレームが出る前に対応できるようにしましょう。

この時ポイントになるのが、変更される可能性がある部分と変わらない部分を見極めて、変わる部分については応用が利くようにしておくことです。変わらない部分をベースにひな形を作り、変更される部分を変数化して、自由に変更できるようにしておきます。

ただ、ユーザーはわがままで、要望は個々に様々です。これに都度対応するのは骨が折れます。そこで、さらに短気になり、設定ファイルなどで、使う人自身が動作をカスタマイズできるようにしておくのも有効です。

傲慢

人様に対して恥ずかしくない仕事をして、保守していきましょう。自分で作ったソフトウェアは、プロ意識を持って、保守を容易にしておきましょう。

この時ポイントになるのが、作成したソフトウェアは、機能ごとにモジュール化して、管理しておくことです。機能としてまとめられたモジュールは、別のソフトウェアを作る時に再利用することができます。

ハードワークは報われない

一般的な職業美徳に、「一生懸命」「我武者羅」など、ハードワークを意味するものがあります。しかし、少なくともプログラマのハードワークには、意味がありません。

確かに、長時間オフィスにいれば、プロジェクトに多大な貢献をしているような錯覚に陥ることがあります。メンバーの人たちも、そう思ってくれることもあります。しかし、事実はまったく逆で、自分の働く時間や労力を減らせば減らすほど、プロジェクトへの貢献は大きくなるのです。

プログラミングは、取り組みながら絶えず学ぶということができる仕事です。仕事をすればするほど、問題領域についての理解は深まり、同じ目的を達するために必要な労力と時間は、徐々に減っていきます。仕事が効率化されるからです。自分の仕事にどんな無駄があるかを常に観察し、その結果を後の仕事に反映させていけば、着実に効率化が図れます。

また、プログラミングのように高度に知的な仕事においては、残業などで無理に時間を捻出しても、それを補って余りあるほどの悪影響が出てしまいます。よいコードを書くには、集中力が必要です。体に無理をかけながらよいコードはかけません。

それに、体調が悪くなると、人につらくあたり、何かあっても人のせいにして、彼害者意識が出てきます。すると対人関係も悪くなり、コミュニケーションも悪くなり、チームの雰囲気も悪くなります。これは、チームにとっても、メンバーにとっても、リリースする製品にとっても、大きな痛手です。たとえそれが一時的なことだとしても、これらの状態の回復には時間がかかります。

結局、自分自身が一生懸命やっても、ほかの誰かがプレッシャーをかけても、それがアシストとなって、急に頭の回転速度が上がるわけがありません、頭脳労働のハードワークは報われません。

ボーイスカウトの規則

コードを掃除して帰る

ボーイスカウトには、シンプルな規則があります。「自分のいた場所は、そこを出て行く時、来た時よりもきれいにしなければならない」という規則です。たとえ、自分が来た時には既にキャンプ場が汚かったとしても、たとえ、汚したのが自分ではなかったとしても、きれいにしてからその場を去るのです。

この規則を、プログラミングにも当てはめます。コードは、自分がそこに来た時よりもきれいにしてから、その場を去ります。最初にそのコードを書いたのが誰であるかに関係なく、少しずつでもコードを改善する努力を続けます。

コードの腐敗を抑止する

コードは常に洗練され続けなければなりません。

しかし、現実には、時間の経過に伴ってコードが腐敗し、品質が低下する事態は珍しくありません。何も意識しないでプログラミングを続けていると、自然とこのような結果を招いてしまいます。この品質の低下を食い止めなければなりません。

「前より少しでもきれいにする」という、この簡単なルールを皆が守るだけで、少なくとも今よりシステムの品質が低下することは防げます。うまく行けば、時間が経つごとにシステムの品質が徐々に向上していくようになります。これは、そのソフトウェアに関わる全プログラマが、自分の担当する小さな部分だけでなく、ソフトウェア全体の質に目を向けるということにもつながります。

ソフトウェアの動作を完全に正確に知るには、結局ソースコードを見るしかありません。コードがすべてです。コードの改善を続けていくことが、プログラマのミッションです。

コードは改良してからコミット

コードを、リポジトリから取得した時よりもきれいにして、コミットしましょう。これを心構えとして常に持ち、習慣化しましょう。それにより、コードの洗練を継続して行えます。

これは決して大仰なことではありません。小さな活動の積み重ねです。

目指すのは、すべてのコードをコミット前に完璧なものにするのではなく、取得した直後より、少しでもよいコードにすることです。変数名をよりよいものにしたり、大きすぎる関数を分割したり、重複を排除したり、条件文の連なりをなくしたり、循環参照を解消したり、インタフェースを追加することで使用方法と実現方法を切り離したり、何でも、どれくらいでも、構いません。

プログラミングは「急がば回れ

ソフトウェアの開発については、最短距離で時間やコストを稼ぐより、回り道して品質をよくした方が、よい結果につながります。ボーイスカウトの規則もそれを示唆しています。ことコードにおいては、近道を選んでしまうと、後で保守に不要なコストがかかるからです。

例えば、以下のような具合です。

直接的な価値が得られないからと、ユニットテストを書くのを省略する

このように作られたソフトウェアは、後で変更するのがとても難しくなります。変更を加えた時、それでよかったのかどうか確かめることができないからです。わずかな変更であっても、手作業によるテストが必要になるため、ソフトウェアが脆くなり、保守にコストがかかります。

設計そのものも、完全にテストできることを考慮された設計と比べると、使われ方が検討されていない分、よいものにはなっていません。

コスト軽減のため、目的が適合しないのに既存システムをむりやり使う

これは、無理をしている以上、苦しくなり、いずれ破綻します。結局、きちんと要件に合わせてアーキテクチャを作り直すことになります。

その時コストは、最初から正しい選択をした時に比べ、後戻りした分、大幅に増
えてしまいます。

不適切なライブラリが選択されていることに気付いたのに、放置する

これは、要件の発展とともに、そのライブラリのまずい部分を隠すために、後で余分なレイヤーを追加しなければならなくなります。そして、レイヤーを追加する度に、もつれあった層をほどくのが難しくなっていきます。これでは、今以上のソフトウェアの改善ができません。

近道した部分が将来の機能の基礎になってしまった場合、後で修正しようとすると莫大なコストがかかるでしょう。

以上のように、近道は、結果的に遠回りになるのです。

 

経済性の原則

貴重で高価なリソースである、プログラマの時間を節約します。

以下のような問題が、プログラマの時間を浪費します。

ハードウェアが貧弱

よくあるのは、開発マシンが貧弱な場合です。

記憶ディスクが不足すると、圧縮や別メディアへの移動など、やりくりに多くの時間を取られます。

CPUの性能が不足すると、コンパイルや実行に時間がかかり、待ち時間が多くなります。

メモリが不足すると、同時に実行できるソフトウェアが少なくなり、開発効率が下がります。

モニタが小さいと、いちいちウインドウの切り替えが発生し、作業がとても非効率になります。

使用するソフトウェアに対する制限

必要なソフトウェアが購入できないと、何らかの工夫をして同じことを実現しなければなりません。

また、フリーソフトだとしても、ルールとしてインストールを制限している組織もあります。ちょっとしたツールがインストールできないと、それを手作業でやることになります。

環境に関するルールや制限

よくあるのは、インターネットにおいて、開発に必要なサイトなのに、アクセスできない場合です。クラウドで稼働するソフトウェアが使用できないルールのところもあります。インターネット接続すら禁止されている場合もあります。

しかし、そもそも、情報処理技術者から、情報を遮断してはいけません。

プログラマの時間は貴重

ハードウェアやソフトウェアの購入を抑制するのは、経費節減のためです。しかし、設備の費用とプログラマの費用は、比較にならないほど後者が高価です。設備に投資して、プログラマが効率よく、気持ちよく仕事ができれば、簡単に投資は回収できます。

また、ルールや制約については、セキュリティがその主たる理由です。しかし、そのために、ものづくりの邪魔をして、ビジネスのスピードを落とすのは、本末転倒です。優秀なプログラマほど、ルールによって力を発揮できなくなり、ルールによってモチベーションを落とします。

プログラマに投資する

開発環境のためのハードウェアやソフトウェアに投資しましょう。設備に投資して、間接的にプログラマに投資すれば、収支は必ずプラスになります。開発効率が上がり、ストレスは下がるので、生産性や品質が格段に向上します。

また、ルールや制約は、施行後にバランスを調整しましょう。いったん作るルールは叩き台として考え、運用後、プログラマの意見を聞くようにします。開発に支障が出ているのであれば、「これだけは最低限譲れない」というところまで譲歩してください。

 

分割統治

大きな問題を小さく割る

そのままでは解決することが難しい「大きな問題」は、いくつかの「小さな問題」に分
割して、個別に解決します。

小さくした各個の問題は、元の問題に比べて格段に容易になり、すぐに解決に至ります。個々の問題解決の積み上げにより、最終的に、元の大きな問題の解決に至ることができます。

大きなままでは制御不能

大きな問題を、大きな問題のまま解決しようとすると、解決が困難になり、解決が遅くなります。最悪、解決できない場合もあります。規模が大きすぎるがゆえに、問題が複雑になりすぎているからです。

制御が容易になるような規模まで問題を分割して、それから取り組む方が効率的です。

小さくして各個撃破

問題を分割してから、解決するようにしましょう。例えば、以下のようにします。

  • ソフトウェア全体を設計する時は、独立して設計できる部分に分割してから、取
    り組みます。
  • モジュールを設計する時は、「責任・責務」の観点からモジュールを分割するようにします。
  • アルゴリズムを設計する時は、マージソートのように、ボトムアップで分割してから問題解決できないかどうか、検討します。
  • 大量データ処理を設計する時は、MapReduceのように、計算を小さい単位に分割して、分散環境で並行して実行できないかどうか、検討します。

 

エントロピーの法則

コードは自然と腐っていく

エントロピーとは物理学の用語で、「無秩序な度合い」を表すものです。熱力学の法則によれば、全宇宙のエントロピーは増加していくことが証明されています。

ソフトウェア開発は、ほとんどすべての物理法則を超越できますが、エントロピー増大の法則には強く縛られます。コードは、自然に任せると、限界を超えるまで無秩序さが増大します。いわば「腐ったコード」になっていくのです。

コードは無秩序へ向かう

コードが無秩序へ向かうというのは、ソフトウェア開発においても、自然な傾向です。

最初はよいスタートを切ったとしても、しばらくすると、コードが腐敗し始めます。生肉が古くなると腐るように、時間が経つにつれ、腐敗はひどくなっていきます。腫れ物がコード内にたまってしまい、どんどん保守しづらくなります。そのうち、ちょっとした変更にも、多大な労力が必要になり、再設計を余儀なくされます。

しかも、こういった場合の再設計はうまく行きません。今のソフトウェアは常に変化し続けているので、新しい設計もそれに追従しなければならないからです。

つまり、明確な目的意識を持って取り組んだとしても、実は「動く標的」を打ち落とそうとしているため、無理が生じるのです。

コード腐敗の兆候をつかむ

コードが腐敗し始める「兆候」がいくつかあります。これらを見過ごさないようにして、迅速に対処しましょう。

硬さ

「硬さ」とは、変更の難しさのことです。

たった1つの変更で、それと依存関係のあるモジュールを、連鎖的に変更しなければならないような場合、「硬い」設計のコードだと言えます。

設計が「硬い」と、例えば、簡単そうな変更を頼まれ、変更箇所を軽く調べてから仕事量の見積もりを出したとしても、実際に作業を進めるに従い、予測していなかった連鎖的変更箇所に直面します。その結果、最初の見積もりよりもずっと多くの変更をすることになり、膨大なコードの中で次々と変更を追いかけることになります。

脆さ

「脆さ」とは、たった1つの変更によって、他の多くの部分が壊れてしまう度合いのことです。脆いコードは、変更した部分とはまったく関連のない箇所まで、壊れてしまうことがあります。そこで新たに発生した問題を修正しようとすると、さらに問題を生み出してしまい、プログラマは自分で自分のシッポを追いかけるような状態に陥ってしまいます。

大げさではなく、そういったモジュールは珍しくありません。脆いモジュールは、すぐに見つかります。例えば、いつも修復されているモジュール、いつまでも障害リストから消えないモジュール、プログラマが再設計の必要を感じているモジュール、修復すればするほどひどくなるモジュールなどです。

移植性のなさ

「移植性のなさ」とは、ほかの環境への移植のしにくさのことです。

どんな環境でも動作する部分を含んでいながら、環境依存の部分から、その部分を切り離すのが困難で、リスクを伴うような場合、移植性がないと言えます。

扱いにくさ

「扱いにくさ」には、コードの扱いにくさと、開発環境の扱いにくさがあります。

コードの扱いにくさとは、設計構造の柔軟性のなさのことです。扱いにくいコードは、設計構造を保持したまま、容易に変更できません。設計構造を保持するやり方よりも、裏技を使った方が簡単に変更ができます。間違ったことをするのは容易で、正しいことをするのが難しい状態です。

一方、環境の扱いにくさは、開発環境が遅くて非効率な時に生じます。例えばコンパイルに非常に時間がかかる場合、設計構造を保持できなくなることがわかっていても、大きなコンパイルをしなくて済むような変更を採用したくなります。あるいは、たかだか2つ3つのファイルをコミットして確認するのに、数時間もかかるような場合、設計構造を保持できるかどうかなど考えず、できるだけ時間がかからないような方法で変更しようとしたくなります。

複雑さ

「複雑さ」とは、「不必要な」要素の多さのことです。

これは、プログラマが仕様の変更を先取りし、後で仕様が変更になった時に対処しやすい仕組みを、あらかじめコードに仕込んでおくことで発生します。こういった対処は、よいことのように思えます。将来の変更を見越して準備しておけば、コードの柔軟性を保ち、後になって悪夢のような変更に苦しまなくて済むはずです。

しかし、残念ながら、まったくの逆効果に終わることがほとんどです。あまりにも多くの不測の事態に対処しようとして、一度も使わない構造がコード中に散乱してしまいます。これが、コードを複雑にし、わかりにくくします。

繰り返し

「繰り返し」とは、同じようなコードが何度も繰り返し現れることです。

コピー&ペーストは、文書作成には便利な方法ですが、コード編集に使うと悲惨な結果を招きます。重複するコードがあると、ソフトウェアの変更はとても骨の折れる作業になります。そのような重複した部分から障害が見つかった場合、コード中にある同じような部分をすべて修正しなければなりません。

しかも、同じようだとはいっても、それぞれがほんの少しずつ違っていることもあり、必ずしも同じ修正をすればいいわけではありません。

このように、同じようなコードが、ほんの少しだけ違う形で、繰り返し現れるような場合、プログラマは抽象化を見逃しています。繰り返しの箇所をすべて見つけ、そういった部分を適切に抽象化することで、繰り返しを削除すれば、システムは理解しやすく、かつ、保守しやすいものになります。

不透明さ

「不透明さ」とは、コードのわかりにくさのことです。

コードは、わかりにくい表現で記述されてしまうことがあります。また、頻繁に改修を重ねられるようなコードは、歳月とともに、どんどんわかりにくいものになってしまいます。

最初にコードを書いた時は、本人にとってはそのコードがとても明瞭に見えるものです。それまでずっとその開発に没頭し、その隅々まで熟知しているからです。しかし、しばらくして、忘れた頃に再び見てみると、いったいどうしたらこんなにひどいコードを書けたのだろう、と不思議に感じることもあります。

こういった事態を避けるには、読み手の立場に立って考え、読み手が理解できるようにコードを書く必要があります。自分の書いたコードを、他の人に見てもらうことも有効です。

アジャイルで腐敗を許さない

アジャイル型のソフトウェア開発では、変化を喜んで受け入れます。

初期設計には、ほとんど時間を割きません。

歳月とともに劣化するような初期の設計に時間をかけるのは、合理的でないからです。

その代わりに、設計を可能な限りクリーンかつシンプルに保つようにし、できるだけ頻繁にユニットテストや受け入れテストを行います。

こうすることで、設計を柔軟かつ変更しやすく保てます。その柔軟性を利用して継続的に設計を改善するので、各イテレーションの最後には、そのイテレーションでの要求にもっともふさわしい設計が得られます。

チーム文化で腐敗を許さない

ソフトウェアを限界まで無秩序へと向かわせる最大の原因は、プロジェクト活動における心理学、あるいは文化です。

腐ったコードを作らないためには、シンプルを常に意識しないといけません。さもないと、過剰な設計をしてしまったり、問題そのものより厄介な解決策を考えてしまったり、本質的な問題ではなくレアな問題ばかりに注力したりなど、コードが複雑になってしまいます。

腐ったコードを見過ごすかどうかは、そのチームの文化次第です。場当たり的な修正を繰り返し、それを許容していけば、あっという間に無秩序は増大します。それを防止するには、チームの行動方針として、コードの腐敗に気付いたら、率先してリファクタリングすることを推奨します。コードの品質を優先する方針です。そうしなければならない雰囲気を作り、全員でよってたかって悪いコードを直し、コードを腐らせる暇を与えません。確かに、コストや時間を支払わなければなりませんが、コードが腐るリスクを回避できれば、十分な見返りのある投資となります。