🤖

Kiro で AWS AI-DLC を実践する

に公開

概要

AI を普段から補助的に使っているソフトウェアエンジニアにとって、次の壁は「補完は速いが、開発全体はあまり変わっていない」という点ではないでしょうか。

コード補完、テスト生成、ドキュメント下書きは速くなっても、要件整理、設計の合意、実装のレビュー、デプロイ判断のような重要な流れは、依然として人間主導のまま分断されがちです。

AWS が提唱する AI-DLC (AI-Driven Development Life Cycle) は、その分断を減らし、AI を開発ライフサイクル全体の協働者として扱うための考え方です。

この記事では、以下をまとめます。

  • AI-DLC の考え方
  • なぜ通常の AI-assisted development より踏み込んでいるのか
  • Kiro を前提に awslabs/aidlc-workflows を導入する手順
  • Workflow を使って具体的に開発を進める流れ
  • 生成される aidlc-docs の見方

なお、この記事では AI がすべてを自律的に決める運用は前提にしません。あくまで 人間が意思決定し、AI が計画と実行を加速する という立場で整理します。

AI-DLC とは何か

AI-DLC は、AI を単なる補助ツールではなく、計画を作り、必要な確認を求め、承認後に実装を進める主体 として開発プロセスに組み込む方法論です。

ポイントは 2 つあります。

  • 人間の監督を前提とした AI 主導の実行
  • 動的なチームコラボレーション

つまり、AI に作業を任せるのではなく、AI が提案し、人間が判断する というループを明示的に開発プロセスへ埋め込みます。

従来の開発との違いを雑にまとめると次のとおりです。

観点 典型的な AI 活用 AI-DLC
AI の役割 補完、生成、要約など個別作業の支援 計画、確認、実装、成果物生成を横断して支援
人の関わり方 必要に応じてレビュー 各フェーズで承認と方向付けを担う
開発の流れ 人が工程を管理し AI を都度呼ぶ AI が状況に応じて工程の深さと順序を提案
成果物 その場限りになりやすい リポジトリ内に文書化され継続利用しやすい

なぜソフトウェアエンジニアに適しているのか

AI を日常的に使っていると、次のような経験が増えます。

  • ちょっとした修正なのに、毎回プロンプトの前提を説明し直す
  • 生成コードは速いが、設計判断の根拠が薄い
  • セッションを跨ぐと文脈が切れる
  • 要件、設計、実装、テストのつながりが弱い

AI-DLC は、この問題を プロンプトの工夫 ではなく ワークフローの定義 で扱おうとします。

特に重要なのは、どの工程を実行するか各工程をどこまで深くやるか を固定しないことです。小さなバグ修正と、新機能開発や既存システムのモダナイゼーションでは、必要な工程が違います。AI-DLC はそこを前提にしています。

AI-DLC の全体像

AI-DLC は大きく InceptionConstructionOperations の 3 フェーズで考えます。

それぞれの役割は次のイメージです。

  • Inception: 何を作るか、なぜ必要か、どの粒度で進めるかを固める
  • Construction: 設計、実装、テストを進める
  • Operations: インフラ、デプロイ、運用上の観点を扱う

ただし、毎回すべてをフルで実行するわけではありません。AI-DLC が重視しているのは adaptive workflow です。つまり、課題の性質に応じて必要な工程だけを選び、必要な深さで実行します。

Human-in-the-loop のループ

AI-DLC の核は、AI が勝手に進めることではなく、承認ポイントを明示した協働ループです。

このループが各フェーズで繰り返されます。AWS の説明では、要件を詰める段階を Mob Elaboration、実装や設計を詰める段階を Mob Construction と表現しています。

AI-DLC の何が実務向きなのか

実務で使いやすいと感じる理由は、次の 3 点です。

1. One-size-fits-all を避ける

AI コーディングツールの中には、何をやるにも同じ手順を踏ませるものがあります。

しかし実際には、以下の作業で最適な流れは違います。

  • 小さな不具合修正
  • 既存システムのリファクタリング
  • 新機能の追加
  • インフラ移行

AI-DLC は、この差を前提にして 今の意図に対して必要なフェーズだけを選ぶ 方針です。

2. 工程ごとの深さを可変にする

軽微な API 修正に大規模な設計文書は不要です。一方で、複数サービスに影響する変更なら NFR や設計の議論を省くと危険です。

AI-DLC では、工程を実行するかどうか だけでなく、どこまで深くやるか も状況に応じて変えます。

3. 人の責任を薄めない

AI に全部任せると速そうに見えますが、あとでレビューコストや手戻りが増えやすくなります。

AI-DLC は、人間の責任を減らすのではなく、人間が判断すべき場所を明確にする 方向です。ここが、単なる自動化より現実的です。

Kiro と AI-DLC の関係

AI-DLC 自体は方法論であり、実際に動かすには各ツール向けのルールやステアリングが必要です。

今回使う awslabs/aidlc-workflows は、その実装をオープンソース化したものです。リポジトリには複数のツール向け設定がありますが、この記事では Kiro を前提にします。

Kiro では Steering Files を使って AI-DLC のワークフローを読み込ませます。ポイントは次の 2 つです。

  • .kiro/steering/ にコアワークフローを置く
  • .kiro/aws-aidlc-rule-details/ に詳細ルールを置く

Kiro IDE でも Kiro CLI でも考え方は同じです。README では、Kiro IDE は Vibe mode で使う想定とされていて、Spec mode へ誘導されても切り替えず進める案内があります。

Kiro で AI-DLC Workflow を導入する

ここでは、awslabs/aidlc-workflows のリリース ZIP を使う最短手順を示します。

1. Workflow を配置する

macOS / Linux では次のように配置できます。

mkdir -p .kiro/steering
cp -R ~/Downloads/aidlc-rules/aws-aidlc-rules .kiro/steering/
cp -R ~/Downloads/aidlc-rules/aws-aidlc-rule-details .kiro/

配置後のイメージは次のとおりです。

<project-root>/
├── .kiro/
│   ├── steering/
│   │   └── aws-aidlc-rules/
│   └── aws-aidlc-rule-details/
└── ...

2. 読み込みを確認する

Kiro CLI なら kiro-cli を起動して /context show を実行し、.kiro/steering/aws-aidlc-rules が見えているかを確認します。

3. 使い始める

README では、開発の開始時に AI-DLC を使って、 ... で意図を伝える使い方が案内されています。ここが重要で、単に「このコードを書いて」ではなく、意図、制約、期待する成果 を AI-DLC に渡します。

たとえば次のような入り方です。

AI-DLC を使って、シンプルな電卓 Web アプリを作成してください。
HTML、CSS、JavaScript はバニラのみを使用してください。
基本的な四則演算、小数入力、
キーボードショートカット、ゼロ除算のハンドリングに対応してください。
静的なフロントエンドプロジェクトとして完結させてください。

具体例: Kiro で電卓アプリを開発する

ここからは、awslabs/aidlc-workflows を Kiro で使って、実際にシンプルな電卓アプリを作成した例を扱います。

今回は、作成時に保存しておいた Kiro の Vibe モードの履歴スクリーンショットどおり、チャットの開始時点でかなり小さなスコープを渡しています。

まずは、AI-DLC ワークフロー開始直後の様子です。ルール詳細ファイルを読み込み、ワークスペース検出へ進んでいることが分かります。

最初の依頼は次の趣旨です。

  • AI-DLC を使ってシンプルな電卓アプリを作成する
  • グリーンフィールドで始める
  • 静的な Web アプリとして完結させる

実際の成果物は、ワークスペース直下に次の 3 ファイルとして生成されました。

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>電卓</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <main class="calculator" role="application" aria-label="電卓">
      <div
        class="display"
        data-testid="calculator-display"
        aria-live="polite"
        aria-atomic="true"
      >
        <span class="display-value" data-testid="calculator-display-value"
          >0</span
        >
      </div>
      <div class="buttons" role="group" aria-label="電卓ボタン">
        <button
          class="btn btn-function"
          data-testid="calculator-clear-button"
          data-action="clear"
          aria-label="クリア"
        >
          C
        </button>
        <button
          class="btn btn-function"
          data-testid="calculator-sign-button"
          data-action="sign"
          aria-label="符号反転"
        >
          ±
        </button>
        <button
          class="btn btn-function"
          data-testid="calculator-percent-button"
          data-action="percent"
          aria-label="パーセント"
          disabled
        >
          %
        </button>
        <button
          class="btn btn-operator"
          data-testid="calculator-divide-button"
          data-action="operator"
          data-value="/"
          aria-label="除算"
        >
          ÷
        </button>

        <button
          class="btn btn-number"
          data-testid="calculator-7-button"
          data-action="number"
          data-value="7"
        >
          7
        </button>
        <button
          class="btn btn-number"
          data-testid="calculator-8-button"
          data-action="number"
          data-value="8"
        >
          8
        </button>
        <button
          class="btn btn-number"
          data-testid="calculator-9-button"
          data-action="number"
          data-value="9"
        >
          9
        </button>
        <button
          class="btn btn-operator"
          data-testid="calculator-multiply-button"
          data-action="operator"
          data-value="*"
          aria-label="乗算"
        >
          ×
        </button>

        <button
          class="btn btn-number"
          data-testid="calculator-4-button"
          data-action="number"
          data-value="4"
        >
          4
        </button>
        <button
          class="btn btn-number"
          data-testid="calculator-5-button"
          data-action="number"
          data-value="5"
        >
          5
        </button>
        <button
          class="btn btn-number"
          data-testid="calculator-6-button"
          data-action="number"
          data-value="6"
        >
          6
        </button>
        <button
          class="btn btn-operator"
          data-testid="calculator-subtract-button"
          data-action="operator"
          data-value="-"
          aria-label="減算"
        >

        </button>

        <button
          class="btn btn-number"
          data-testid="calculator-1-button"
          data-action="number"
          data-value="1"
        >
          1
        </button>
        <button
          class="btn btn-number"
          data-testid="calculator-2-button"
          data-action="number"
          data-value="2"
        >
          2
        </button>
        <button
          class="btn btn-number"
          data-testid="calculator-3-button"
          data-action="number"
          data-value="3"
        >
          3
        </button>
        <button
          class="btn btn-operator"
          data-testid="calculator-add-button"
          data-action="operator"
          data-value="+"
          aria-label="加算"
        >
          +
        </button>

        <button
          class="btn btn-number btn-zero"
          data-testid="calculator-0-button"
          data-action="number"
          data-value="0"
        >
          0
        </button>
        <button
          class="btn btn-number"
          data-testid="calculator-decimal-button"
          data-action="decimal"
          aria-label="小数点"
        >
          .
        </button>
        <button
          class="btn btn-equals"
          data-testid="calculator-equals-button"
          data-action="equals"
          aria-label="等号"
        >
          =
        </button>
      </div>
    </main>
    <script src="script.js"></script>
  </body>
</html>
script.js
/**
 * 電卓アプリ - メインロジック
 * 基本的な四則演算をサポートするシンプルな電卓
 */
(function () {
  "use strict";

  // 状態管理
  const state = {
    currentValue: "0",
    previousValue: null,
    operator: null,
    waitingForOperand: false,
    hasDecimal: false,
  };

  // DOM 要素
  const displayValue = document.querySelector(
    '[data-testid="calculator-display-value"]',
  );
  const buttons = document.querySelector(".buttons");

  /**
   * ディスプレイを更新する
   */
  function updateDisplay() {
    let value = state.currentValue;

    // 長い数値の場合はフォントサイズを調整
    if (value.length > 9) {
      displayValue.style.fontSize = "2rem";
    } else if (value.length > 7) {
      displayValue.style.fontSize = "2.5rem";
    } else {
      displayValue.style.fontSize = "3.2rem";
    }

    displayValue.textContent = value;
  }

  /**
   * 数値を入力する
   * @param {string} digit - 入力する数字
   */
  function inputNumber(digit) {
    if (state.waitingForOperand) {
      state.currentValue = digit;
      state.waitingForOperand = false;
      state.hasDecimal = false;
    } else {
      if (state.currentValue === "0" && digit !== "0") {
        state.currentValue = digit;
      } else if (state.currentValue !== "0") {
        state.currentValue += digit;
      }
    }
    updateDisplay();
  }

  /**
   * 小数点を入力する
   */
  function inputDecimal() {
    if (state.waitingForOperand) {
      state.currentValue = "0.";
      state.waitingForOperand = false;
      state.hasDecimal = true;
      updateDisplay();
      return;
    }

    if (!state.hasDecimal) {
      state.currentValue += ".";
      state.hasDecimal = true;
      updateDisplay();
    }
  }

  /**
   * 演算を実行する
   * @param {number} a - 左オペランド
   * @param {number} b - 右オペランド
   * @param {string} op - 演算子
   * @returns {number|string} 計算結果またはエラーメッセージ
   */
  function calculate(a, b, op) {
    switch (op) {
      case "+":
        return a + b;
      case "-":
        return a - b;
      case "*":
        return a * b;
      case "/":
        if (b === 0) {
          return "エラー";
        }
        return a / b;
      default:
        return b;
    }
  }

  /**
   * 演算子を設定する
   * @param {string} nextOperator - 次の演算子
   */
  function handleOperator(nextOperator) {
    var current = parseFloat(state.currentValue);

    // アクティブな演算子ボタンのスタイルをリセット
    document.querySelectorAll(".btn-operator").forEach(function (btn) {
      btn.classList.remove("active");
    });

    if (state.operator && !state.waitingForOperand) {
      var result = calculate(state.previousValue, current, state.operator);

      if (result === "エラー") {
        state.currentValue = "エラー";
        state.previousValue = null;
        state.operator = null;
        state.waitingForOperand = true;
        state.hasDecimal = false;
        updateDisplay();
        return;
      }

      // 浮動小数点の丸め処理
      result = Math.round(result * 1e10) / 1e10;
      state.currentValue = String(result);
      state.previousValue = result;
    } else {
      state.previousValue = current;
    }

    state.operator = nextOperator;
    state.waitingForOperand = true;
    state.hasDecimal = false;

    // アクティブな演算子ボタンをハイライト
    var activeBtn = document.querySelector(
      '[data-value="' + nextOperator + '"]',
    );
    if (activeBtn) {
      activeBtn.classList.add("active");
    }

    updateDisplay();
  }

  /**
   * 等号を処理する
   */
  function handleEquals() {
    if (state.operator === null) {
      return;
    }

    var current = parseFloat(state.currentValue);
    var result = calculate(state.previousValue, current, state.operator);

    // アクティブな演算子ボタンのスタイルをリセット
    document.querySelectorAll(".btn-operator").forEach(function (btn) {
      btn.classList.remove("active");
    });

    if (result === "エラー") {
      state.currentValue = "エラー";
      state.previousValue = null;
      state.operator = null;
      state.waitingForOperand = true;
      state.hasDecimal = false;
      updateDisplay();
      return;
    }

    // 浮動小数点の丸め処理
    result = Math.round(result * 1e10) / 1e10;
    state.currentValue = String(result);
    state.previousValue = null;
    state.operator = null;
    state.waitingForOperand = true;
    state.hasDecimal = state.currentValue.includes(".");
    updateDisplay();
  }

  /**
   * クリアする
   */
  function handleClear() {
    state.currentValue = "0";
    state.previousValue = null;
    state.operator = null;
    state.waitingForOperand = false;
    state.hasDecimal = false;

    // アクティブな演算子ボタンのスタイルをリセット
    document.querySelectorAll(".btn-operator").forEach(function (btn) {
      btn.classList.remove("active");
    });

    updateDisplay();
  }

  /**
   * 符号を反転する
   */
  function handleSign() {
    if (state.currentValue === "0" || state.currentValue === "エラー") {
      return;
    }

    if (state.currentValue.startsWith("-")) {
      state.currentValue = state.currentValue.slice(1);
    } else {
      state.currentValue = "-" + state.currentValue;
    }
    updateDisplay();
  }

  /**
   * ボタンクリックイベントを処理する
   * @param {Event} event - クリックイベント
   */
  function handleButtonClick(event) {
    var target = event.target;

    if (!target.matches(".btn")) {
      return;
    }

    var action = target.dataset.action;
    var value = target.dataset.value;

    // エラー状態の場合、クリア以外は無視
    if (state.currentValue === "エラー" && action !== "clear") {
      return;
    }

    switch (action) {
      case "number":
        inputNumber(value);
        break;
      case "decimal":
        inputDecimal();
        break;
      case "operator":
        handleOperator(value);
        break;
      case "equals":
        handleEquals();
        break;
      case "clear":
        handleClear();
        break;
      case "sign":
        handleSign();
        break;
    }
  }

  /**
   * キーボードイベントを処理する
   * @param {KeyboardEvent} event - キーボードイベント
   */
  function handleKeyboard(event) {
    var key = event.key;

    // エラー状態の場合、Escape 以外は無視
    if (state.currentValue === "エラー" && key !== "Escape") {
      return;
    }

    // 数字キー
    if (key >= "0" && key <= "9") {
      event.preventDefault();
      inputNumber(key);
      return;
    }

    switch (key) {
      case ".":
        event.preventDefault();
        inputDecimal();
        break;
      case "+":
        event.preventDefault();
        handleOperator("+");
        break;
      case "-":
        event.preventDefault();
        handleOperator("-");
        break;
      case "*":
        event.preventDefault();
        handleOperator("*");
        break;
      case "/":
        event.preventDefault();
        handleOperator("/");
        break;
      case "Enter":
      case "=":
        event.preventDefault();
        handleEquals();
        break;
      case "Escape":
      case "c":
      case "C":
        event.preventDefault();
        handleClear();
        break;
      case "Backspace":
        event.preventDefault();
        if (!state.waitingForOperand && state.currentValue.length > 1) {
          state.currentValue = state.currentValue.slice(0, -1);
          state.hasDecimal = state.currentValue.includes(".");
          updateDisplay();
        } else if (!state.waitingForOperand) {
          state.currentValue = "0";
          state.hasDecimal = false;
          updateDisplay();
        }
        break;
    }
  }

  // イベントリスナーの登録
  buttons.addEventListener("click", handleButtonClick);
  document.addEventListener("keydown", handleKeyboard);

  // 初期表示
  updateDisplay();
})();
style.css
/* 電卓アプリ - iOS/Windows 電卓風デザイン */

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background-color: #222;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.calculator {
  width: 320px;
  background-color: #000;
  border-radius: 20px;
  padding: 20px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
}

/* ディスプレイ */
.display {
  background-color: #000;
  padding: 20px 16px;
  text-align: right;
  min-height: 100px;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
}

.display-value {
  color: #fff;
  font-size: 3.2rem;
  font-weight: 300;
  line-height: 1;
  word-break: break-all;
  overflow: hidden;
}

/* ボタングリッド */
.buttons {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}

/* ボタン共通 */
.btn {
  width: 100%;
  aspect-ratio: 1;
  border: none;
  border-radius: 50%;
  font-size: 1.5rem;
  font-weight: 400;
  cursor: pointer;
  transition:
    opacity 0.1s ease,
    transform 0.05s ease;
  outline: none;
}

.btn:hover {
  opacity: 0.85;
}

.btn:active {
  transform: scale(0.95);
}

.btn:focus-visible {
  box-shadow:
    0 0 0 3px #fff,
    0 0 0 5px #007aff;
}

/* 数字ボタン */
.btn-number {
  background-color: #333;
  color: #fff;
}

.btn-number:hover {
  background-color: #555;
}

/* 0 ボタン(横長) */
.btn-zero {
  grid-column: span 2;
  border-radius: 40px;
  aspect-ratio: auto;
  padding: 0 28px;
  text-align: left;
}

/* 機能ボタン(C, ±, %) */
.btn-function {
  background-color: #a5a5a5;
  color: #000;
}

.btn-function:hover {
  background-color: #c8c8c8;
}

.btn-function:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* 演算子ボタン */
.btn-operator {
  background-color: #ff9f0a;
  color: #fff;
}

.btn-operator:hover {
  background-color: #ffb340;
}

.btn-operator.active {
  background-color: #fff;
  color: #ff9f0a;
}

/* 等号ボタン */
.btn-equals {
  background-color: #ff9f0a;
  color: #fff;
}

.btn-equals:hover {
  background-color: #ffb340;
}

Kiro への最初の依頼

Kiro では次のように依頼すると、AI-DLC の流れに乗せやすくなります。

AI-DLC を使ってシンプルな電卓アプリを作成します。

今回のスクリーンショットでも、Kiro はいきなり HTML を書き始めるのではなく、まずルール詳細を読み込み、ワークスペースを確認し、.kiro しか存在しないグリーンフィールドだと判断してから aidlc-state.mdaudit.md を作っています。

ここで見ておきたいのは、AI-DLC が まず状況把握をしてから進める ことです。小さいアプリでもこの挙動が見えるのは、実務上かなり重要です。

要件分析の段階では、いきなり実装に進まず、対象プラットフォーム、使用技術、機能範囲、UI 方針などを質問として切り出して確認していました。

AI-DLC がどう進めるか

この例では、おおむね次のような流れになります。

実際の execution-plan.md でも、Inception では Requirements AnalysisWorkflow Planning が完了し、Construction では Code GenerationBuild and Test のみが実行対象になっています。逆に、アプリケーション設計、NFR 設計、インフラ設計はスキップされました。

これは、今回の題材が 単一コンポーネントの静的 Web アプリ で、複雑な設計ドキュメントを増やす必要がなかったからです。AI-DLC の 必要な工程だけ通す という性質がよく出ています。

コード生成に入る前には、生成対象ファイルとステップを明示した計画を提示し、レビューを要求していました。ここでも、AI が勝手に突っ走るのではなく、承認を挟んでいることが分かります。

生成される成果物

AI-DLC Workflow を使うと、成果物は aidlc-docs/ に蓄積されます。

今回の電卓アプリでは、概ね次のような構成になりました。

aidlc-docs/
├── aidlc-state.md
├── inception/
│   ├── plans/
│   ├── requirements/
│   └── audit/
├── construction/
│   ├── code-generation/
│   └── build-and-test/
└── operations/

重要なのは、AI が何を考えてその実装に至ったか を後から追いやすいことです。今回も Kiro の最終メッセージでは、ワークスペースルートに index.htmlstyle.cssscript.js を置き、aidlc-docs/ には要件定義、実行計画、コード生成関連文書、ビルド&テスト手順を出力したことが確認できます。

完了時点のサマリーも残っていて、生成されたファイル、実装済み機能、ドキュメント出力が一覧できました。

普段の AI チャットだけだと、要件と設計の文脈は会話に埋もれます。AI-DLC では、少なくとも次の追跡がしやすくなります。

  • なぜその工程を選んだのか
  • どの要件からその設計になったのか
  • どの前提でそのコードやテストを書いたのか

Execution Plan で確認したいこと

最初に出てくる execution-plan.md は特に重要です。ここで最低限、次を見ます。

  • どのフェーズが実行対象になっているか
  • どの工程がスキップされているか
  • MVP として必要十分な深さか
  • セキュリティや NFR が早い段階で消えていないか

たとえば今回の電卓アプリなら、軽量な実装でも次は確認したいところです。

  • 本当に静的ファイルだけで完結できるか
  • 四則演算と小数計算だけにスコープが絞られているか
  • ゼロ除算の扱いが定義されているか
  • キーボード操作や ARIA の要件が落ちていないか

ここを見ずに承認すると、あとで「速く作れたが運用できない」状態になりやすいです。

Construction フェーズでの見方

Construction に入ると、Kiro は設計文書とコード生成を進めます。ここで大事なのは、AI が作った実装を眺めることより、設計上の判断が自分たちの現場に合っているか を見ることです。

たとえば今回なら以下を確認します。

  • index.html に適切な ARIA ラベルと data-testid が入っているか
  • script.js が四則演算、小数入力、連続計算、ゼロ除算を扱えているか
  • キーボード操作が意図どおりか
  • style.css が iOS / Windows 風の見やすい UI になっているか

AI-DLC の利点は、これらの判断材料が設計文書として先に出る点です。コードだけをレビューするより、修正コストが低くなります。

Operations フェーズでの見方

今回のような静的アプリでは Operations の重みは軽くなりますが、それでも確認する価値はあります。

今回の build-and-test-summary.md では、次の点が明示されていました。

  • ビルドツール不要で、index.htmlstyle.cssscript.js が成果物
  • ユニットテストと統合テストの手動テスト観点が整理されている
  • 静的ファイルホスティングで公開可能

つまり、この規模のアプリでは Operations を重く設計するより、どこへ置けば配信できるかどこまでテスト観点を残すか を整理するほうが現実的です。

AI-DLC では、この運用観点もワークフローの一部として扱えます。ここが、コード生成止まりの運用との差です。

実務で使うときの進め方

普段から AI を使っているエンジニアほど、AI-DLC は次のように使うと噛み合いやすいと思います。

1. 最初の入力を雑にしすぎない

AI-DLC を使って、 ... の後に入れるべきなのは、実装指示だけではありません。

  • 何を達成したいか
  • 何を今回はやらないか
  • 既存資産があるか
  • どこにリスクがあるか

この情報が薄いと、AI-DLC の適応力も活かしにくくなります。

2. 承認ポイントを省略しない

速く作りたくなるほど、計画レビューを飛ばしたくなります。ただ、AI-DLC はそこを飛ばさない前提の方法論です。

特に次は飛ばさないほうが安全です。

  • Inception の execution plan
  • Application design
  • NFR に関する設計
  • Build/Test の結果

3. aidlc-docs を成果物として扱う

aidlc-docs/ を単なる中間ファイルにしないほうが、後続開発で役立ちます。

たとえば次の用途があります。

  • 新メンバーへのオンボーディング資料
  • 設計レビューのベース
  • 変更理由の監査ログ
  • 次回の AI セッションへの文脈入力

4. 小さく始める

いきなり全社標準にするより、まずは次のようなテーマで試すのが無難です。

  • 小規模な新機能追加
  • 独立した内部ツール
  • Brownfield の限定的な改修

AI-DLC は強力ですが、最初から最大深度で回す必要はありません。

AI-DLC でエンジニアは成長できるのか

AI が計画して実装まで進める比率が上がると、エンジニアの成長機会が減るのではないか、という懸念はあります。

実際、AI をただのコード自動生成装置として使い、出てきた結果をほぼ無批判に受け入れる運用をすると、学習機会は薄くなります。

ただし、AI-DLC が目指しているのはその運用ではありません。

AI-DLC で増えるのは、単にコードを書く量ではなく、何を作るべきかを定義する力生成された計画や設計を評価する力品質と運用まで含めて判断する力 です。

言い換えると、AI-DLC は、より上流から下流まで一貫して判断できるエンジニア を求める考え方です。

実装しなくなるわけではない

まず前提として、AI-DLC を導入したからといって、人がコードから完全に離れるわけではありません。

この記事の電卓アプリの例でも、人が見るべき点は多く残っています。

  • 要件が過不足なく整理されているか
  • execution plan の深さは適切か
  • 生成コードが要件を正しく満たしているか
  • アクセシビリティや操作性の観点が落ちていないか
  • Build and Test の観点が十分か

つまり、AI がコードを書く場面が増えても、エンジニアには 読む力評価する力修正方針を決める力 が引き続き必要です。

成長の軸が変わる

従来は、成長の中心を「自分でどれだけ多くの実装を書いたか」に置きやすかったと思います。

AI-DLC では、その比重が少し変わります。重要になるのは次のような力です。

  1. 問題設定の力
    何を作るのか、何を作らないのか、どこに制約があるのかを明確にする力です。AI が優秀でも、問題設定が曖昧なら出力も曖昧になります。

  2. 要件分解の力
    ビジネス要件を、実装可能な要件、設計上の判断点、テスト観点に分解する力です。AI-DLC では Inception でここを丁寧に扱うので、この力がそのまま成果物の質に出ます。

  3. ドメイン理解
    AI は一般的な実装案を出せても、職場固有の業務知識や優先順位までは自動で補えません。だからこそ、人間側がドメイン知識を深める価値はむしろ高まります。

  4. 設計レビューの力
    AI が出した設計やコードを見て、どこが妥当でどこが危ないかを判断する力です。これは単なるレビューではなく、技術的な目利きに近い能力です。

  5. 品質判断の力
    動くかどうかだけでなく、テスト観点、運用性、保守性、変更容易性まで含めて妥当かを判断する力です。

  6. 説明責任を果たす力
    なぜこの要件なのか、なぜこの設計なのか、なぜこの生成物を承認したのかを説明する力です。AI-DLC は成果物が文書として残るぶん、この力も重要になります。

ドメイン知識の重要性はむしろ上がる

重要なのはここです。

AI-DLC では、ビジネス要件やドメイン知識の重要性は下がるのではなく、むしろ上がります。

理由は単純で、AI が一般化された実装や設計を素早く提案できるようになるほど、自分たちの現場では何が正しいか を決める人間側の知識が差になるからです。

たとえば同じ機能追加でも、次の違いは AI だけでは埋めにくい部分です。

  • この業務ではどの例外ケースが本当に重要か
  • 法務、監査、セキュリティ上どこが地雷か
  • 利用者が重視する操作感は何か
  • 組織としてどの品質水準を許容するか

こうした判断は、コード量ではなくドメイン理解の深さに依存します。AI-DLC はその理解を不要にするのではなく、より重要なものにします。

成長しなくなるケースはある

一方で、AI-DLC を導入すれば自動的に成長できるわけでもありません。

次のような使い方をすると、たしかに成長しにくくなります。

  • AI の提案を読まずに承認する
  • execution plan を確認しない
  • 設計文書を飛ばしてコードだけ眺める
  • なぜその実装になったかを追わない
  • テスト結果を見ずに完了扱いにする

この使い方は、AI-DLC の思想というより、単なる丸投げ運用です。成長を支えるのは AI の有無ではなく、どこで立ち止まって考えるか です。

AI-DLC は成長の機会を別の場所へ移す

結局のところ、AI-DLC は学習機会を消すのではなく、場所を変えます。

減りやすいものは、反復的な実装作業の比率です。

増えやすいものは、次のような学習です。

  • 要件整理の学習
  • ドメイン理解の学習
  • 設計レビューの学習
  • テスト観点の学習
  • 運用や保守を見据えた判断の学習

一方で、実装経験の減少が成長機会の減少につながるのではないか、という不安は残るかもしれません。

ただ、実務では、実装そのものに加えて、何を作るべきかを見極め、設計を判断し、品質を担保し、説明責任を果たすことも重要です。AI-DLC は、そうした力をより強く求めるやり方です。

AI-DLC を使うときの注意点

AI が正しいとは限らない

これは当たり前ですが、AI-DLC でも変わりません。むしろ、工程全体へ AI を広げるぶん、誤った前提が広く伝播する リスクがあります。

そのため、以下は必須です。

  • 計画の承認
  • 設計のレビュー
  • テスト結果の確認
  • コストとセキュリティの確認

文書の量を増やしすぎない

AI-DLC の価値は文書を増やすことではなく、必要な判断を追跡可能にすること です。軽微な修正に重厚な成果物を求めると逆効果です。

ツール導入より運用設計が大事

awslabs/aidlc-workflows を入れるだけで急に開発文化が変わるわけではありません。

次をチームで合わせておくほうが効果が出ます。

  • 誰がどこで承認するか
  • どの成果物を保存するか
  • どこまでを AI に委ねるか
  • セキュリティや監査の基準をどう適用するか

まとめ

AWS の AI-DLC は、AI を補助ツールから 開発ライフサイクルを前に進める協働者 へ引き上げるための方法論です。

特に実務で重要なのは次の点です。

  • 固定ワークフローではなく、課題に応じて工程を変えられる
  • 人間の承認を前提にしている
  • 要件、設計、実装、運用のつながりを成果物として残せる

そして awslabs/aidlc-workflows を使えば、その考え方を Kiro 上で具体的に試せます。

普段から AI を使っているエンジニアほど、次の順で試すと差が見えやすいはずです。

  1. 小さな題材で AI-DLC を使って、 ... から始める
  2. aidlc-docs/ の execution plan と design artifacts を丁寧にレビューする
  3. 承認ポイントを飛ばさず、どこまで深くやるべきかをチームで調整する

コード生成の速さだけでなく、開発の流れそのものをどう再設計するか に関心があるなら、AI-DLC は十分に試す価値があります。

参考資料

Discussion