0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AI時代に"設計"と向き合ってみる ③|「共通化しろ」って言うたやんけ!線引きが難しすぎる問題

0
Posted at

はじめに

前回(②大原則編)で、設計の7つの大原則と、その親玉「変更に強くする」を腹落ちさせた私。いい感じに賢くなった気がして、調子に乗ってました。

特にDRY。「同じ知識は一箇所に」。これはもう完全に理解した。似たコードを見つけたら、まとめればいいんでしょ? 簡単じゃん。……と思っていたら、先輩に冷たい目で止められたのが前回のラスト。

:sweat_smile::DRY守ってるだけなのに、なんでダメなんですか?

:sunglasses::その「似てたらまとめればいい」が、一番事故るやつやからや。

:sweat_smile::……いや、意味わかんないっす。共通化しろって言うたやん。

:sunglasses::まあ聞け。お前みたいに「原則は知ってる、あとは当てはめるだけ」と思ってるやつが、一番きれいに転ぶんよ。

今回はこの 「線引き」 の話です。原則を知ってるのに、なぜか実務でうまく使えない——たぶんこのシリーズで一番、私が長いこと悩んできたところ。

原則を知ってても、使えない

正直に告白すると、私はエンジニア4年目で、ここに挙げた原則は全部「聞いたことある」レベルでは知ってました。SOLIDもDRYもYAGNIも。

でも、知ってるのに使えない

  • DRY:目の前の似たコード、これは共通化すべき? それとも放っておくべき?
  • YAGNI:この機能、今作るべき? それとも「まだ要らない」?
  • 抽象化:このクラス、インターフェース切るべき? やりすぎ?

全部、「どこで線を引くか」 がわからない。原則は知ってるのに、いざ手を動かすと毎回迷う。

そして、さっき先輩が言った通り、線引きをミスると「やらなさすぎ」より 「やりすぎ」の方が地獄 だったりします。良かれと思って共通化したコードが、いつの間にか全機能から参照される密結合の塊になって、一箇所いじると全部が連鎖崩壊する……ってやつ。

ミノ駆動さんの有名なクソコード動画「共通化の罠」が、まさにこれを的確に描いてて、初見で笑ったあと真顔になります。

「共通化、よかれと思ってやったのに、なんで地獄になるの?」── この感覚、心当たりある人多いんじゃないでしょうか。私はめちゃくちゃあります。

:sweat_smile::先輩、これ僕の勉強不足ですよね…。原則の理解が浅いから、使いこなせないんだ。

:sunglasses::いや、ちゃう。それな、勉強不足ちゃうねん。線引きが難しいのには、ちゃんと構造的な理由があるんよ。

え、私のせいじゃない…?

なぜ線引きは「本質的に」難しいのか

先輩いわく、線引きが難しいのは努力や才能の問題じゃなくて、そもそもの構造が難しいからだそうです。理由は4つ。

理由1:文脈で正解が変わる

同じコードでも、状況次第で正解が逆になります。

:sunglasses::3日で捨てる試作品なら、多少汚くても動けば正解。10年使う基幹システムなら、最初から丁寧に設計するのが正解。同じコードでも、寿命や目的で答えがひっくり返るんよ。

「絶対の正解」が存在しないから、原則を機械的に当てはめても外れる。

理由2:原則同士がケンカする

前回「7つは全部地続き」と言いましたが、実務では原則同士がぶつかることもあります。

  • DRY(重複を消せ)と YAGNI(先回りするな):「2回しか出てないけど、3回目が来そう。今まとめる?」
  • 高凝集(きっちり分けろ)と シンプルさ:「完璧に分けるとファイルが爆発する」

:sweat_smile::片方を立てると、もう片方が倒れる…

:sunglasses::そう。どれか1つに従うと、別のが破れるのが普通や。だから「全部守る」は無理で、毎回「今回はどっちを優先するか」を選ぶしかない。

前回「7つは全部同時には満たせない、どれをどこまで適用するかは毎回トレードオフ」と言いましたが、まさにこれです。

理由3:未来予測は、たいてい外れる

線引きの多くは「将来どうなるか」の予測に依存します。「この機能、将来拡張されるかな?」と。

:sunglasses::でもな、その「将来こうなるやろ」って予測、当たることのほうが少ないんよ。

:sweat_smile::そんなに外れるんですか…!

:sunglasses::そう。未来を読んで打った手の大半は、的外れに終わる。だから「将来のため」の先回り設計は、そもそも分が悪い賭けなんよ。

理由4:答え合わせが、数ヶ月〜数年後に来る

これが一番きつい。設計判断が良かったか悪かったかは、変更が必要になった瞬間 に初めてわかります。

:sunglasses::「あの抽象化、正解やったな」とか「あれは過剰やったわ」って気づくの、リリースの数ヶ月後、下手したら数年後やろ。

:sweat_smile::フィードバックが遅すぎて、学習できない…

:sunglasses::そういうことや。打った手の結果がすぐわからんから、上達しにくい。これが線引きが難しい、4つ目にして最大の理由や。

……というわけで、線引きが難しいのは私の能力のせいじゃなかった。構造的にムズいんです。ちょっと安心しました:sob:

じゃあ、どうすればいいのか

:sweat_smile::構造的に難しいのはわかりました。でも「難しいから諦めろ」じゃ困るんですよ。

:sunglasses::もちろん。完璧な正解は出せんでも、判断の質を上げるコツはある。代表的なやつを3つ教えたろ。

コツ① 3回ルール(Rule of Three)

DRYの線引きで一番実用的なやつ。「同じコードが何回出たら共通化するか」のヒューリスティックです。

  • 1回目:とりあえず書く
  • 2回目:コピペでOK(多少モヤッとしても我慢)
  • 3回目:ここで初めて「共通化する?」を検討

:sweat_smile::なんで2回目はコピペでいいんですか? もう重複してるのに。

:sunglasses::2回だけやと、それが 「本当に同じ知識」なのか「たまたま似てるだけ」なのか、判断できんからや。前回の住所の話、覚えてるか?

前回(②)のDRYで、「住所みたいに同じ"知識"があちこちに散らばってるのは、消すべき重複」という話をしました。でも厄介なのはその逆で、たまたま見た目が似てるだけのコードは、共通化すると事故ることがある。3回ルールは、この「本物の重複」と「似てるだけ」を見極めるための「待ち時間」なんですね。

:sunglasses::3回目が出てくると、「あ、これ毎回セットで出てくるな=同じ知識やな」ってパターンが見えてくる。逆に2回で慌ててまとめると、後で「やっぱ別物やった」ってなって剥がす羽目になる。

:sweat_smile::早すぎる共通化は、むしろ損なんですね。

「早すぎる抽象化のコスト > 重複のコスト」

コツ② 迷ったら、具象に倒す

これも実務で効く指針です。迷ったら、共通化せずにベタ書きしておけ

理由は、抽象化には 非対称性 があるから。

:sunglasses::ベタ書き(具象)から共通化(抽象)するのは、後からでも簡単や。3つ目が出てきたら、そのときまとめればええ。

:sweat_smile::逆は?

:sunglasses::抽象から具象に戻すのは、地獄や。一回まとめたものを「やっぱバラそう」ってなったら、それに依存してる全部のコードを直して、テストも書き直し。やる方向とほどく方向で、重さが全然違うんよ。

具象 → 抽象(後でまとめる)   :軽い。3つ目が出たらやればいい
抽象 → 具象(まとめたのを剥がす):重い。依存してる全部を直す羽目に

進む方向(具象→抽象)は軽くて、戻る方向(抽象→具象)は重い。だったら、軽い方に倒しておくのが安全。迷ったら具象、これだけで設計の事故がだいぶ減ります。

コツ③ 「戻すコスト」を毎回問う

3つ目は、前回の 可逆性 の実践版。判断する前に、毎回これを問います。

「この判断、もし間違ってたら、戻すのに何がかかる?」

:sunglasses::たとえばライブラリの採用。まだ依存が広がってへん早い段階なら、やめるのは軽い。でも全体に使い倒した後やと、引き剥がすのが地獄や。

:sweat_smile::同じ「やめる」でも、タイミングで戻すコストが全然違う…

:sunglasses::そう。だから「正しいかどうか」だけやなくて、「間違えたとき、どっちが戻しやすいか」で選ぶ。戻しやすい方を選んどけば、判断ミスが致命傷にならん。

「絶対正しい選択」は選べなくても、「間違えても傷が浅い選択」なら選べる。これが不確実な中での現実的な戦い方です。

共通化、ありがちな2つの失敗

コツがわかったところで、逆に「やりがちな失敗」も知っておくと事故が減ります。2方向あります。

失敗1:「似てる」を「同じ」と勘違いする

前回ちらっと出した、この例。

calculateUserScore(user)       { return user.points * 1.5; }
calculateProductScore(product) { return product.rating * 1.5; }
calculateOrderScore(order)     { return order.amount * 1.5; }

3つとも * 1.5 してて、見た目はそっくり。「DRYだ!まとめよう!」と、こうしたくなる。

calculateScore(value) { return value * 1.5; }

:sunglasses::これな、やった瞬間は気持ちええ。でも後で詰む典型や。

:sweat_smile::なんでですか? ちゃんと重複消せてますよ。

:sunglasses::「ユーザーのスコアだけ、係数を2.0に変えたい」って要件が来たらどうする? まとめたせいで、商品も注文も巻き添えになるやろ。

ここで効くのが、前回も出た判断基準です。

「この3つは、"同じ理由で"変更されるか?」

同じ仕様変更が来たら3つとも一緒に変わる、なら共通化してOK。でも「ユーザーのスコアだけ変えたい」が起こりうる=変わる理由が別々なら、たまたま今は似てるだけ。消しちゃダメ。

:sunglasses::見た目で判断すんな。「変わる理由が同じか」で判断せえ。これが単一責任原則(SRP)の本当の意味でもあるんよ。

失敗2:逆に、重複を放置しすぎる

「具象に倒せ」「3回ルール」を聞くと、今度は「じゃあ共通化しなきゃいいんだ」と振り切る人がいます。これも失敗。

:sweat_smile::え、でも「迷ったら具象」って言いましたよね?

:sunglasses::迷ったらな。でも同じ知識が10箇所、20箇所に増えてもまだ放置、はやりすぎや。そこまで散らかってから直すと、リファクタのコストが膨らむ。

3回ルールは「早すぎる共通化を防ぐ」ためのもので、「永遠に共通化するな」じゃない。

:sunglasses::理想は、3〜5回くらいで「お、そろそろまとめどきやな」って 匂いを嗅ぎ取れる こと。早すぎず、遅すぎず。

:sweat_smile::その嗅覚、どうやって鍛えるんですか?

いい質問です。そして、それが今回の結論に繋がります。

結論:線引き力は「言語化」で育つ

:sweat_smile::結局、この「線引きの嗅覚」ってどうやったら身につくんですか? 近道は?

:sunglasses::残念ながら、近道はない。経験の量 × 振り返りの質、これでしか伸びん。本を読むだけじゃ絶対に身につかんネタや。

ただ、「振り返りの質」を上げる具体的な方法はあります。それが 判断の言語化 です。

設計判断するとき、頭の中だけで決めて終わりにせず、こう書き残す。

【検討した選択肢】
A. 共通化する  B. 重複のまま残す  C. 一部だけ共通化

【選んだ理由】
今は2箇所だが、関連機能で3箇所目が確実に出るのでA。
ただし実装時に再評価する余地を残す。

【切ったトレードオフ】
抽象化レイヤーが1段増える。将来仕様が分岐したときのリスクは残る。

:sunglasses::これをPRの説明とかADR(設計判断の記録)に残す癖をつけると、自分の判断パターンが見える化されるんよ。

:sweat_smile::なんでそれが嗅覚に繋がるんですか?

:sunglasses::記録がなかったら、3ヶ月後に結果を見ても「当時何考えてたっけ」で終わりや。それやと答え合わせにならん。さっき言うた「答え合わせが遅すぎる」問題(理由4)やな。記録しとくから、遅れてきた答えを当時の判断と突き合わせて、ちゃんと学習に変えられるんよ。

書き残すことで、遅れてくる答え合わせを「あのとき何を考えてたか」と突き合わせられる。これが振り返りの質を上げ、線引きの嗅覚を育てる。地道だけど、これが王道なんですね。

まとめ

今回のポイント。

  • 原則を知ってても線引きできないのは、勉強不足じゃなく構造的に難しいから(文脈依存/原則のトレードオフ/予測はたいてい外れる/答え合わせが遅い)
  • 完璧な正解は出せないが、判断の質を上げるコツはある
    • 3回ルール:3回出るまで共通化を待つ
    • 迷ったら具象:抽象化は軽い、解体は重い。軽い方に倒す
    • 戻すコストを問う:「間違えたら戻すのに何がかかる?」で選ぶ
  • 共通化の失敗は2方向:「似てる」を「同じ」と勘違い/逆に放置しすぎ。 「変わる理由が同じか」 で判断
  • 線引き力は 経験量 × 振り返りの質 でしか伸びない。判断の言語化(PR・ADR)が振り返りの質を上げる

線引きに「これさえやればOK」の魔法はない。でも、向き合い方の型はある。これを知ってるだけで、毎回の迷いが「意味のある迷い」に変わると思います。

で、次回

線引きの基本戦略が見えてきました。「迷ったら具象から始めて、共通項が見えてから抽象化する」。これで万事解決……かと思いきや、先輩が一言。

:sunglasses::……まあ、基本はそれでええ。でもな、「最初から」きっちり設計せなアカンものも、世の中にはあるで。

:sweat_smile::え? 「迷ったら具象」じゃなかったんですか?

:sunglasses::それが通用せん領域があるんよ。後から変えると、死ぬほど痛いやつ。

:sweat_smile::なんですかそれ、こわい。

:sunglasses::キーワードは 「契約」 や。……長くなるから、次回な。

次回は、「具象から始める」戦略が通用しない例外 ── 「契約」の設計 に踏み込みます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?