
ソフトウェアテスト
イベント
マガジン
技術ブログ
はじめに こんにちは、トモニテ開発部の吉田です。 今回は、私たちの部署で実施した「AI days」という取り組みについてレポートします。2日間かけて、普段の開発業務にAIを組み込むための土台を集中的につくる社内イベントです。 そもそものきっかけは、私が「トモニテでのAI活用をもっと加速させていきたい」と声を上げたことでした。私は役職者ではなく一開発メンバーですが、その思いを伝えたところ、具体的な形として今回のAI days開催に至りました。最初から「AI daysをやりたい」と考えていたわけではなく、「なんとかしたい」という思いが先にあって、それがチームを巻き込んだ取り組みに育っていった、という流れです。 「AIを業務に活かしたい」という話はあちこちで聞くものの、実際にチームとして何から手をつければいいのかは悩ましいところだと思います。私たちも手探りで進めたので、その過程と、やってみて分かったことを正直に共有します。 なぜ「AI days」をやったのか きっかけは、いくつかの課題感が重なっていたことでした。 AI活用が「点在」していた 業界全体、そして社内の他部署でもAIを業務に組み込み始める動きが広がっていました。一方で私たちトモニテ開発部は、メンバーそれぞれがAIを使ってはいるものの、スキルやノウハウが個人に点在しているだけで、業務フローに常設できていない状態でした。 組織として一段上のフェーズへ 個人の工夫に頼るのではなく、開発部全体のAI活用レベルを底上げして、組織として次のフェーズへ移行したい、という思いがありました。今後の新たな取り組みに着手するときにも、ここで構築した環境や型をそのまま流用できる状態をつくっておきたい、という実利的な狙いもありました。 これらを一気に前進させるために、まとまった時間を確保して集中的に取り組む形として「AI days」を企画しました。 進め方 AI daysは、次のような構成で実施しました。 Day0: 何にフォーカスしてどんなものを作るのかディスカッション Day1〜2: チームでskillを作成する 実施後: 全体での振り返り Day0で方針を固め、残りの時間はひたすら手を動かす、という流れです。それぞれ、どんなことを話して何をやったのかを掘り下げて紹介します。 なお、本記事に出てくる「skill」「agent」「オーケストレーター」は、いずれも Claude Code をベースにした仕組みです。AIに実行させる手順や命令群を、Claude Code の skill / agent として書き起こしていった、という前提で読んでいただけると分かりやすいと思います。使用したモデルは、AI days を実施した2026年6月第1週時点での Claude Opus 4.8 です。 Day0:AIにどこまで任せるかを決める Day0は、作業日とは別にMTGとして実施しました。本番に入る前に、まずチームで次のことを共有・議論する時間です。 なぜやるのか:背景と大義名分の目線合わせ 他部署での活用事例の共有:たとえば、Claude Code と Redash MCP(Databricks)を組み合わせることで、非エンジニア(PMM)でも高度な統計分析や横断分析ができるようになった、といった事例 現在地のヒアリングとアクション議論:各自のAI活用の現状の持ち寄りと、次のアクションの検討 そして、この場で中心になったのが、「そもそも何にフォーカスするのか」という問いでした。 論点はいくつもありました。 日常業務の自動化か、機能開発の効率化か:効果が大きいのはどちらか。日常業務なら複数の業務をMCPでつないで回せるか、機能開発ならUIの妥当性やデザインとの接続まで担保できるか。 どこまで巻き込むか:開発部に閉じてやるか、ビジネスサイドまで巻き込める領域でやるか。 議論の中で見えてきたのは、領域によってAIに任せきれる度合いが違うということでした。たとえばサーバーサイドは、私たちの開発基盤上、DBのスキーマからモデルを自動生成したり、OpenAPIでAPIの型を定義したりと、「定義」から実装をコード生成で結びつける仕組みが整っています。そのぶん生成物が定義からずれにくく、確からしさを担保しやすい。一方でUIには、こうした「正解」を機械的に突き合わせる仕組みがなく、AIのよしなな判断に委ねるとずれが出やすく、任せきりにしにくい領域です。 こうした議論を経て、今回は「開発部に閉じて、実装フェーズの自動化にフォーカスする」と決めました。対象にしたのは、 要件 → 設計 設計 → 実装 それを受けてのレビュー という実装まわりの一連の流れです。なお、要件→設計については、すでに個人が作ったものが共有されていたため、AI daysでは設計→実装のところから着手しました。 ここで目指したのは、AIの生成物をほぼノーレビューでapproveできる状態でした(結果がどうだったかは、後半の「振り返り」であらためて触れます)。そのために、行き当たりばったりではなく「こういう順番で・こういうルールで開発する」という型(ハーネス/ガードレール)をあらかじめ決めてしまおう、という方針を立てました。 進め方そのものも合わせて決めました。モブプロ/ペアプロ形式で手を動かし、話し合った内容をその場で誰かが作業者として形にしていく。そして、毎日PRを出してマージするところまで持っていく、という進め方です。 Day1〜2:チームでskillをつくる まずは「どんなルールがあるとよいか」を出し合う Day1は、対象とするAPIサーバーのリポジトリを1つ決め、「設計→実装の仕組みづくりにおいて、どんなルールがあるとよいか」をメンバーそれぞれが発表するところから始めました。 出てきた観点は多岐にわたりました。 アーキテクチャの明示:レイヤードアーキテクチャや命名規則といった既存の実装規約 実装フローの明示:要件→設計→テスト→実装という順序、Red→Greenサイクル テスト設計方針:テストテンプレート、テストデータ作成、テーブルテストの汎用化 レビュー観点:個人情報、環境依存、命名規則、再利用性、依存パッケージのバージョンなど PR作成:レビューしやすいよう小さく分割する セキュリティ:余計な権限をつけない、依存は最新・公式の使い方に準拠 パフォーマンス:EXPLAINなどで重くなりそうな箇所に事前に気付けるように この過程で出てきたのは、明確なルールだけではありませんでした。「普段はこう書く」「ここはこう判断している」といった、これまで明文化されてこなかったチームの共通認識も、あわせて表に出てきました。各自の頭の中にあった前提を口に出して並べたことが、思わぬ副産物につながりました。この点は、後ほど「振り返り」であらためて触れます。 「AIにできること/できないこと」で仕分ける 集まったアイデアは、次の3つに分類していきました。 人間はできているが、AIがまだできていないこと 人間もAIもできていないこと これまでできていなかったが、AIを使うことで効率よくできるようになること この仕分けが効きました。(1) はすでに人間が回せていることを言語化すればよいので、効果が出やすく着手しやすい。(2)(3) は新たに型をつくる必要があるぶん難度は上がりますが、うまくいけば伸びしろが大きいというように、何にどれだけ力を割くかの優先度を、チームの認識を揃えたうえで決められたからです。 そのうえで採ったのが、「普段のワークフローをskillに落とし込む」というアプローチです。いきなりAIエージェントの大掛かりな設計に踏み込むのではなく、すでに自分たちが回している業務の手順を、AIが実行できる形(skill)として書き起こしていきました。身近な業務から手をつけられるので、メンバー全員が手を動かしやすく、成果物がそのまま日々の開発に使える、という狙いです。初日は、この設計→実装のskillを形にするところまで進めました。 動かして検証し、レビューフローまでつくる 2日目は、前日につくったskillを実際のタスクに当てて動かし、その結果をチームで共有するところから始めました。出来上がったコードだけでなく、エージェントが実際にどう動いたかのログも一緒に見ながら、「ここは気になる」というポイントを洗い出していきます。たとえば、こんな気づきが挙がりました。 既存の実装を見つけているのに使わない:月齢計算のような複雑な処理で、本来は流用してほしい既存のユーティリティ関数があるのに、AIはそれを見つけたうえで使わず、独自に実装していました。「これを使ってね」という前提を事前に渡しておくべきだった、という気づきです。 ゼロから作るものは別PRに切り出したい:テストのfactoryのように、まだベースが存在しないものを実装しながら作らせると、意図しない作り方になりがちでした。先にそれだけを用意するPRを分けた方がよさそうです。あわせて「PRをどう分割するか」自体も、判断基準として持たせる必要があるかもしれません。 手順として明示すべき付随作業がある:DBを変更したらマイグレーションを生成する、API定義を変えたらドキュメント(swagger)を更新する、といった作業は、フローの中に手順として書いておかないと抜けてしまいます。 agentとskillの責務分担:「どこまでをagentに考えさせ、どこからをskillとして固定するか」の線引きには個人差があり、ここでも議論になりました(この問いは後述の「今後の展望」にもつながっていきます)。 そして、こうして見えてきた観点も踏まえながら、2日目の後半は、初日と同じくモブプロ形式でレビューフローの作成に取り組みました。実装する側だけでなく、生成物をチェックする側の型もそろえることで、「AIに実装を任せ、別系統でレビューする」という一連の流れを形にする、という狙いです。 つくったもの 2日間で、思っていた以上にたくさんの成果物が生まれました。大きく分けると、AIに渡すための「土台」と、それを使って実際に動かしたskill群です。 土台(AIに前提を渡すためのドキュメント類) リポジトリごとの約束ごとをまとめた CLAUDE.md テスト設計ガイドライン(テスト設計の指針をドキュメント化。 docs/test_design_guideline.md ) 実装ガイドラインの更新( docs/implementation_guide.md ) 実装フローを回すskill群 全体を束ねるオーケストレーターと、そこから呼び出される工程ごとのskillをセットで作りました。タスク分割書(実装タスクを粒度ごとに分割したドキュメント。前述のとおり要件→設計の工程は既存のskillが担っており、その出力物がこれにあたります)を入力に渡すと、テストコード・実装のdiff・ドラフトPRが出力される、というイメージです。具体的には、次の流れを一気通貫で回します。 コンテキスト収集 → テストケース定義 → テスト実装(Red)→ 機能実装(Green / Refactor)→ 動作確認(curlでの実機疎通)→ ドラフトPR作成 → レビュー 工夫したのは、各工程を独立したサブエージェント(別コンテキスト)として起動し、引き継ぎは会話ではなくファイル(収集したコンテキスト、テストコード、diff など)で行うようにした点です。テスト・実装・レビューが互いの思考を引きずらないので、後述する「別系統でのレビュー」も自然に組み込めました。 イメージしやすいよう、オーケストレーターskillの構成をもう少し具体的に紹介します。オーケストレーター自身は「薄く」保ち、ループ制御・サブエージェントの起動・成果物の引き継ぎ・失敗時の停止に徹して、実装の実体は工程ごとのskillに委譲する、という役割分担です。タスク分割書の依存関係からタスクの実装順を決め、1タスクごとに次の工程を回していきます。全体像を図にすると、次のような流れになります。 工程 委譲先skill 成果物 ① コンテキスト収集 collect-context context.md(当該タスク分) ② テストケース定義 write-testcases testcases.md ③a テスト実装(Red) implement-tests テストコード+Red確認 ③b 機能実装(Green / Refactor) implement-feature 本番コード+全テストGreen ③c 動作確認 verify-endpoint curlでの疎通確認結果(※エンドポイントを含むタスクのみ) ④ ドラフトPR作成 create-draft-pr 1タスク=1ドラフトPR ⑤ レビュー 社内のレビュー用プラグイン 指摘一覧 フロー全体のルールとしては、次のようなものを明文化しています。 工程は基本①〜⑤を順に回すが、③c 動作確認はエンドポイントの追加・変更を含むタスクのときだけ実行する(repository追加やバッチなど、叩く対象がないタスクではスキップする) PRは1タスク=1PRで小さく保ち、依存タスクがある場合は依存先のブランチから分岐したスタックPRにする レビュー(⑤)でCritical / Importantな指摘が出たら、機能実装とレビューを、指摘がゼロになるまで往復する(上限あり)。このとき、修正者の思考をレビューが引き継がないよう、レビュー担当のサブエージェントは毎回新規に起動する Greenにできない・要件と矛盾するなど解消できない問題に当たったら、推測で進めずに要確認事項として記録し、そのタスクで停止する もう一歩踏み込んで、各工程のskillに実際に書いている指示も紹介します。どのskillも、「品質に気をつける」のような心構えではなく、 「〜の場合は〜する」という状況と行動のペア で指示を書いています。 テストケース定義(②)には、こんな指示を書いています。 異常系は「エラーになること」ではなく、期待するエラー文言・型まで指定する 各テストケースに信頼性ラベルを付けさせる。「🔵 要件・既存実装に基づく / 🟡 合理的な推測 / 🔴 要確認」の3段階で、AIが推測で書いた部分を確定情報と混ぜさせない テスト実装(③a)のskillには、「テストを仕様として、本番実装とは独立したコンテキストで書く」という目的と、それを守るための指示を書いています。 本番ロジックは書かない。テストのコンパイルを通すための最小限のスタブ(中身は panic("not implemented") など)までは許可する Redを確認するときは、失敗の理由が「未実装による期待どおりの失敗」なのか「テストコード自体のバグ」なのかを切り分けてから返す 機能実装(③b)には、その逆を守らせる指示を書いています。 テストを弱めない。Greenにするためにアサーションを緩めたり削ったりしない。テスト側にバグがあると判断しても自分では直さず、要確認として報告する(テストは別工程の責務) リファクタは「このタスクで自分が書いた差分」に限定する。既存コードの規約違反に気づいても勝手に直さず、別PRの領分として報告に留める 動作確認(③c)には、何をもって「確認できた」とするかを指示しています。 「200が返った」だけでは正常系の確認にしない。検証用の既知の値をDBに投入し、それがレスポンスに正しく含まれることまで突き合わせる。あわせて、他ユーザーのデータや論理削除済みデータといった「含まれてはいけないデータが含まれない」ことも確認する 結果が期待と違ったら❌のまま正直に報告し、レポートを✅に寄せない。安易に「環境のせい」にしない こうした指示の多くは、最初から書けていたわけではなく、実行ログで意図しない動作を見つけるたびに書き足していったものです。たとえば「実行が英語で進んでいってしまう」という地味な問題は、サブエージェントを起動するプロンプトの冒頭に「すべての出力・成果物・ユーザーへの質問は日本語で行うこと」を必ず明記する、という指示で潰しました。 書いたルールが実際に判断として現れた場面もありました。テスト側のフィクスチャにバグがあり(デフォルト値を持つカラムにゼロ値を入れたところ、ORMの仕様でドロップされてDB側のデフォルト値で上書きされ、「非アクティブにしたいデータ」がアクティブのまま保存されていた)、実装が正しいのにテストがGreenにならない状況が起きたときのことです。このとき機能実装のサブエージェントは「テストを弱めない・テストは別工程の責務」というルールに従って、テストを書き換えてGreenにする近道を選ばず、オーケストレーターに差し戻していました。 そのときのオーケストレーターの実行ログがこちらです(抜粋・整形。日本語化の指示を入れる前の実行なので英語のままです)。 ⏺ Agent(Write testcases TASK-0003) ⎿ Done (13 tool uses · 72.1k tokens · 1m 56s) ⏺ 14 cases. Test subagent (Red) for TASK-0003: ⏺ Agent(Write Red tests TASK-0003) ⎿ Done (22 tool uses · 103.3k tokens · 3m 12s) ⏺ Red confirmed (14 cases). Feature subagent (Green→Refactor) for TASK-0003: ⏺ Agent(Implement TASK-0003 Green) ⎿ Done (20 tool uses · 52.3k tokens · 2m 40s) ⏺ The feature SA found a genuine test-fixture bug (not an impl bug): boil.Infer() drops is_active=false (zero-value of a with-default column), so the inactive fixture V3 persists as active. The impl is correct; per the skill the feature SA correctly refused to weaken the tests and stopped. Fixing fixtures is implement-tests' responsibility. I'll spawn a focused test-fix subagent (still the implement-tests role): ⏺ Agent(Fix TASK-0003 test fixture) ⎿ Done (14 tool uses · 38.2k tokens · 1m 22s) ⏺ 14/14 green now. テストケース定義→テスト実装(Red)→機能実装(Green)と工程ごとにサブエージェントが起動されていく様子と、機能実装のサブエージェントがフィクスチャのバグを見つけながらも自分では直さず("correctly refused to weaken the tests and stopped")、オーケストレーターがテスト修正専用のサブエージェントを改めて立ち上げて、フィクスチャだけをピンポイントで直させた様子が分かります。skillに書いた「テストを弱めない・テスト側のバグは自分で直さず報告する」が、そのまま判断として現れた例です。 一方で、現実的な落としどころを選んだ部分もあります。レビュー工程は、社内ですでにプラグイン化されているものを再利用しました(このレビュー用プラグインについては 過去のブログ記事 で紹介しています。その後もアップデートを重ねています)。また動作確認は、そもそも「何をもって動作確認とするか」という議論もしました。その過程で「リモートのテスト環境(社内のtestkit)経由で実行できる仕組み」という案も出たのですが、時間の兼ね合いで断念。今回はcurlでの実機疎通に落ち着いています。 そして、これらを使って実際にコードを書き、プルリクエストを出すところまで一気に進めることができました。人間が操作したのは、走り出す前にオーケストレーターから「どこまで自律で進めるか」「push・PR作成をどう扱うか」を確認されて回答した一度だけで、あとは全自動でできました。 振り返り:やってみて分かったこと 実施後、メンバー全員で振り返りを行いました。出てきた声を、よかった点と課題に分けて整理します。 よかったこと オーケストレーター+個別skillという構成 全体を指揮するオーケストレーターと、個別のskillに分けた構成にしたのですが、これがとてもよかったです。役割が分かれているので作るときも考えやすく、あとから育てていきやすい構成になりました。 暗黙知を言語化する作業そのものに価値があった skillをつくるには、普段は頭の中にある暗黙知を明文化する必要があります。この「暗黙知を落とし込む」作業は、skill作成の上で必須であると同時に、チームの知識を整理するうえでも意味のあるプロセスでした。 振り返りでも、「チームでの理解が揃った」「自分たちのコーディングやレビュー視点の棚卸しになった」「開発のスタイルや意思決定に対する、お互いの認識を合わせられた」という声が多く挙がりました。AIに渡すための土台(コンテキスト)を整える作業が、結果としてチーム内の共通認識を言語化する場にもなった、というのが大きな収穫でした。 モブプロ/ペアプロ形式が「やり方の共有」になった 普段の開発とはあえて違う形式で進めましたが、これも結果的によかった点です。話し合った内容をその場で誰かが形にしていくので、議論したことがそのまま成果物として残っていきました。また、skillやプロンプトを書く過程を互いに見ながら進める形式だったこともあり、振り返りでは「それぞれがどんなふうにskillを使い、作っているかという話ができたのはよかった」という声が挙がりました。AI活用のノウハウが個人に点在していた私たちにとって、やり方そのものを共有する機会になりました。 「まずは作ってみる」で十分ワークした ワークフローを落とし込むだけで、ある程度使えるものが出来上がりました。最初から作り込む必要はなく、まずトライしてみる、というスタンスで進めてよかったと感じています。 課題 「ツールで仕組み化すべき層」と「AIに任せる層」が混ざっていた 一方で反省点もありました。本来は静的解析(linterや型チェックなど)で機械的に防げるはずのところを、skill側でカバーしようとしていたケースがありました。 裏を返すと、暗黙知をわざわざskillに落とし込まなくても、静的解析で担保できた領域があったということです。何でもAIに言い聞かせるのではなく、コンパイラやリンターのレベルで制約をかけられるものはそちらに寄せる、という切り分けが必要だと気づかされました。 AIのセルフレビューには構造的な盲点があった もう1つ、AI駆動開発ならではの学びがありました。生成されたコードに対してAI自身にセルフレビューをさせると「重大な問題はなし」と返ってくる一方、別のAIコードレビューに通すと、バグやテストの不備が次々と見つかる、という場面が繰り返し起きたのです。 設計判断そのものは概ね妥当でも、AIに「自分の書いたものを自分でレビューさせる」だけだと、観点に構造的な抜けが残るということです。集約したデータを取りこぼしていないか、境界条件、並列実行時のテストの安定性など、人間でも見落としやすい観点ほど抜けやすい傾向がありました。 ここから得た教訓は、AIに任せきりにせず、静的解析・別系統のレビュー・人間のレビューを重ねる「多層のガードレール」を前提に組むべき、ということです。 さらに踏み込んで議論したこと 「よかった/課題」とは別に、振り返りでは少し踏み込んだ問いについても議論しました。AI駆動開発をチームで進めるうえで、同じことを考えている方の参考になりそうなので共有します。 通常業務の時間を削ってまで、この期間を確保した価値はあったか ここはおおむね「価値はあった」で一致しました。チームの理解が揃い、各自がどんなふうにskillを使い・作っているかを共有でき、AI駆動開発を進めるための基盤ができた、という点が評価されました。一方で「実際の開発フローへの導入まではもう一段ハードルが高い」という現実的な声もありました。 作ったものを、そのまま実務に流用できそうか ここは率直に「使える、ただし手放しでは無理」という評価でした。 使うことはできるが、劇的に速くなるわけではない 出来上がるのは「本実装とプロトタイプの中間」くらいの成果物で、そのまま扱うには少し悩ましい 「どこかにダメな部分がありそう」という前提でレビューするので、認知負荷込みで考えると「爆速」にはならない レビューの往復は当面避けられず、人間の手放しは遠い ただし、「要件を満たすPRが出来上がるまでのリードタイムは減らせそう」という手応えもありました。実装そのものは人間がやらなくてよい、けれどその分の穴を見つけて直す工程が残る、というのが現在地です。「せめて、AIレビューで定番的に指摘される箇所くらいは、AI自身が自律的に直せるようになってほしい」という要望も挙がりました。 なぜ「育てながら使う」という結論に落ち着いたか 「このままバッチリ使える」ではなく「各自で使いながら育てよう」という着地になった背景も振り返りました。 成果物の数は出たものの、全体を一気に「広く」設計してしまったため、一つひとつのskillの試行錯誤や深掘り(精度向上)に時間を割ききれなかった(開発フローの一部に絞って深める、というやり方もあり得たかも) 言語化しきれていない暗黙の指定が、まだ多く残っている skillへの指定だけでは限界があり、コンパイラやリンターのような強い制約はかけられない 「使ったあとにどう育てるか」までフローに組み込めていれば、もう少し「勝手に育つ」状態に近づけられたかもしれない 印象的だったのは、「これまで『よしなに実装』していたのが、『よしなにAIを育てる』に変わった感じ」という表現でした。人間がやることの重心が、実装そのものから「AIをどう育てるかの設計」へ移りつつある、という感覚です。 継続して運用するために、最低限なにが必要か 最後に、これを一過性で終わらせないために必要な仕組みを洗い出しました。 ガードレール(静的解析やテストのファクトリなど、機械的に品質を担保する仕組み) 各skillをもっと独立させ、一部から個別に導入・チューニングできるようにすること フィードバックを貯める場所と、それを改善に回すループ(理想は、改善が自然な運用フローに乗っている状態) 「どう育てていくか」の方針 今後の展望 今回は「ワークフローをskillに落とし込む」という形で進めましたが、振り返ってみると、その一歩手前にある「これはskillにすべきか、agentにすべきか」「skillの責務は必要十分か」という「AIの設計」のレベルまで踏み込めていれば、さらによかったかもしれません。 次の一手としては、実装前の手順も含めた全体フローを可視化し、どこからどこまでがAIの役割で、どこが人間の責務なのか(エンジニアだけでなく、PdMレベルも含めて)を整理していきたいと考えています。 あわせて、このskill群が実際にどれだけ利用されているかも計測していくつもりです。また、どの工程にどのモデルを充ててトークンコストをコントロールするかも、ハーネスエンジニアリングの一部として今後組み込んでいきたいと考えています。 まずは作ってみる、はじめから作り込まない、というアプローチ自体は正解だったと思っています。「改善は使った人が各自で進めてよし、大きな変更や相談したいことは歓迎」というゆるやかな運用方針のもと、ここで構築した環境や型を、今後の開発で継続的に育てながら活かしていく予定です。 まとめ 「AI days」は、点在していたAI活用のスキルを、組織の型として束ねていくための第一歩でした。 2日間という短い期間でも、ワークフローをskillに落とし込むだけで、ある程度使えるものを形にできました。同時に、「ツールで仕組み化すべき層との切り分け」「AIのセルフレビューの盲点」「育てる仕組みの必要性」といった、次に向き合うべき課題も具体的に見えてきました。 私たちの場合は、「まずは作ってみる。はじめから作り込まない」というスタンスで始めてみました。まだ手探りですが、得られた型を実務で磨きながら、次はもっと使えるものを作れるよう、引き続き思いを馳せていきます。
本ブログは 2026 年 6 月 4 日に公開された Blog “ Amazon Cognito unlocks advanced capabilities with next-generation infrastructure ” を翻訳したものです。 Amazon Cognito は最近、3 つの強化を導入しました。要求の厳しいワークロードに対応する高スループットパフォーマンス、保管時のデータ暗号化を完全に制御できるカスタマーマネージドキー、そして事業継続性を向上させるマルチリージョンレプリケーションです。これらの機能は、拡張性とスケールを考慮して設計された次世代のストレージインフラストラクチャによって実現されています。これらの強化をお客様に提供するにあたり、数億件のユーザープロファイルを移行しましたが、おそらくお気づきになることはなかったはずです。本投稿では、新機能の概要、その背後にあるアーキテクチャ、そしてお客様のアプリケーションを稼働させたままゼロダウンタイムで実現した移行について解説します。 Cognito で利用可能になった新機能 新しいインフラストラクチャへの移行は、単に既存の機能を維持するためだけのものではありませんでした。それは、Amazon Cognito の継続的な改善を可能にしつつ、お客様の課題を解決する機能を提供するための基盤を構築するものでした。 高スループットなパフォーマンス : 新しいアーキテクチャは、モダンなアプリケーションが要求するより高いリクエスト量とスケール要件をサポートしながら、アプリケーションが依存する低レイテンシのパフォーマンスを維持します。これにより、1 つのユーザープールあたり数千万人のユーザーと、1 秒あたり数千トランザクション (TPS) をサポートできます。 カスタマーマネージドキー : お客様は、保管時のデータの暗号化に、 AWS Key Management Service (AWS KMS) に保存された独自の暗号化キーを使用できるようになりました。これにより、セキュリティ制御と機能が強化され、お客様は暗号化キーのライフサイクルを完全に管理できます。 マルチリージョンレプリケーション : お客様は、ユーザーのパスワード、属性、設定を含むユーザープール全体のデータを、選択した別のリージョンの別のユーザープールに同期できるようになりました。これにより、お客様は事業継続計画 (BCP) を実装し、リージョンのフェイルオーバーが発生した場合でも認証の可用性を維持できます。予期しない障害が発生した場合でも、アプリケーションをユーザーが利用し続けられるようサポートします。 イノベーションのためのアーキテクチャ 新しいアーキテクチャでは、ID 操作の拡張性とスケーラビリティを目的として設計された専用のストレージレイヤーを使用しています。新しいアーキテクチャは、以下の設計理念を中心に据えて構築しました。 アイデンティティファーストの設計 : ストレージレイヤーがユーザー ID を理解します。クライアント固有のビジネスロジックは存在せず、ID 管理を超えた一般化も行いません。これにより、システムは焦点を絞り、ポータブルで最適化された状態を保ちます。 後戻りできない選択を避ける : アーキテクチャの選択を後から変更可能な状態に保ちながら、価値を段階的に提供します。これにより、新たなニーズが生じた際に進化できます。 後方互換性 : 基盤となるインフラストラクチャへの変更が、お客様のアプリケーションの動作を決して損なわないようにします。 これらの理念が、すべてのアーキテクチャ上の意思決定を形作りました。このアーキテクチャは、独立してデプロイ可能なドメインに分割されています。以前は、 Amazon Cloud Directory を使用していたため、サービスアーキテクチャはすべての顧客情報を永続化するために単一のデータストアに依存していました。これにより、シンプルなデータ走査が可能になりましたが、新機能が必要になった際にデータベーススキーマを調整するには複数サービス間の調整が必要でした。新しいアーキテクチャでは異なるデータセットを使用しており、それぞれが独立して進化できるため、より迅速な機能の反復改善が可能になります。 ゼロダウンタイムでの移行 ユーザーの移行には細心の注意が求められ、すべてのステップでダウンタイムゼロを維持し、データの整合性を確保するために設計された戦略が必要です。私たちのアプローチでは、次の施策を通じて、即時の安定性と長期的な柔軟性の両方を優先しています。 シャドウモード検証 : 顧客の API リクエストを新旧両方のインフラストラクチャに同時に流し、レスポンス構造、ステータスコード、動作特性を比較しました。この検証は、比較中に機密情報が平文で公開されることが決してないように設計されています。たとえば、システム間でタイムスタンプがわずかに異なる場合があるといった既知の差異を考慮し、意味のある不一致のみが対処すべきアラートとして表面化するようにしました。 データバックフィル: ユーザープールを新しいインフラストラクチャに切り替える前に、レガシーシステムから既存のすべてのユーザーレコードを新しいストレージへ一括投入(バックフィル)しました。この反映は本番トラフィックの裏側で並行して実行され、後述のデュアルライトによってバックフィル期間中に行われた変更を取り込み、データの損失や古いデータの参照が発生しないようにしました。シャドウモードはバックフィルの検証レイヤーとして機能しました。データ同期におけるエッジケースへの対応を進めるにつれてシャドウモードの一致率が上昇し、切り替えに進む前にデータの完全性を確認できました。 デュアルライトアーキテクチャ : すべての ID 操作をレガシーサービスと新サービスの両方に同時に書き込むシステムを実装し、整合性を確保するための包括的な検証を行いました。新しいインフラストラクチャへのデュアルライトが失敗した場合でも、操作はレガシーシステムで引き続き成功し、顧客が開始したすべてのリクエストが保持されます。これはつまり、デュアルライトの失敗は内部的な整合性の問題として封じ込められ、顧客に影響を与えなかったということです。 アンチエントロピー検証 : 新旧のインフラストラクチャ間でレコードを継続的に比較し、データの乖離を検出して解決するデータ検証および修正システムを実装しました。アンチエントロピースキャンでは、ユーザー属性、認証情報のハッシュ、グループメンバーシップ、設定などのレコードを比較しました。真の不一致が見つかった場合、システムはレガシーシステムを信頼できる情報源 (source of truth) として使用し、自動的にそれらを調整しました。このレイヤーは、シャドウモードとデュアルライトだけではカバーできないエッジケースを捕捉できました。 ロールバック機能を備えた段階的ロールアウト : 即時ロールバック機能を備えた、制御されたデプロイフェーズを確立しました。ユーザープールを新しいインフラストラクチャに切り替えた後も、すべての書き込みをレガシーシステムへ複製し続け、データの損失なしにいつでもユーザープールをレガシーインフラストラクチャに戻せるようにしました。移行中にロールバックが必要になった場合、オーケストレーターがタイムスタンプ順にエントリを再適用し、ユーザープロファイルをレガシーシステムに同期し直しました。 インフラストラクチャモダナイゼーションから得られた教訓 このモダナイゼーションを通じて、私たちはあらゆる大規模インフラストラクチャプロジェクトに適用できる貴重な原則を学びました。そのため、皆様が同様の移行を実施する際の参考になるよう、これらの学びを共有することにしました。 顧客のアクセスパターンがアーキテクチャの意思決定を左右する : 実際の顧客のアクセスパターンを分析した結果、ID ワークロードは予測可能なパターンに従うことが明らかになりました。これは、完全性と運用のシンプルさのバランスを取った同期型のデュアルライトアプローチを採用できることを意味していました。この原則は、あらゆるドメイン固有の移行に適用できます。汎用的なソリューションに手を伸ばす前に、ワークロードの実際のアクセスパターンを理解しましょう。 動作の保持には従来のテストを超えた技術が必要 : 新旧のシステム間で同等の機能を確保することは簡単でした。しかし、まったく同じ API の動作を保持することは簡単ではありませんでした。機能テストは意図された動作を検証しますが、特定の API の動作を前提に顧客がアプリケーションを構築しているシナリオを特定しました。そのような場合、変更によって顧客のアプリケーションが気づかないうちに壊れてしまう可能性がありました。たとえば、同じユーザーへの同時書き込みが、新旧のシステム間で最終的に異なる状態に収束する可能性があります。書き込みはすべて成功しますが、結果がわずかに異なるのです。同様に、属性を書き込んだ直後にそれを読み取る顧客は、整合性ウィンドウの影響を受けます。更新が反映されるタイミングのわずかな違いが、古いデータの読み取りを引き起こす可能性があります。これらは機能的な障害ではありませんが、実際のトラフィックパターンにおける動作は変化する可能性があります。シャドウモードでの検証により、自動テストだけでは見逃していたエッジケースが浮き彫りになりました。これらの技術には早期に投資しましょう。 段階的な検証は、テストだけでは得られない信頼性を築く : それぞれが異なるアクセスパターンをカバーする複数の独立した検証技術(シャドウモード、デュアルライト、アンチエントロピースキャンなど)を、組み合わせて適用しましょう。単一のアプローチですべてを検出できることはなく、それらの間の隙間こそが本番環境の問題が潜む場所です。即時ロールバック機能を備えた段階的なロールアウトにより、各ステップを検証しながら、迅速に元の状態に戻す能力を維持できます。 ご自身のモダナイゼーションプロジェクトで押さえるべき主要原則 : 目的に特化したソリューションに投資し、拡張性を考慮した設計を行い、段階的な検証を実装しましょう。あるいは、マネージドサービスを利用すれば、アプリケーションを稼働させ続けながら、手間をかけることなくインフラストラクチャが改善され、ビジネスニーズに集中できるようになります。 まとめ 本投稿では、最新の ID 管理機能の基盤を構築する Amazon Cognito のインフラストラクチャモダナイゼーションから得られた全体的なアプローチと学びを共有しました。新しい Cognito インフラストラクチャはすでに稼働しており、カスタマーマネージドキーやマルチリージョンレプリケーションといった機能を提供しています。移行が進むにつれて、すべての Cognito のお客様は、現在ご利用中のものと同じサービス上で、特別な操作を必要とすることなくこれらの機能を利用できるようになります。 認証インフラストラクチャをモダナイズする準備はできましたか?詳細については、 Amazon Cognito をご覧ください。 Howie Li Howie は Amazon Web Services のプロダクトマネージャーで、認証をデフォルトで簡単にすることに取り組んでいます。仕事以外では、旅行を通じて文化や食を探求したり、それらにインスパイアされた新しいアイスクリームのフレーバーを考案したりすることを楽しんでいます。 Georgi Baghdasaryan Georgi は Amazon Web Services のプリンシパルエンジニアであり、組織が大規模にアクセスと認証を安全に管理できるよう支援するアイデンティティシステムを構築しています。彼のより広範な関心は、お客様がクラウドで安心して運用できるようにする、信頼性が高く影響力の大きいインフラストラクチャにあります。仕事以外では、新しい抹茶ラテのレシピを試したり、長距離のサイクリングを楽しんだりしています。 本ブログは Solutions Architect の松井 僚太郎が翻訳しました。
テスト観点を軸にした品質サイクルのすすめ 「テストが終わらない」——ソフトウェア開発に携わる人なら、一度はこの言葉を口にしたことがあるのではないでしょうか。リリース直前に湧き出るバグ、収束しない不具合、膨れ上がるテストケース。なぜ、テストはいつも終わらないのか。 結論から言います。テストを「する」ことを目的にしているからです。 テストケースを消化すること、カバレッジを上げること、全項目を網羅すること。これらは手段であって、目的ではありません。本当に問われるべきは、「そのテストは品質を上げているのか?」という問いです。 この記事では、テストそのものではなく、テスト観点を軸にした品質サイク





















