avatar
2024年 10月 1日

良いコードは変更容易性が9割

ものごとは、それを使う人に適用できる場合にうまく設計されていると言えます。
コードの場合、それは変更に対応できなければならないことを意味しています。
このため、我々はETC原則を信じています─── 「Easier To Change」これがETC原則です。

達人プログラマー 熟達に向けたあなたの旅

世の中には良いコードを書くための様々な原則、パターン、アーキテクチャが存在しますが、常に適用できるわけではありません。 良いコードを書くためには、これらの指針を実際のプロジェクトに適用するべきか、状況に応じて判断し続ける必要があります。

この投稿では、それらの原則の根底にある変更容易性を指針とすることで、迷わずに良いコードを書きやすくなるのではないか、という現時点での僕の考えを書いていきます。

また、この投稿は達人プログラマーの2.8章「良い設計の本質」を自分なりに解釈して理解するためのものです。 タイトルは冗談が9割です。

良いコードのための無数の指針

良いコードを書くための指針は無数に存在します。 例えば、DRY、KISS、YAGNI、SOLID、オブジェクト指向設計、デザインパターン、クリーンアーキテクチャ、可読性、再利用性、一貫性などがあります。

これらの指針は無条件に従えば良いコードがかけるようになるものではありません。 最近、Googleの社内コード品質の向上に取り組んでいるCode Healthというグループが、DRY原則を厳格に適用しすぎると変更しづらくなるといった記事を出していたりします。 また、SOLID原則のSである単一責任原則は「一つのモジュールは一つの責務を持つべきである」と誤解されることがありますが、 この原則は対象が人であり、システムを扱う人が別であるなら同じ概念と思われるものも別々にするべきという原則です。

しかし、指針に従うべきかを状況に応じて判断し続けるのは難しいです。 そのためには、無数に存在する指針を誤解なく解釈し、いつ従うべきなのかの基準を覚える必要があるからです。 その結果、特定の指針に常に従うという教条主義的な態度に流れてしまうか、従うべき状況が分からず、なんとなくで従ってしまうと思います。

そのような問題を軽減するため、指針を一つに絞ることが有効だと考えました。 問題の原因は大量の指針を覚えるのが難しいということです。そこで、良いコードを書くのに効果的な指針を一つ用意することで、 教条主義や、なんとなくで指針に不適切に従わずに済みます。

良いコードとは

指針を一つだけ用意するために、良いコードとはどういうものかを考える必要があります。 良いコードを定義することができれば、原則を適用する基準にすることができそうです。

まず1つ目は、「効果的に課題を解決できるコード」です。 多くのソフトウェアの目的は、現実世界の課題を解決することです。なので良いソフトウェアとは「効果的に課題を解決できるもの」と言えます。 例えば高速に動作する、仕様通りに動いている、多くのリクエストをさばくことができる、などです。 このようなソフトウェアを実現するためのコードが良いコードだというのは、多くの人が認識していることであり、疑う余地はないと思います。

2つ目は、「変更しやすいコード」です。 課題を解決するソフトウェアを一度作って終わりというのは多くありません。課題を解決した結果別の課題が出てきたり、 バグが見つかった場合には、ソフトウェアを変更する必要が出てきます。 変更のたびにコードの様々な箇所を壊してしまったり、 変更のための期間が長引いてしまうと、良いソフトウェアから遠ざかってしまいます。そのため、変更しやすいコードも良いコードということができます。

まとめると、良いコードとは、

  • 効果的に課題を解決できるコード
  • 変更しやすいコード

であると言えそうです。

良いコードのための一つの指針

良いコードのための一つの指針として適切なのは、変更しやすいコード、つまり変更容易性のあるコードだと考えています。 もちろんどちらも重要なのですが、「効果的に課題を解決できる」というのはドメインの理解が不可欠で一般化しづらいですが、 「変更しやすいコード」はコードの設計に関わるもので一般化しやすいため、指針として適切だと考えました。 また、世の中の原則の多くは変更容易性の向上を目的として存在しているため、原則を適用するかの基準にすることができます。

我々が知る限り、この世の中のあらゆる設計原則は、ETC(Easier To Change)原則を特殊化したものとなっています。

達人プログラマー 熟達に向けたあなたの旅

変更容易性を指針にする利点

変更容易性を良いコードの指針とした場合、コードを書くときに変更という視点でコードを見ることができます。 それは「変更しやすいコードを書く」というだけではなく、

  • いつ変更されそうか
  • 変更される頻度
  • 何が変更されるのか
  • 変更するときのコスト

などもあります。 無数の原則を覚えなければいけなかった時と状況が似ていますが、変更という軸があることで考えやすくなっていると感じています。

しかし、将来の変更について考える手がかりが存在しないときには役に立たないので、小さく作ることを意識するのが良いと考えています。 コードを書き始めた初期の頃には、そのプロジェクトに対する理解が浅く、変更に対する手がかりが少ないです。 そいったときに何もしないのではなく、複雑なことをしていると思う箇所を関数やクラスに切り出しておくことで、 将来プロジェクトへの理解が増して変更に対する手がかりが揃ったときに、構造の変更を行いやすくなると考えています。 小さく作ることを意識すると、ある程度テストのしやすさは確保されるというのと、複雑なコードをあとから分割するのが難しいというのが理由です。

それらの意識だけで良いコードが書けるようにはならないので、経験を積む必要はあります。 変更容易性を指針にしていても、将来の変更を過度に意識しすぎたり、初期段階で細かく分割しすぎてしまい逆に変更がしづらくなってしまうかもしれません。 このあたりのバランス感覚を掴むためには経験を積む必要があるのですが、指針を一つに絞るとそのための振り返りは行いやすくなります。

変更容易性の注意点

変更容易性を指針にして変更という視点でコードを見ることができても、視野が狭まってしまい、 一つの変更しか見えなくなってしまうことがあります。

問題になっている例として聞いたことがあるのは、変更容易性のために抽象的なレイヤーを作りすぎて、逆に変更するのが難しくなっているというものです。 例えば戦術的DDDのテクニックやクリーンアーキテクチャを参考にしたコードでよく耳にします。

具体例として、特定のライブラリやフレームワークに依存させないためのレイヤーを導入した結果、固有の機能を使えなくなるというものがありそうです。 これはライブラリを抽象化するためのレイヤーで、別のライブラリを使おうと思ったときに入れ替えやすくすることを狙ったものです。 このレイヤーは様々なライブラリを抽象化するものであるため、固有の機能を実装してしまうと、他のライブラリに切り替えられなくなってしまいます。 そのため、裏にあるライブラリの責務が小さいか、開発側が要件をコントロールできるとき以外で使用すると問題になりやすいのだと思います。

このような問題は、変更の頻度やコストを見誤ってしまった場合に発生しやすいと考えています。 頻度が少なくコストの低い変更に着目してしまい、日常的に発生する変更に目を向けることができていないような状態です。 高い頻度で発生しそうな変更とバランスを取って、無理にコードの構造で解決せずに、手で書き換える選択を取ったほうがコストが低いこともあると思います。

さいごに

無数に存在する原則やパターン、アーキテクチャに惑わされないために、変更容易性を指針とすることで良いコードを書きやすくなるという考えを書きました。

これは良いソフトウェアを開発するためのスタートラインです。 一つだけ指針を選ぶ際に、一般化しやすいからという理由で「変更しやすいコード」を選びましたが、 実際のプロジェクトでは「効果的に課題を解決できるコード」のほうが重要だとも言えます。 そこを目指すためにはドメインに対する深い理解が必要であり、その理解が変更しやすいコードの手がかりにもなります。 良いソフトウェアを開発するためには、片方の視点だけを持つのではなく、両方の視点を持つことが重要です。