今年でエンジニアとして3年目を迎えました。
まだまだ駆け出しエンジニアではあるものの、少しずつ年数が増えて、いつまでも初心者としての立ち位置では居られなくなってきたことも事実です。
そこで、エンジニアの原理原則を学べる名著として知られている『プリンシプル・オブ・プログラミング』を読んで、これからエンジニアとして初心者レベルを脱却していくために必要な知識を学習していきたいと思います。
この記事では、読み進める中で、私が特に重要だと感じたものをピックアップして紹介していきます。
本書の中には全部で101のプリンシプルが書かれているので、この記事では紹介しなかった他のプリンシプルも知りたいという方は、ぜひ本書を購入して読んでみてください。
シンプル・イズ・ザ・ベスト
コードを簡潔に保つことは、何よりも重要なプリンシプルです。
なぜなら、ソフトウェアは大抵の場合、短期的に使われて終わるものではなく、変化を伴いながら長期的に運用していくものだからです(1週間限定のシステムやアプリなどは、あまり聞いたことがありませんね)
ソフトウェアは長期的・継続的に運営していくものと考えると、保守性と拡張性という2つの観点が非常に重要になってきます。
そして、保守性と拡張性を高めるためには、誰から見てもコードが理解しやすい状態、つまりコードが簡潔に保たれていることが大切なのです。
同じコードを繰り返すな(Don't repeat yourself)
同じコードを繰り返し書かないというのは、コードを簡潔に保つために最も効果的な方法です。
もし以前にも同じようなコードを書いたなら、コピペするのではなく、ロジックを切り出して関数やモジュールとして再利用可能な形にするべきです。
関連性の強いコードは一つにまとめておくことで、修正を加える際の影響範囲も狭くなり、より拡張性の高いコードとなります。
ただし、コードをまとめることを意識しすぎて、一つの関数やモジュールに複数の責務を負わせてしまわないように注意しましょう。
「重複を排除する」ことは「コードを簡潔に保つ」ための手段であって、目的ではありません。
コードは読みやすさが最優先
コードは書かれる時間よりも読まれる時間の方が圧倒的に多いです。
そのため、多少実装に時間がかかったとしても、その後の利益を考えて読みやすいコードを書くことを優先すべきです。
例えば、下記のようなことを意識するだけでも、コードの読みやすさは飛躍的に向上するでしょう。
読みやすいコードを書くために
- 関数や変数に適切な名前をつける
- コメントはWhyの部分を意識して書く
また、人が読むものという観点では、良いコードと良い書籍は似たような性質があります。
書籍のように目次や章、段落が整理されており、一目見れば全体の構造を理解できる状態が理想的なコードといえるでしょう。
怠惰であれ
「怠惰」という単語は少しマイナスなイメージがありますが、プログラミングにおいて実はとても重要なことです。
楽をすることを意識すると、効率的に開発を進められるだけではなく、ミスやバグの発生も最小限に抑えることができます。
作業を自動化する
開発を進めていく中で、何度も同じような作業をしなければならない場面を経験したことのある人は多いでしょう。
一回一回の作業はそこまで時間がかかるものではなかったとしても、それらが積み重なると最終的には大きなコストを割くことになってしまいます。
CI/CDツールを利用してデプロイ作業を自動化したり、テストツールでユニットテストやリグレッションテストを自動化することで得られる利益は、導入にかかるコストよりも圧倒的に大きなものになるはずです。
できるだけコードを書かない
「よいプログラマはよいコードを書く。偉大なプログラマはよいコードを借りてくる」
本書に登場した名言の中で、私の一番お気に入りの言葉です。
ソフトウェアを開発する際、ついつい「どのようにコードを書くか」ということに目を向けてしまいがちです。
しかし、発想を転換して「どうすればコードを書かなくて済むか」を考えるようにすれば、時間や労力を節約することができて、本当に必要な箇所にだけリソースを集中できるようになります。
急がば回れ
ソフトウェアの開発を行ううえで出てくる問題は、一見すると解ける気がしないほど高度で複雑なものが多いです。
そういった問題に出くわすと、だんだんと思考するのが面倒になり、一足飛びに解決できる魔法がないかと期待してしまいがちです(私もよく魔法使いにジョブチェンジしたくなります…)
しかしこういう時こそ、急がば回れの精神で地道に取り組んでいくことが、よいエンジニアとなるために必要な心構えなのでしょう。
一つずつ、一歩ずつ
あなたが今、新規機能の開発と不具合修正の二つのタスクを抱えていたとします。
このとき、たとえ一気にプログラミングを進めた方が効率的だったとしても、同じブランチや同じコミットの中に、両方のタスクの作業内容を混ぜてしまうのは危険です。
開発を進めていくうえで、下記のような要望が生まれることは多々あります。
こんな要望が出てきたらどうする?
- 新規機能の仕様が変更となったため、途中まで作業を巻き戻したい
- 不具合修正のみ先にリリースしたい
一つのブランチやコミットに対して一つのタスクのみ進めるようにしていれば、上記の要望に応えることは比較的容易です。
しかし、もし複数のタスクを一つにまとめてしまっていた場合、途端に面倒な作業となってしまいます。
後々困らないようにするためにも、タスクは一つずつ確実に進めていき、並行する場合には別々の場所で管理するようにしましょう。
技術的負債はコツコツ返済する
ソフトウェアの歴史が長くなってくると、使用しているフレームワークやライブラリのバージョンアップへの対応なども必要になってきます。
アップデートが容易に行えるような軽微な内容であれば問題ないのですが、コードに大幅な修正を加えなければならないような破壊的変更を伴う場合は、いったん対応を先延ばしにすることもあります。
他のタスクとの優先度の兼ね合いもあるため、対応を先延ばしにすること自体は悪い選択ではありませんが、そのままにしておくと技術的負債がたまっていく一方です。
日々の中で余裕があるときを見つけて、できるだけ早くコツコツと負債を返済していくことを心がけましょう。
速いコードより正しいコードを
エンジニアとしての技術力が上がってくると、より洗練された、素早くパフォーマンスの高いコードを書きたい欲が出てくるものです。
もちろん、パフォーマンスを向上させることはUXなどの面でもとても大事なことです。
しかし、それを追い求めすぎるあまりコードが複雑で読みづらいものになってしまうと、バグの多発、拡張性や保守性の低下など、逆に悪影響を及ぼしてしまう可能性があります。
誰から見ても分かりやすく、必要な機能を十分に満たしている「正しいコード」は、複雑でわかりづらいけれどもハイパフォーマンスの「速いコード」よりも優れているのです。
変化に耐えうる柔軟性を
世の中で運営されているソフトウェアのうち、最初に実装されてから一度も変更されないものは、存在しないといっていいでしょう。
現実が常に変化し続けている以上、ユーザーのニーズも変化し、それに伴ってソフトウェアの方も変更が必要になるからです。
そのため、エンジニアはコードを書くときに、未来の変化にも適応できるような柔軟性を意識しておかなければなりません。
変更を予測する
プログラミングをするうえで、あらかじめ「今後変更される可能性があるとしたらどこだろうか?」という予測を立てる癖をつけておくと、長い目で見たときに非常に役立ちます。
そして、変更可能性の高いところを見つけたら、その変更の可能性も考慮したコードを実装しておくと、将来本当に変更が必要となったときに、大きな見返りを得られるでしょう。
ただし、コードの汎用性の高さと、実装コストやコードの複雑さは常にトレードオフの関係にあります。
全ての可能性に備えようとして欲張りすぎず、バランスを取って実装することが重要です。
コードを独立させる
複数の関数やモジュールがそれぞれ複雑に絡み合っている(結合度が高い)状態では、気軽に変更を加えることができません。
あるモジュールで変更したメソッドが、他のモジュールに悪影響を及ぼしてしまう可能性があるからです。
影響がないことを確認するためには、関連しあっている全てのモジュールの内部実装を紐解く必要があり、これは時間的にも能力的にも、エンジニアにとって非常に高いコストとなってしまいます。
そのような状況を避けるためにも、それぞれの関数やモジュールはできるだけ独立(結合度を低く)させて、変更が他の箇所に影響を与えないように実装することが大切です。
テストのないコードは危険
コードに変更を加えたとき、その変更によって既存の機能に思わぬ影響が出ていないかを確認するために行われるのがリグレッションテストです。
テストを手動で行うことも出来なくはないのですが、機能が増えていくにつれて指数関数的にコストが増大していくため、あまり現実的ではありません。
テストコードがきちんと実装されていれば、コマンド一つでリグレッションテストを実行することができるため、コードの変更に対する品質保証のハードルを低くすることができます。
少し面倒に感じるかもしれませんが、コストよりも得られるメリットがはるかに大きいものなので、必ずテストは作成するようにしてください。
まとめ
いかがでしたでしょうか。
言われてみれば当たり前の内容ばかりですが、実際の開発時にこれらすべてを意識できているエンジニアは意外と少ないように感じます。
派手で突出した才能はなくても、確実にチームに貢献できる「普通のエンジニア」を目指して、この本で学んだことを日々の業務の中でも実践していきたいと思います。