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

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