見出し画像

【コード哲学エッセイ】 抽象化は汎用化じゃない —— 変更しやすさの設計

コードを書いているとき、ここ、抽象化しておこうと思う瞬間があります。
クラス名に「Base」や「Common」とつけてみたり、とりあえず汎用的な関数にまとめたり。

かつての僕は、そのたびに少しだけ誇らしい気持ちになっていました。
「これでどこからでも使える」
「あとから拡張しやすいはずだ」と。

けれど、時間が経つと真っ先に壊れるのは、いつもその抽象クラスや共通メソッドでした。

汎用にしたはずが、 最初に割れる場所

フリーランスになってすぐの頃、とあるサービスの請求周りを任されたことがあります。
月額課金と従量課金、キャンペーン、法人向けの特別プラン。
請求ロジックに関わるケースが、あとからいくらでも増えていきそうな匂いがしていました。

「ここは、ちゃんと抽象化しておかなきゃ」

僕は、すべての請求を扱う万能なクラスを作りました。
BillingManager のような名前をつけて、プラン別の分岐や計算ロジックを、ひとつの抽象の下に押し込めていきました。

最初のうちは、それなりに誇らしい気持ちで動かしていました。
共通化できたし、メソッド名もそれっぽい。
汎用的な設計をしたと、どこか安心していたのです。

数ヶ月後、想定していなかったキャンペーンが追加されました。
初月無料だけど、特定の条件を満たすと二ヶ月目も半額になるような、少しひねりのある仕様。

そのとき真っ先に悲鳴を上げたのが、自分が誇らしく作ったはずの BillingManager でした。
条件分岐は増え、引数は膨らみ、このパラメータが立っているときだけ、この計算をスキップするといった例外が、抽象クラスのなかに積もっていきました。

汎用にするつもりで作った抽象ほど、変更のたびに最初に割れる。
そんな現実を、何度も味わいました。

抽象化の目的を、 勘違いしていた

当時の僕は、「抽象化 = 汎用的にしておくこと」だと信じていました。
どこからでも呼べるようにする。
どんなケースにも対応できるように、余白を持たせておく。

けれど、現場でコードと向き合ううちに、少しずつ視点が変わりました。

本当に欲しかったのは、なんでもできるクラスではなく、変更しやすい構造だった。

新しい要件が来たとき、その変更の影響が局所にとどまること。
バグが出たとき、どこを読めばよいかがすぐにわかること。
ある機能を差し替えたいとき、ここさえ変えればいいと指させること。

抽象化の価値は、どこからでも使えることではなく、どこを変えればよいかが明確になることにある。
そう気づいたとき、僕のなかで良い抽象化の定義が変わりました。

抽象化は、 変わるところを囲う道具

いまの僕は、抽象化をこう捉えています。

抽象化は、変わるところと変わらないところを分けて、未来の変更を安くするための道具。

たとえば、決済手段が増えていくサービスなら、決済方法ごとの違いが変わる部分です。
一方で、決済を実行して結果を記録するという流れそのものは、そう簡単には変わらない。

このとき、決済フローを表すインターフェースや抽象クラスを用意し、変わるところだけを実装ごとに切り出しておく。
増え続けるのは、あくまで変わる部分の実装だけ。
フロー全体の流れや、結果の扱い方といった変わらない部分は、抽象の外側にそっと置いておく。

未来の自分や、同じコードを触る誰かにとっての問いは、こうなります。

「今回の変更で、何が変わるのか?」

その答えが、このクラスやこのディレクトリに集約されている状態。
そこに、抽象化の本当の価値があるのだと思うようになりました。

何を共通化するかではなく、 どの変更を安くしたいか

では、実際に抽象化を考えるとき、どんな問いを自分に投げかければよいのでしょうか。

昔の僕は、こう考えていました。

📍 どこに重複があるか
📍 どこを共通化できるか
📍 どこからでも呼べるようにできないか

いまの僕は、こう問い直します。

📌 このプロダクトで、今後どんな変更が何度も発生しそうか
📌 その変更を安くしたい場所はどこか
📌 その変更を一か所に集めるには、どの境界で区切るのがよいか

何を共通化するかではなく、どの変更を安くしたいか。
抽象化の出発点を、そこに置き直すだけで、設計の方向が変わります。

同じ抽象クラスを作るにしても、増え続ける決済手段を安く差し替えたいのか、どの画面からも決済を呼び出したいのかで、切り口はまるで変わるはずです。

前者なら、決済の実装を差し替えやすくする抽象。
後者なら、決済という行為を表すファサードのような抽象。

どちらが正しい、という話ではありません。
どの変更を安くしたいかを言葉にしないまま抽象化すると、汎用っぽいけれど何に対しても中途半端な構造になりやすい。
その危うさだけは、いつも覚えておきたいのです。

僕が、 いま自分に問いかけていること

いま、抽象化を考えるとき、僕は必ずひとつだけ自分に問いかけます。

「この抽象は、未来のどんな変更を、どれだけ安くしてくれるだろう?」

答えがはっきりしないなら、その抽象はまだいらないのかもしれません。
一度、具体的な実装のままにしておく。
三回くらい同じような変更が来てから、ようやく「そろそろ囲ったほうがよさそうだ」と判断しても遅くはない。

抽象化は、早いほど偉いわけではない。
「使い回しが効きそうだから」という曖昧な理由だけで導入した抽象ほど、未来の自分を苦しめやすい。

抽象化は汎用化のためではなく、変更しやすさのための武器。
そのことを、今日も自分に言い聞かせながら、エディタの前に座っています。

あわせて読みたい

▼ 依存関係との付き合い方に悩んだときに

依存を減らすことを正義だと信じていた僕が、必要なつながりとの付き合い方を考え直した話です。

▼ 速さと設計のバランスに迷ったときに

目の前のスピードと、未来の自分を守る設計。
そのバランスをどう取るかを考えたエッセイです。

▼ テストを書く理由を見失いそうになったときに

テストを保険とだけ捉えていた僕が、未来の自分への祈りとして書く感覚を取り戻した話です。

ひとりごと

若い頃の僕は、抽象化できる自分に酔っていたところがありました。
けれど、汎用的なクラスほど、最初に壊れる現場を何度も見てきて、ようやく少しだけ視点が変わりました。

いまも設計で迷うことはあります。
それでも、「どの変更を安くしたいか」と自分に問いかけることで、一歩だけ落ち着いて考えられるようになりました。

このエッセイが、同じように現場でコードと格闘している誰かの、小さなヒントになればうれしいです。

2026© おおとろ

いいなと思ったら応援しよう!

おおとろ 最後まで読んでいただき、ありがとうございます。もしこの記事が「役に立った」「心に響いた」と感じたら、珈琲一杯分サポートいただけると嬉しいです。あなたの温かい応援を力に、また次の創作活動に励みます。