【ITニュース解説】Your-Projects-a-Mess-Its-Not-You-Its-Your-Frameworks-Fault
2025年10月03日に「Dev.to」が公開したITニュース「Your-Projects-a-Mess-Its-Not-You-Its-Your-Frameworks-Fault」について初心者にもわかりやすく解説しています。
ITニュース概要
プロジェクトの混乱はフレームワークの選び方が原因だ。自由すぎ厳格すぎは課題。Hyperlane Blueprintのような指針で機能・データを分離し、保守しやすいコードを構築する。
ITニュース解説
ソフトウェア開発の現場では、プログラミングプロジェクトが時間とともに管理しきれないほど複雑になり、混沌とした状態に陥ることがよくある。プロジェクトに参加したばかりのときや、しばらくぶりに自分が書いたコードを開いたときに、どこに何があるのか分からず、コードが絡み合った「スパゲッティコード」になっていると感じる経験は、多くのプログラマーがしているだろう。これは「ソフトウェアエントロピー」や「プロジェクト腐敗」と呼ばれる現象だ。
私たちはこの混乱の原因を、自分自身やチームの能力不足、あるいは厳しい納期に求めがちだ。しかし、長年多くのプロジェクトを見てきた経験から言えるのは、この問題の多くは、最初に選択したフレームワークに起因している可能性があるということだ。
プロジェクトの構造に関して、主要なフレームワークには二つの極端なタイプが存在する。
一つ目は「意見を持たないフレームワーク」と呼ばれるものだ。例えばExpress.jsやFlaskのようなマイクロフレームワークがこれに当たる。これらは非常に柔軟性が高く、小さく、短時間で「Hello World」のような簡単なアプリケーションを動作させることができる。そのシンプルな特性は魅力的だ。しかし、プロジェクトが規模を拡大していくと、この「自由さ」が問題の温床となる。これらのフレームワークは、プロジェクトの構造に関するルールをほとんど提供しない。理論上はすべてのコードを一つのファイルに詰め込むことも可能だ。チームで開発を進める場合、開発者Aはデータベースのモデルをmodels/ディレクトリに置くと考え、開発者Bはdata/entities/に慣れている、開発者Cはユーザー関連のロジックやデータ構造をroutes/user.jsに直接定義するといった具合に、それぞれが自身の理解に基づいてコードを配置し始める。その結果、プロジェクトは異なる考え方が混在する寄せ集めになってしまう。統一された基準がないため、コードの配置に一貫性がなく、新しく参加したメンバーは何がどこにあるのか、プロジェクトの暗黙のルールを理解するまでに数週間から数ヶ月を要することになる。この種のフレームワークは、開発者に最大限の自由を与えるが、同時に方向性を見失わせる危険性がある。
二つ目は「意見を持つフレームワーク」と呼ばれるものだ。Ruby on RailsやDjangoのような古典的なフレームワークがこれに該当する。これらは「設定より規約(Convention over Configuration)」という哲学の典型だ。モデルはどこに配置すべきか、ビューはどこか、コントローラはどのように命名すべきかなど、あらゆることをフレームワークが厳密に規定する。これらの規約に従って開発を進める限り、開発効率は非常に高くなる。しかし、これはある意味でフレームワークによる支配とも言える。フレームワークの規約に合わない特別な要件に直面した場合、その規約に逆らうことは非常に困難だと感じるだろう。フレームワークの内部メカニズムは強く結合しており、小さなデフォルトの動作を変更するためには、その複雑なソースコードを読み解いたり、特殊な手法を使ったりする必要があるかもしれない。これは快適ではあるものの、開発者のあらゆる動きが制限されてしまう状況だ。
では、理想的なフレームワークとはどのようなものだろうか。それは、細部にわたってすべてを決定するのではなく、堅実で合理的、そして実績のある「建築設計図」を提供するような存在であるべきだ。開発者に正しい方向を示しつつも、十分な創造的な空間を残すようなフレームワークが理想的だ。
ここで「hyperlane-quick-start」プロジェクトで示されているディレクトリ構造は、まさにそのような優れた設計図の一つだ。これは強制されるものではないが、プロフェッショナルで拡張性のある組織化の方法を強く推奨している。
この設計された構造を見てみよう。主要な部分としてapp、config、init、plugin、resourcesといったディレクトリがある。この中でも特に重要なのがappディレクトリ内部だ。ここにはcontroller、service、mapper、model、middlewareなどのレイヤーが含まれている。
この構造の核となる考え方は「関心事の分離」である。それぞれのレイヤーは特定の役割を持ち、その役割を完璧に遂行する。
controller(インターフェース制御層)は、HTTPリクエストとレスポンスの処理だけを担当する。クライアントからのリクエストを受け取り、それを専門のビジネス部門(service)に渡して処理させ、その結果をクライアントに返す。controllerはデータベースの詳細や複雑なビジネスロジックについては一切関知しない。service(ビジネスロジック層)は、アプリケーションの本当の「ビジネスの中核」だ。ユーザー登録、注文作成、記事公開など、すべてのコアなビジネスロジックがここで実行される。データがHTTP経由で来たのか、コマンドラインから来たのか、あるいはどのデータベースに最終的に保存されるのか、といったことには関心を持たない。ここは純粋で再利用可能なビジネスロジックを集約する場所である。mapper(データアクセス層)の責任は、データベースとのやり取りだ。service層が必要とするデータをデータベースから取得したり、データを保存したりする役割を果たす。これにより、ビジネスロジックはデータの保存方法から切り離され、独立性を保つことができる。
この階層化が設計図の骨格だとすれば、model層のきめ細かい分割はその本質とも言えるだろう。多くのプロジェクトでは、modelsという一つのディレクトリにあらゆる種類の「モデル」が詰め込まれてしまうが、これは大きな間違いだ。Hyperlaneの設計図は、データがアプリケーションの異なる段階で異なる「形式」を持つべきだと示している。
具体的には、以下の細分化が提案されている。
param(パラメータオブジェクト)は、controllerが受け取るHTTPリクエストパラメータをカプセル化する。これにより、ルート関数の引数が長くなるのを防ぎ、リクエストのバリデーションにも利用できる。persistent(永続化オブジェクト)は、データベースのテーブル構造に正確に対応する。データベーステーブルには、ビジネスロジックやAPIの利用者には関係のないcreated_atやupdated_byといったフィールドが含まれることがあるが、persistentオブジェクトはそれらを表現する。domain / bean(ドメイン/エンティティオブジェクト)は、コアなビジネスドメインオブジェクトを表し、ビジネス上の振る舞いを含む。例えば、Orderオブジェクトはデータだけでなく、cancel()のような操作も持つべきだ。これこそがビジネスの中核となるオブジェクトである。dto(データ転送オブジェクト)は、APIでデータを転送するために特別に設計されたデータ構造である。これは内部実装の詳細を隠蔽し、ユーザーのパスワードハッシュのような機密データがAPIのレスポンスに漏洩するのを防ぐ上で非常に重要だ。dtoはAPI契約の保証となる。view(ビューオブジェクト)は、フロントエンドのページをレンダリングするために特化したデータ構造だ。APIがJSONを返す場合でも、サーバーでレンダリングされるページが必要とするデータ構造は全く異なる可能性がある。この明確な分離は、フロントエンドとバックエンド双方の開発を容易にする。
このきめ細かい分割は、最初は少し手間がかかると感じるかもしれない。しかし、プロジェクトが成長するにつれて、この明確な区別があったことに必ず感謝するだろう。これは一連の仕切りのように機能し、異なるレイヤーの実装詳細が互いに漏洩するのを防ぎ、システム全体の長期的な健全性を確保する。
フレームワークがただAPIの集合体を提供するだけでは、その役割の50%しか果たしていない。残りの50%は、それが提唱する「哲学」や「ベストプラクティス」であるべきだ。良いフレームワークは、その推奨するパターンを通して、開発者に良いアーキテクチャの習慣を育むものだ。
Hyperlaneの設計図は、この哲学を完璧に具現化している。それは開発者に特定のやり方を強制するのではなく、成功への明確な道筋を示している。プロフェッショナルなWebアプリケーションがどのようにあるべきかを教えているのだ。
だから、次に新しいプロジェクトを始めるときは、そのフレームワークが「Hello World」をどれだけ速く動かせるかだけで満足してはいけない。それが今回紹介したような「アーキテクチャの設計図」を提供しているかどうかを確認することが重要だ。良いスタートはまさに戦いの半分を制したことに等しい。適切なアーキテクチャは、設計された堅牢なプロジェクトのように、あなたのプロジェクトが時の試練に耐え、エレガントで、保守しやすい状態を長く保つことを保証するだろう。