Prompt
ラザニアコードの改善方法は存在しない?
「スパゲッティコード」が絡まり合ったカオスなら、 「ラザニアコード」 は「あまりにも多層化されすぎて、どこで何が起きているか分からない」という、過剰な抽象化が生んだ悲劇だね。
情報工学を学ぶ君なら、DRY(Don’t Repeat Yourself)を追求しすぎたり、デザインパターンを愚直に適用しすぎたりして、気づけば 「一つの処理を追うのに 10 個のファイルをジャンプしなければならない」 という状態に陥った経験があるかもしれない。
結論から言うと、改善方法は存在する!けれど、それは「コードを追加する」のではなく、君が愛する一意性を取り戻すための 「削ぎ落とし(デリバリング)」 の作業になるんだ。
1. 「関心の分離」から「凝集度」へのシフト
ラザニアコードの最大の問題は、層(Layer)を分けること自体が目的化し、一つの機能(関心事)が複数の層に薄く引き延ばされていることだ。
-
改善策: 「垂直スライス(Vertical Slice Architecture)」 を検討しよう。
-
手法: 「Controller層」「Service層」「Repository層」という横切りの層で分けるのをやめ、「ユーザー登録」「注文処理」といった 機能単位 でコードをまとめる。
-
メリット: 一つの機能を修正する際、複数の層をまたぐ必要がなくなり、コードの「見通し」が劇的に良くなる。
2. 抽象化の「インライン化」
「将来使うかもしれない」と作られたインターフェースや、一箇所でしか使われていない抽象クラスが、ラザニアの「層」を分厚くしている犯人だ。
-
改善策: 「時期尚早な抽象化(Premature Abstraction)」 を排除する。
-
手法: 実装が一つしかないインターフェースを削除し、具体的なクラス(具象型)を直接使うように戻す。
-
格言: 「少しの重複は、間違った抽象化よりも遥かに安上がりである(A little duplication is far cheaper than the wrong abstraction)」。
3. ボイラープレートを「コード生成」や「マクロ」に逃がす
各層を繋ぐためだけの DTO(Data Transfer Object)の変換コードなどが、層を厚く見せている。
-
改善策: 手動の変換をやめる。
-
手法: Rust なら
From/Intoトレイトの実装、TypeScript ならZodの型推論などを活用し、層の間のデータの受け渡しを自動化する。 -
メリット: 意味のない「右から左へ受け流すだけのコード」が消え、ビジネスロジックだけが浮かび上がる。
4. 「深すぎるコールスタック」の平坦化
関数 A が B を呼び、B が C を呼び……という連鎖が 5 段を超えたら、それはラザニアの危険信号だ。
-
改善策: 「パイプライン処理」 や 「関数合成」 への書き換え。
-
手法: 深いネストを、データの流れ(ストリーム)として平坦に記述する。
-
君への刺さりポイント: Haskell や Rust のイテレータチェーンのような書き方だね。これなら「何が行われているか」が一箇所で上から下に読めるようになる。
見落とされがちな視点:テストコードが「層」を固定している
ラザニアコードを直せない理由の多くは、「各層ごとに細かくユニットテストを書きすぎていて、層を統合しようとするとテストが大量に壊れる」ことにある。
-
改善策: テストの粒度を上げる。
-
手法: 内部の細かい関数ではなく、「外から見た挙動(APIエンドポイントなど)」 に対してテストを書く。こうすることで、内部の「層」をどれだけ削っても、機能が壊れていないことを保証しつつリファクタリングできるんだ。
結論
ラザニアコードの改善とは、「過剰な正しさ(デザインパターンの遵守)」という呪縛から解き放たれ、シンプルという名の「究極の正しさ」に戻るプロセス だよ。
君のデジタルガーデン(https://garden.asappy.xyz)の構造も、もし「情報を探すのにクリック回数が多すぎる」と感じたら、それはラザニア化の兆候かもしれないね。
次は、「実際に Rust で、多すぎる Service 層を削ぎ落として Vertical Slice に移行するための具体的なディレクトリ構成のビフォーアフター」 を考えてみる?
Would you like me to code a comparison of a ‘Lasagna’ style implementation vs a ‘Vertical Slice’ implementation for a simple API feature?