退屈なアーキテクチャのルール(明確なフォルダ境界、一貫した命名、シンプルなデフォルト)を使って生成コードを保守しやすくする方法を学びましょう。

生成コードは日常の仕事を変えます。機能を作るだけでなく、短時間で大量のファイルを生み出すシステムを導くことになります。速さは本物ですが、小さな不一致が急速に増殖します。
生成された出力は単体では問題なさそうに見えます。コストが現れるのは2回目、3回目の変更時です:そのコードがどこに属するか分からない、同じ振る舞いを二箇所で直す羽目になる、あるいは影響範囲が分からず触れたくないファイルが出てくるなどです。
「賢い」構造は予測が難しく高コストになります。カスタムパターン、隠れたマジック、過度な抽象化は初日には理にかなって見えますが、6週目には次の変更が遅くなります。AI支援の生成では、その賢さが将来の生成を混乱させ、ロジックの重複や上に積み重なる新しい層を生むこともあります。
退屈なアーキテクチャはその逆です:明瞭な境界、平凡な名前、分かりやすいデフォルト。完璧を目指すわけではありません。疲れたチームメイト(または将来の自分)が30秒で理解できるレイアウトを選ぶことです。
シンプルな目標は:次の変更を簡単にすること、かっこよくすることではありません。通常は、UI・API・データ・共有ユーティリティそれぞれに明確な置き場所があり、ファイルの役割に合った予測可能な名前を付け、自動配線や隠れたグローバル、メタプログラミングのような“魔法”を最小化することです。
例:Koder.ai に「チーム招待」を追加するよう頼むとき、UI は UI エリアに、API ルートは API エリアに、招待データはデータ層に格納されるようにしてほしい――その機能だけのために新しいフォルダやパターンを発明してほしくない。そうした退屈な一貫性が将来の編集コストを低く保ちます。
生成コードは同じことをする方法が多いほど高コストになります。退屈なアーキテクチャのルールは単純です:最初の構築が少し地味でも、次の変更が予測可能になること。
次の問いに素早く答えられることが理想です:
一つの平凡な構造を選び、どこでもそれに従うこと。ツールやチームメイトが凝ったパターンを提案したら、実際の痛みを取り除かない限りデフォルトで「ノー」と答えます。
長期的に持つ実践的なデフォルト:
新しい開発者がリポジトリを開いて「サブスクリプションをキャンセルする」ボタンを追加する必要があると想像してください。彼らはカスタムアーキテクチャを学ぶ必要はありません。明確な機能領域、UI コンポーネント、単一の API クライアントの場所、単一のデータアクセス経路が見つかるべきです。
このルールは Koder.ai のようなビブコーディングツールと特に相性がいい:高速に生成できても、毎回同じ退屈な境界に出力を誘導すれば保守が効きます。
生成されたコードは急速に増えがちです。保守性を保つ最も安全な方法は、誰でもどこに変更が属するか推測できる退屈なフォルダマップです。
多くの Web アプリに適する小さなトップレベルのレイアウト例:
app/ スクリーン、ルーティング、ページレベルの状態components/ 再利用可能な UI 部品features/ 機能ごとのフォルダ(billing, projects, settings など)api/ API クライアントコードとリクエストヘルパーserver/ バックエンドのハンドラ、サービス、ビジネスルールこれで境界は明白になります:UI は app/ と components/、API 呼び出しは api/、バックエンドロジックは server/ に集まります。
データアクセスも退屈に保ちましょう。SQL クエリやリポジトリコードはバックエンドの近くに置き、UI ファイルに散らさないこと。Go + PostgreSQL の場合、シンプルなルールは:HTTP ハンドラがサービスを呼び、サービスがリポジトリを呼び、リポジトリが DB と話す、です。
共有型やユーティリティには明確な場所を与えつつ小さく保つ:共通の型は types/(DTO、列挙、共有インターフェース)、小さなヘルパーは utils/(日付フォーマット、簡単なバリデータ)に入れる。もし utils/ が第二のアプリのようになり始めたら、そのコードはむしろ機能フォルダに置くべきです。
生成されたフォルダは置き換え可能と見なすべきです。
generated/(または gen/)に置き、直接編集を避ける。features/ や server/ に置き、再生成で上書きされないようにする。例:Koder.ai が API クライアントを生成するなら generated/api/ に置き、api/ に薄いラッパーを書いて再試行やログ、分かりやすいエラーメッセージを追加し、生成ファイルには触らないようにします。
生成コードは簡単に増えます。名前付けが、1か月後に読みやすさを保ちます。
一つの命名スタイルを選び混ぜない:
kebab-case(例:user-profile-card.tsx, billing-settings)PascalCase(例:UserProfileCard)camelCase(例:getUserProfile)SCREAMING_SNAKE_CASE(例:MAX_RETRY_COUNT)「役割」で名付ける、現在の実装方法で名付けない。user-repository.ts は役割名。postgres-user-repository.ts は実装の詳細で、将来変わり得る。複数の実装が本当にある場合にのみ実装サフィックスを使う。
misc や helpers、巨大な utils のようなジャンクドロワーは避ける。関数が一つの機能でしか使われないならその機能の近くに置く。共有されるなら機能を説明する名前(date-format.ts、money-format.ts、id-generator.ts)を付け、モジュールは小さく保つ。
ルート、ハンドラ、コンポーネントがパターンに従うと検索なしで見つけられます:
routes/users.ts、パスは /users/:userId のようにhandlers/users.get.ts, handlers/users.update.ts のようにservices/user-profile-service.tsrepositories/user-repository.tscomponents/user/UserProfileCard.tsxKoder.ai(または任意のジェネレータ)を使う場合、これらのルールをプロンプトに入れて生成と編集の間で一貫させましょう。ファイル名を予測できれば将来の変更コストは安くなります。
生成コードは初日は見栄えが良くても30日後に苦労を生むことがあります。コードが明白になるデフォルトを選び、多少冗長でも読みやすさを優先します。
まず魔法を減らす。動的ロード、リフレクション風トリック、自動配線は必須でない限り避ける。これらは要素の発生源を隠し、デバッグやリファクタを遅らせます。
明示的なインポートと明確な依存関係を優先する。ファイルが何かを必要とするなら直接インポートする。モジュールの配線が必要なら、1つの目に見える場所(例えば単一の構成ファイル)で行う。何が先に動くか推測させないこと。
設定は退屈で中央集権的に保つ。環境変数、機能フラグ、アプリ全体の設定は一つのモジュールに同じ命名規約でまとめる。便利さから設定をランダムなファイルに散らすのは避ける。
一貫性を保つ経験則:
エラーハンドリングは賢さが最も害する領域です。パターンを一つに絞りどこでも同じにする:データ層は構造化されたエラーを返し、それを一箇所で HTTP レスポンスにマッピングし、UI 境界でユーザー向けメッセージに翻訳する。ファイルによって三種類のエラーを投げ分けない。
Koder.ai でアプリを生成する場合、最初にこれらのデフォルトを求めておくと良い:明示的なモジュール配線、集中化された設定、一貫したエラーパターン。
UI、API、データの明確なラインは変更の影響範囲を限定します。多くの難しいバグは一つの層が別の層の仕事を始めると発生します。
UI(多くは React)は画面を描画し UI 固有の状態を管理する場所として扱いましょう:どのタブが開いているか、フォームエラー、読み込みスピナー、基本的な入力処理など。
サーバ状態は分離する:取得したリスト、キャッシュされたプロファイル、バックエンドと一致すべきもの。UI コンポーネントが合計を計算したり複雑な検証を行ったり権限を判断し始めると、ロジックが画面に散らばり変更が高コストになります。
API 層は予測可能に保つべきです。HTTP リクエストをビジネスコード呼び出しに翻訳し、結果を安定したリクエスト/レスポンス形に戻す役目です。データベースモデルをそのままワイヤーに流さないように。
シンプルな経路:
SQL(または ORM)のロジックはリポジトリ境界の背後に置き、アプリの他部分が「どう保存されているか」を知らないようにします。Go + PostgreSQL では、通常 UserRepo や InvoiceRepo のようなリポジトリを用意し、GetByID、ListByAccount、Save のような小さなメソッドを持たせます。
具体例:割引コードを追加する場合。UI はフィールドを表示し更新後の価格を出す。API は code を受け {total, discount} を返す。サービスがコードの有効性と割引の重複ルールを決め、リポジトリが必要な行を取得・永続化します。
生成されたアプリは短時間で「できた」ように見えますが、構造が後で変更コストを左右します。先に退屈なルールを決め、その後に必要十分なコードを生成して検証します。
短い計画パスから始めます。Koder.ai を使うなら Planning Mode でフォルダマップといくつかの命名ルールを書いておくと良いです。
次にこの順序で進めます:
ui/, api/, data/, features/)と数個の命名ルールを選ぶ。CONVENTIONS.md を追加し契約のように扱う。コードベースが大きくなると命名やフォルダパターンの変更は高コストになる。現実チェック:新しい人が「編集コンタクトをどこに置くか」を尋ねずに推測できないなら、まだ退屈すぎるアーキテクチャではありません。
単純な CRM を想像してください:コンタクト一覧ページとコンタクト編集フォームがある。最初のバージョンを素早く作り、一週間後に「タグ」を追加する必要が出たとします。
アプリを UI、API、データの三つの退屈な箱として扱います。各箱に明確で文字通りの名前を付ければ「タグ」の変更は小さく済みます。
きれいなレイアウトの例:
web/src/pages/ContactsPage.tsx と web/src/components/ContactForm.tsxserver/internal/http/contacts_handlers.goserver/internal/service/contacts_service.goserver/internal/repo/contacts_repo.goserver/migrations/こうすれば「タグ」は予測可能になります。スキーマを更新(contact_tags テーブルや tags カラム追加)し、各レイヤーを順に触るだけ:リポジトリがタグを読み書きし、サービスが検証し、ハンドラがフィールドを公開し、UI が表示・編集する。SQL をハンドラに忍び込ませたり、React にビジネスルールを入れたりしないこと。
テストとフィクスチャも小さくコード近くに置く:
server/internal/service/contacts_service_test.go(例:「タグ名は同一のコンタクト内で一意である」等のルール)server/internal/repo/testdata/(最小限のフィクスチャ)web/src/components/__tests__/ContactForm.test.tsx(フォーム挙動)Koder.ai で生成した場合でも、エクスポート後に同じルールが当てはまります:フォルダを退屈に保ち、名前を文字通りにしておけば編集が考古学的作業になりません。
生成コードは初日はきれいに見えても後で高コストになることがあります。主な原因は「一貫性の欠如」です。
高コストな習慣の一つは、毎回ジェネレータに構造を発明させることです。機能ごとに独自のフォルダ、命名スタイル、ヘルパーが入り混じり、同じことをする方法が三通りになることがあります。一つのパターンを選び、それを書き留め、新しいパターンは意図的な変更として扱いましょう。
別の罠は層の混在です。UI コンポーネントが DB に直接話す、あるいは API ハンドラが SQL を組み立てると、変更がアプリ全体に跨る危険な編集になります。境界を保つ:UI は API を呼び、API はサービスを呼び、サービスはデータアクセスを呼ぶ。
早すぎる汎用抽象化もコストを増やします。普遍的な BaseService や Repository フレームワークはかっこよく感じますが、初期の抽象化は推測であり、現実が変わると自分の作ったフレームワークと格闘することになります。
頻繁なリネームや再編成も静かな負債です。ファイルが毎週動くなら人はレイアウトを信頼しなくなり、気軽な修正がランダムな場所に入ります。まずフォルダマップを安定させ、その後計画的にリファクタしてください。
最後に、実際にユーザーがいない「プラットフォームコード」は注意深く。共有ライブラリや自作ツールは繰り返しの需要があるときにだけ価値を発揮します。それまでは直接的なデフォルトを維持しましょう。
新しい人がリポジトリを開いたとき、素早く答えられるべき質問:"これをどこに追加する?"
プロジェクトを同僚(または将来の自分)に渡し、「サインアップフォームにフィールドを一つ追加して」と頼んでみてください。すぐに適切な場所が見つからなければ構造は機能していません。
三つの明確な置き場所を確認:
プラットフォームがサポートするならロールバックパスを保持しましょう。構造を試す時にスナップショットとロールバックは特に有用です。
保守性が最も速く改善するのは、スタイルを議論するのをやめ、いくつかの決定をしてそれを守ることです。
どこにファイルを置くか、どう名付けるか、エラーと設定をどう扱うかといった日々の迷いを取り除く小さな規約を書き留めてください。一分で読めるくらい短く保ちます。
それから一回のクリーンアップでルールに合わせ、毎週の再編成をやめること。頻繁な再編成は見た目がよくても次の変更を遅くします。
もし Koder.ai(koder.ai)で構築しているなら、これらの規約を起点プロンプトとして保存しておくと各生成が同じ構造に落ち着きます。ツールは速く動けますが、退屈な境界がコードを変更しやすく保つのです。