単一のAI生成コードベースが、共有ロジック・一貫したデータモデル・安全なリリースでWeb、モバイル、APIをどのように支えられるかを解説します。

「1つのコードベース」はめったにどこでも同じUIが動くことを意味しません。実務では、通常は1つのリポジトリと1セットの共有ルールを指し、配信面(Webアプリ、モバイルアプリ、API)は別々でも、基になるビジネス判断を共有します。
有用な考え方は「決して矛盾してはいけない部分を共有する」ことです:
一方で、UI層を丸ごと共有することは通常推奨されません。Webとモバイルではナビゲーション、アクセシビリティ、パフォーマンス要件、プラットフォーム機能が異なります。場合によってはUI共有が有利ですが、それが「単一コードベース」の定義ではありません。
AI生成コードは以下を劇的に高速化します:
しかしAIが自動的に一貫したアーキテクチャを作るわけではありません。境界が明確でないと、アプリ間でロジックを重複させたり、関心事を混ぜたり(UIが直接DBコードを呼ぶなど)、複数箇所で「ほぼ同じ」バリデーションを生成しがちです。レバレッジは、まず構造を定め、その後にAIで反復部分を埋めることにあります。
AI支援の単一コードベースが成功すると次が得られます:
単一コードベースが機能するのは、何を達成すべきか、そして何を標準化しないかが明確な場合だけです。Web、モバイル、APIは同じビジネスルールを共有しても、異なる利用者と利用パターンに応えます。
多くのプロダクトには少なくとも3つの「フロントドア」があります:
目標は挙動(ルール、権限、計算)の一貫性であり、同一の体験ではありません。
よくある失敗は「単一コードベース=単一UI」とみなすことです。これは多くの場合、Web風のモバイルアプリやモバイル風のWebアプリという妥協を生み、どちらのユーザーも不満を感じる結果になります。
代わりに目指すべきは:
オフライン対応: モバイルはネットワークなしで読み取り(場合によっては書き込み)する必要があります。ローカルストレージ、同期戦略、競合解決、明確な「真実の源」ルールが必要です。
パフォーマンス: WebはバンドルサイズとTime-to-Interactiveを気にし、モバイルは起動時間とネットワーク効率を、APIはレイテンシとスループットを重視します。共有コードが全てのクライアントに不要なモジュールを送りつけるべきではありません。
セキュリティとコンプライアンス: 認証、認可、監査ログ、暗号化、データ保持を全ての表面で一貫させる必要があります。規制のある領域で運用するなら、ログ、同意、最小権限などの要件を最初から組み込み、後付けにしないでください。
単一コードベースが最も機能するのは、責任が厳格に分かれた明確なレイヤーで整理されたときです。その構造はAI生成コードのレビュー、テスト、差し替えを容易にします。
多くのチームが収束する基本形は次の通りです:
Clients (Web / Mobile / Partners)
↓
API Layer
↓
Domain Layer
↓
Data Sources (DB / Cache / External APIs)
要点は:ユーザーインターフェースと伝送(トランスポート)に関する詳細は周辺に置き、ビジネスルールは中心に置くことです。
「共有可能なコア」はどこでも同じ振る舞いをするべきものです:
AIが新機能を生成する際のベストケースは:ドメインルールを一度更新すれば、すべてのクライアントが自動的に恩恵を受けることです。
共有抽象化に押し込むのが高コスト(またはリスク)なコードもあります:
実践的なルール:ユーザーが見える部分やOSが壊せる部分はアプリ固有にする。ビジネス判断はドメインに置く。
共有ドメイン層は「最高に退屈であるべき」部分です:予測可能でテストしやすく、どこでも再利用できる。AIでシステムを生成するなら、この層をプロジェクトの基準として据えてください—Web画面、モバイルフロー、APIエンドポイントが同じルールを反映するようにします。
製品のコア概念をエンティティ(時間を通じて識別を持つもの、例:Account、Order、Subscription)と値オブジェクト(値によって定義されるもの、例:Money、EmailAddress、DateRange)として定義します。振る舞いはユースケース(アプリケーションサービス)として捉えます:Create order、Cancel subscription、Change email。
この構造はドメインを非専門家にも理解しやすくします:名詞は存在するものを、動詞はシステムが行うことを表します。
ビジネスロジックはボタンタップ、Webフォーム送信、APIリクエストのどれから呼ばれているかを知らないべきです。実務的には:
AI生成コードではこの分離が失われやすいので、境界が破られたらリファクタの対象としてください。
バリデーションはプロダクトが最も分裂しやすい領域です:Webは許容してAPIが拒否する、あるいはモバイルが別の検証をする。バリデーションはドメイン層(または共有バリデーションモジュール)に置き、すべての表面が同じルールを強制するようにしてください。
例:
EmailAddress はフォーマットを一度だけ検証し、Web/モバイル/APIで再利用Money はマイナス合計を防ぐ(発生源に関係なく)これがうまくいくと、APIレイヤーは翻訳者になり、Web/モバイルはプレゼンターになり、ドメイン層が唯一の真実の源になります。
APIレイヤーはシステムの“公開顔”であり、AI生成の単一コードベースでは他をアンカーする役割を担うべきです。契約が明確なら、Webアプリ、モバイルアプリ、内部サービスは同じ真実に基づいて生成・検証できます。
ハンドラやUIワイヤリングを生成する前に契約を定義します:
/users、/orders/{id})、予測可能なフィルタやソート。\n- エラー:安定したエラー形(code、message、details)とHTTPステータスの使い分けのドキュメント。\n- ページネーション:一つのアプローチを選ぶ(カーソルベースは進化させやすい)。\n- バージョニング:早期に決める(/v1/...のパスかヘッダベースか)と非推奨ルールを文書化する。正準アーティファクトとして OpenAPI(またはGraphQL SDL)を使い、そこから生成します:
AI生成は大量のコードを高速に作れますが、スキーマがそれを整合させます。
いくつかの不変ルールを決めてください:
snake_case か camelCase のどちらかに統一し混在させない。JSONと生成型の一致を保つ。\n- ステータスコード:成功は200/201/204、バリデーションは400、認証は401/403、競合は409など。\n- 冪等性:支払い・注文作成などリスクのある操作には Idempotency-Key を要求し、リトライ挙動を定義する。API契約をプロダクトとして扱ってください。契約が安定すれば、生成・テスト・デプロイが容易になります。
Webアプリは共有ビジネスロジックから大きな恩恵を受けますが、UI関心事と絡めてしまうと苦しみます。共有ドメイン層を「ヘッドレスエンジン」として扱うのが鍵です:ルールやバリデーション、ワークフローを知るが、コンポーネントやルートやブラウザAPIについては何も知らない。
**SSR(サーバーサイドレンダリング)**を使う場合、共有コードはサーバー上で安全に動く必要があります:直接 window、document、ブラウザストレージを参照してはいけません。これは良い強制力になります:ブラウザ依存の振る舞いは薄いウェブアダプタ層に置くべきです。
**CSR(クライアントサイドレンダリング)**では自由度が高いですが、同じ規律が必要です。CSRのみのプロジェクトは、すべてがブラウザで動くがゆえにドメインモジュールにUIコードを誤ってインポートしやすく、後でSSRやエッジレンダリング、Node実行のテストを追加すると問題が出ます。
実践ルール:共有モジュールは決定論的で環境に依存しないこと。クッキー、localStorage、URLに触るものはWeb層に置く。
共有ロジックはドメイン状態(注文合計、適格性、派生フラグ)を平易なオブジェクトと純粋関数で公開するべきです。WebアプリはUI状態(読み込みスピナー、フォームのフォーカス、楽観的アニメーション、モーダルの表示)を管理します。
これにより、React/Vueの状態管理を変更してもビジネスルールを書き換える必要がなくなります。
Web層が扱うべきもの:
localStorage、キャッシュ)Webアプリはユーザー操作をドメインコマンドに翻訳し、ドメインの結果をアクセシブルな画面に翻訳するアダプタと考えてください。
モバイルアプリは共有ドメイン層から最も恩恵を受けます:価格、適格性、バリデーション、ワークフローのルールはWebやAPIと同じに振る舞うべきです。モバイルUIはその共有ロジックをラップする「シェル」として、タッチ向け・断続接続向け・デバイス機能向けに最適化します。
共有ビジネスロジックがあっても、モバイルに特有のパターンは多く、1:1でWebにマップされることは稀です:
実際のモバイル利用を想定するなら、オフラインを前提に設計します:
Web、モバイル、APIがそれぞれ独自のデータ形やセキュリティルールを発明すると単一コードベースはすぐに破綻します。モデル、認証、認可を製品決定として一元化し、1回だけコード化してください。
モデルがどこに定義されるかを1つ決め、他はそこから派生させます。選択肢:
重要なのはツールではなく一貫性です。OrderStatus が片方のクライアントでは5値、別のクライアントでは6値なら、AI生成コードは嬉々としてコンパイルしバグを出荷します。
認証はユーザーにとって同じ体験に感じられるべきですが、各表面で仕組みは異なります:
単一のフローを設計する:ログイン → 短命のアクセストークン → 必要時リフレッシュ → ログアウトでサーバー側状態を無効化。モバイルでは秘密情報をKeychain/Keystoreに保存し、WebではhttpOnlyクッキーを優先してください。
権限は一度定義し(できればビジネスルールに近い場所)、どこでも適用してください。
canApproveInvoice(user, invoice))。\n- APIで強制して実際のセキュリティを担保。\n- UIではミラーして表示/無効化するのみ(データ保護として頼らない)。これにより「モバイルでは動くがWebでは動かない」といったドリフトを防ぎ、AI生成の契約をテスト可能にします。
統一されたコードベースが統一のままでいるには、ビルドとリリースが予測可能であることが必要です。チームがAPI、Web、モバイルを独立して出荷でき、ロジックを分岐させたり環境ごとに特例を作したりしないことが目標です。
モノレポ(1リポジトリに複数のパッケージ/アプリ)は単一コードベースでは有利なことが多いです。共有ドメインロジック、API契約、UIクライアントが一緒に進化するため、1つのPRで契約と消費側を同時に更新できます。
マルチレポでも統一は可能ですが、調整コストがかかります:共有パッケージのバージョニング、アーティファクト公開、破壊的変更の同期など。組織の境界やセキュリティ要件、スケールが理由でない限りはモノレポを検討してください。
各サーフェスを別のビルドターゲットとして扱います:
ビルド出力は明示的かつ再現可能に(ロックファイル、固定ツールチェーン、決定論的ビルド)。
典型的なパイプライン:lint → typecheck → ユニットテスト → コントラクトテスト → ビルド → セキュリティスキャン → デプロイ。
設定はコードから分離:環境変数とシークレットはCI/CDとシークレットマネージャに置き、リポジトリに置かないでください。dev/stage/prodのオーバーレイを使い、同じアーティファクトを環境間でプロモートできるようにします(特にAPIとWebのランタイムで有用)。
Web、モバイル、APIが同じコードベースから出荷されると、テストは「追加のチェックリスト」ではなく、変更が3つのプロダクトを壊すのを防ぐための仕組みになります。目標は単純です:可能な限り安価に問題を検出し、リスクの高い変更をユーザーに届く前にブロックすること。
まずは共有ドメイン(ビジネスロジック)に投資してください。再利用度が高く、インフラ無しでテストしやすいからです。
この構造は自信の大部分を共有ロジックに置きつつ、レイヤー接合部の配線ミスを捕捉します。
モノレポでもAPIが型的には通るがユーザー体験を壊す変更をするのは簡単です。コントラクトテストで静かなドリフトを防ぎます。
テストだけでなく、それを取り囲むルールも重要です。
これらのゲートがあれば、AI支援の変更は頻繁でも脆弱になりません。
AIは単一コードベースを加速できますが、「速いジュニアエンジニア」の扱いが必要です:ドラフト生成は得意だが、レビューなしでマージするのは危険。AIの価値は速度にあり、アーキテクチャ、契約、長期的一貫性の責任は人が持ちます。
AIを以下の「機械的に書く作業」の初版生成に使ってください:
良いルール:AIには「読みやすく/テストしやすい」コードを生成させ、ビジネスの意味を密かに変えるようなコードは生成させない。
AI出力は明示的ルールで制約すべきです:
AIが境界を破る近道を提案したら、たとえコンパイルしても拒否してください。
リスクは悪いコードだけでなく、追跡不能な意思決定にもあります。監査痕跡を残してください:
AIは繰り返し可能であるときに最も価値を発揮します:なぜ生成したかをチームが見られ、検証でき、要件が進化したら安全に再生成できること。
システムレベル(Web + API + Mobile)でAI支援開発を採用する場合、最も重要な機能は生産速度ではなく、出力を契約やレイヤリングと整合させ続ける能力です。
例えば Koder.ai はチャットインターフェースを通じてWeb、サーバー、モバイルアプリを構築できるプラットフォームで、実際にエクスポート可能なソースコードを生成します。この記事で述べたワークフローに役立つのは、API契約とドメインルールを定義してから、ReactベースのWeb画面、Go + PostgreSQLのバックエンド、Flutterのモバイルアプリを素早く反復できる点です。プランニングモード、スナップショット、ロールバックのような機能は「生成 → 検証 → プロモート」というリリース規律にマッチします。
単一コードベースは複製を減らせますが、常に「最善」ではありません。共有コードが不自然なUXを強いる、リリースを遅らせる、あるいはプラットフォーム差を隠すと、アーキテクチャの交渉に多くの時間を費やすことになります。
別コードベース(少なくともUI層を分ける)は次の場合に正当化されます:
単一コードベースに踏み切る前に問うべきこと:
警告サインが出るなら、実用的な代替は 共有ドメイン + API契約 を残し、Webとモバイルは別々のアプリ にすることです。共有コードはビジネスルールとバリデーションに集中させ、各クライアントがUXとプラットフォーム統合を担当します。
もし道を選ぶ助けが必要なら、/pricing を比較するか /blog で関連アーキテクチャパターンを参照してください。
通常は1つのリポジトリと1セットの共有ルールを意味し、同一のUIがどこでも動くという意味ではありません。
実務では、Web、モバイル、APIはドメイン層(ビジネスルール、バリデーション、ユースケース)や通常は共通のAPI契約を共有し、各プラットフォームは独自のUIやプラットフォーム統合を保持します。
決して矛盾してはいけない部分を共有してください:
UIコンポーネント、ナビゲーション、デバイス/ブラウザ固有の統合はプラットフォーム別にしてください。
AIはスキャフォールディングや繰り返し作業(CRUD、クライアント、テスト)を高速化しますが、適切な境界を自動で作るわけではありません。
意図しないままだとAI生成コードは:
AIは定義済みのレイヤーを埋めるために使い、レイヤー設計自体は人が決めてください。
シンプルで堅実なフローの例:
ビジネスルールを中央に置くことで、テストとAI生成の追加がレビューしやすくなります。
バリデーションは一箇所に置くことで乖離を防げます。
実用的なパターン:
EmailAddress や Money のような値オブジェクトは一度だけ検証するこれにより「Webは受け入れるがAPIは拒否する」といったドリフトを防止します。
OpenAPIやGraphQL SDLのような正準スキーマを使い、そこから生成すること:
さらにコントラクトテストを導入し、スキーマを壊す変更はCIで失敗させます。
オフラインをただのキャッシュ任せにするのではなく、明示的に設計します:
オフライン保存と同期ロジックはモバイルアプリ層に置き、ビジネスルールは共有ドメインに置きます。
概念上は一貫したフローを持ちつつ、表面(surface)ごとに実装を変えるのが良いです:
権限チェックは中央で定義(例:canApproveInvoice(user, invoice))し、APIで強制します。UIは表示/無効化のみに使用してください。
各サーフェスを共有パッケージを消費する別々のビルドターゲットとして扱います:
CI/CDでは lint → typecheck → ユニットテスト → コントラクトテスト → ビルド → セキュリティスキャン → デプロイ の流れを守り、シークレットはリポジトリ外に置きます。
AIは速いジュニアエンジニアのように扱い、ドラフト生成や反復作業を任せますが、アーキテクチャの決定や重要な契約は人が責任を持ちます。
守るべきガードレール:
AIが境界を破る出力をしたら、その生成物は却下してください。