はじめに

「とりあえず動くものを作る」。

ソフトウェア開発では、どうしてもこの誘惑があります。

目の前に要件があり、それを満たすために必要なAPIを調べ、コードを書き、動作確認をする。テストも通った。これで完成です。

しかし、その実装が半年後、1年後も安全に変更できるとは限りません。

私は最近、ソフトウェア開発において特に避けるべきなのは、単に「バグのあるコード」や「複雑なコード」ではなく、

変更したときの影響範囲が読めないコードを書くこと

なのではないか、と考えるようになりました。

そして、そのようなコードが生まれる大きな原因の一つが、

仕様や利用する技術の仕組みを十分に理解しないまま、目の前の要件を満たす実装をしてしまうこと

なのではないかと思います。

1. 影響範囲が読めないコードの例

例えば、ECサイトに「購入金額が1万円以上なら送料無料」という仕様があったとします。

目の前の要件を満たすだけなら、注文処理の中に、

if (totalPrice >= 10_000) {
    shippingFee = 0
}

のような処理を追加すれば十分です。

実際に動作しますし、テストも通るでしょう。

ところが、しばらくして仕様が変更され、

「1万円以上でも、一部の商品は送料無料の対象外とする」

となったとします。

すると、先ほど追加した処理を変更する必要があります。

さらにその後、

「会員ランクがゴールド以上なら、5,000円以上で送料無料」

という仕様が追加されたらどうでしょうか。

最初は注文処理の中に直接書いた条件が、次第に複雑になっていきます。

if (totalPrice >= 10_000) {
    shippingFee = 0
} else if (isGoldMember && totalPrice >= 5_000) {
    shippingFee = 0
}

さらに商品ごとの例外が追加され、キャンペーンが追加され、地域による違いが追加され……。

最初は「数行追加するだけ」だった実装が、いつの間にか、

「送料の仕様を変更したら、どこに影響するのか分からない」

という状態になってしまいます。

ここで重要なのは、最初の実装が間違っていたとは限らないことです。

その時点では、要件を満たしていたかもしれません。

問題なのは、目の前の要件だけを見て実装した結果、後から仕様との関係を追いにくくなってしまったことです。

2. 仕様とコードの因果関係を分かりやすくする

では、どうすればこのような状態を防げるのでしょうか。

一つの方法は、

仕様に存在する概念やルールを、コード上でも分かる形にすること

だと思います。

先ほどの例なら、「送料」という単純な値を注文処理の中で直接変更するのではなく、

注文
 ↓
送料を計算する
 ↓
送料無料条件を判定する
 ↓
送料を決定する

という仕様上の流れが、コードからも読み取れるようにします。

すると、仕様変更が発生したときにも、

「送料無料の条件が変わったので、送料を計算している部分を確認すればよい」

と判断できます。

これは単にコードを綺麗にするという話ではありません。

仕様とコードの因果関係を明確にすることが重要なのです。

逆に、同じ仕様に関する条件が画面やAPI処理、データベース処理などにバラバラに書かれていると、

「この仕様に関係するコードはどこにあるのか?」

から調査しなければなりません。

そして、変更漏れがバグにつながります。

3. 開発者にとって怖いのは「影響範囲が読めないコード」

ここまで考えると、コードの「読みやすさ」についても少し違った見方ができます。

一般的に、読みやすいコードというと、

  • 変数名が分かりやすい
  • メソッドが短い
  • ネストが浅い
  • クラスが大きすぎない
  • コメントが適切

といったことが挙げられます。

もちろん、これらは重要です。

しかし、それ以上に重要なのではないかと思うことがあります。

それは、

そのコードを変更したとき、何が変わり、何が変わらないのかを予測できること

です。

100行あるコードでも、

「このコードは送料計算だけを担当している」

と分かっていて、その責務が明確なら、変更の影響範囲を予測できます。

一方で、10行しかないコードでも、

「このコードを変更すると、なぜか別の画面の動作まで変わる」

という状態なら非常に危険です。

つまり、コードの行数や見た目の複雑さだけでは、変更リスクは判断できません。

本当に怖いのは、

「このコードを変更したら、何が起こるのか分からない」

という状態です。

私は、これこそが開発者にとって非常に大きなリスクだと考えています。

4. 良いコードとは「変更の影響範囲が読めるコード」

ソフトウェアは、一度作ったら終わりではありません。

仕様は変更されます。

新しい機能も追加されます。

既存の機能が廃止されることもあります。

つまり、ソフトウェアにとって「変更されること」は前提です。

だからこそ、開発者が考えるべきなのは、

「どうすれば今の要件を満たせるか」

だけではなく、

「この仕様が変更されたとき、私は影響範囲を読めるだろうか」

ということなのではないでしょうか。

そのためには、仕様を理解し、その仕様に存在する概念やルール、因果関係をコードに適切に落とし込む必要があります。

これはAndroidのプラットフォームAPIを扱う場合でも、外部サービスを利用する場合でも、純粋なビジネスロジックを実装する場合でも同じです。

よく分からない仕組みを「とりあえず動くから」という理由だけで利用し、その挙動をアプリの前提としてしまう。

目の前の要件だけを満たすために、仕様上の意味を考えず条件を追加する。

こうした実装を積み重ねると、やがて仕様とコードの因果関係が分からなくなります。

そして、

「この変更はどこまで影響するのか?」

という問いに答えられなくなります。

だから私は、

やってはいけない実装とは、必ずしも「汚いコード」ではない。

最も避けるべきなのは、変更したときの影響範囲が読めなくなるコードを書くことなのではないか。

と考えています。

良いコードとは、単に現在の要件を満たしているコードではありません。

仕様とコードの因果関係が明確で、変更したときに何が変わり、何が変わらないのかを読み取れるコード。

それこそが、長く保守されるソフトウェアにとって重要なのだと考えます。