はじめに
アドフリくん開発プロジェクトは、広告運用の自動化を目指すSaaSプロダクトの開発プロジェクトです。 複雑なビジネスロジックと高い変更頻度が予想される要件に対応するため、私たちはアジャイル開発手法を全面的に採用しました。
従来のウォーターフォール型開発では、仕様変更への対応や品質確保に課題を感じていました。 特に、ビジネス要件の変化が激しい広告業界において、柔軟かつ迅速な開発が求められていました。
本記事では、以下の観点からアジャイル開発手法の実践について詳しく解説します。
- プロセス面: スクラム開発の導入と運用
- 設計面: ドメイン駆動設計(DDD)とC4 Modelsによる可視化
- 実装面: Clean Architectureの適用とテスト駆動開発の実践
1. 開発プロセス:スクラム開発の採用
1.1 会議体の制定
アドフリくんプロジェクトでは、1週間スプリントのスクラム開発を採用しました。 新規採用技術が多く、要件の解像度も低かったため、課題を素早く吸い上げて設計や実装に反映することを重視し、短いサイクルを選択しました。 以下の会議体を定期的に実施することで、チーム全体の透明性と協調性を高めました。
スプリントプランニング(1週間に1回、1時間)
- プロダクトバックログの優先順位付け
- タスクの説明
- タスクの詳細化とアサイン
デイリースクラム(毎日、30分)
- 会議やSlackなどでの決定事項共有
- インシデントの共有
- スプリントゴールに向けた進捗確認
レトロスペクティブ(1週間に1回、1時間)
- Keep(継続すべきこと)
- Problem(問題点)
- Try(次回試すこと)
- チームの改善アクションプラン策定
今回、スプリントレビューは行いませんでした。 成果物にUIが存在しないため、地味過ぎて見ていて退屈なことが理由です。
1.2 導入の効果と課題
チームコミュニケーションの改善 デイリースクラムにより、メンバー間の情報共有が格段に向上しました。 従来は個人作業に陥りがちでしたが、チーム全体で問題を解決する文化が根付きました。
透明性の向上 スプリントバックログとバーンダウンチャートの可視化により、プロジェクト進捗が常に把握できるようになりました。 ステークホルダーも開発状況を理解しやすくなり、適切なフィードバックを得られるようになりました。
1週間スプリントのメリットとデメリット
- メリット: 新規技術や不明確な要件に対する素早い学習サイクル、課題の早期発見と対応
- デメリット: ベロシティの不安定化、中長期スケジュール見積もりの困難さ、会議コストの増加
今回は実装の進捗と並行して、要件の解像度が上がるイレギュラーケースであったため、1週間スプリントが機能しました。 しかし、デメリットが大きいため、今後は2週間のスプリントにしたいと思います。
2. 設計手法:ドメイン駆動設計(DDD)の実践
2.1 DDDを選択した理由
ビジネスロジックの複雑性への対応 広告配信システムは、オークション処理、入札戦略、効果測定など、複雑なビジネスルールが絡み合います。 DDDのアプローチにより、これらの複雑性をドメインモデルとして適切に表現できました。
ドメインエキスパートとの共通言語の構築 同じ用語・概念で議論できるユビキタス言語を確立しました。 これにより、要件定義の精度が大幅に向上しました。
2.2 実装における工夫
エンティティの設計 ドメインの概念を適切にエンティティで表現しました。
ドメインサービスの活用 複数のエンティティにまたがる複雑なビジネスロジックは、ユースケースとして実装しました。
3. アーキテクチャ設計:C4 Modelsによる可視化
3.1 C4 Modelsとは
C4 Modelsは、ソフトウェアアーキテクチャを4つの抽象レベルで表現する手法です。 従来のUMLや複雑な設計書に比べ、ステークホルダー全員が理解しやすい図で表現できます。
4階層の概要
- Level 1 (Context): システム全体と外部システムとの関係
- Level 2 (Container): システム内の主要コンポーネントと技術スタック
- Level 3 (Component): 各コンテナ内部の詳細設計
- Level 4 (Code): クラス図やシーケンス図レベルの実装詳細
従来の設計手法との違い
- 可読性: 専門知識がなくても理解できる
- 階層性: 必要な詳細レベルを選択して説明可能
- 保守性: システム変更時の影響範囲が把握しやすい
3.2 実際の設計プロセス
レベル1(システムコンテキスト図)
まず、アドフリくんシステムが他のシステムとどのように連携するかを明確にします。 これにより、外部API依存や データフローの全体像を把握できます。
アドフリくんはSSPとしてメディエーションを行なっているため、DSPへ広告リクエストを送信します。 また、RTBを行なっているため、DSP及びAdExchangeに入札リクエストを送信します。 それらのレスポンスを受け、アプリに最適な広告を送信します。
レベル2(コンテナ図)
次に、各コンテナの責務と技術スタックを図示します。
コンテナ図全体で、コンテキスト(システムコンテキスト図の黄色四角)「Adfurikun」を表しています。 RTBシステムはGKEで動作しているため、Web ServerやBatchのPodをコンテナとして図示しました。 また、一部のシステムはEC2で動作しているため、それを1つのコンテナとして図示しました。 ストレージとして利用しているBigTable、Mongo、S3、BigQueryをコンテナとして記載し、それらの関係を線で示しました。
レベル3(コンポーネント図)
各コンテナ内部をコンポーネントに分割します。
白枠がコンテナ(コンテナ図の黄色四角)を表しており、その内部をコンポーネントという単位で分割して図示しています。 今回のプロジェクトはマイクロサービスのため、1つのコンテナが小さいという特徴があります。 そのため、この図は不要と感じました。 しかし、モジュラーモノリスのような巨大なコンテナを持つ場合、モジュールの関係を図示するのに効果を発揮するのではないかと考えています。
レベル4(コード図)
具体的なコード構成を記載。
白枠がコンテナ(コンテナ図の黄色四角)を表していますが、本来はコンポーネントを表すのが正しいかと思います。 今回はgolangで実装したため、packageを1つのコード(黄色四角)として表現しました。 Clean Architectureを採用したため、依存関係が一方行に向かっていることを視覚的に確認できます。
3.3 チーム全員での合意形成
図を使った議論の進め方
- アーキテクチャレビュー: C4図を使った設計議論
- ライブモデリング: Miroホワイトボードでの協働設計
- 非同期レビュー: Pull Requestでの設計変更確認
アジャイル、スクラム、DDDを採用したため、全員の概念モデルを一致させる必要があります。 このケースでは、Miroを使って全員でモデリングする手法は、非常に有効でした。
4. 実装アーキテクチャ:Clean Architectureの適用
4.1 Clean Architectureの採用理由
依存関係の制御 従来のMVCアーキテクチャでは、コントローラーがデータベースやフレームワークに密結合になりがちでした。 Clean Architectureにより、ビジネスロジックを外部技術から独立させることができました。
テスタビリティの向上 依存性注入とインターフェースの活用により、単体テストが格段に書きやすくなりました。 外部APIやデータベースをモック化し、純粋なビジネスロジックのテストが可能になりました。
変更容易性の確保 レイヤー間の責務分離により、特定層の変更が他層に影響しにくい構造を実現しました。 例えば、データベースをBigTableからSpannerに変更する場合も、リポジトリ層のみの修正で対応できます。
4.2 レイヤー構成と責務
┌─────────────────────────────────────┐
│ Controller Layer │
├─────────────────────────────────────┤
│ UseCase Layer (Business) │
├─────────────────────────────────────┤
│ Domain Layer (Entity) │
├─────────────────────────────────────┤
│ Storage Layer (DB/API). │
└─────────────────────────────────────┘
エンティティ層
- ビジネスの核となるドメインモデル。フレームワークに依存しない純粋なビジネスロジック。
- GREE BizCenの事例 では、純粋なデータ構造としました。複雑なアドフリくんでは、データ構造と付随するビジネスロジックを実装することでUsecaseの肥大化を防ぎました。
ユースケース層
- アプリケーション固有のビジネスルール。エンティティを組み合わせたワークフロー。
コントローラー層
- 外部とのデータ変換。HTTPリクエストのvalidationやレスポンスの形成などを担う。
ストレージ層
- 外部技術の詳細実装。データベース、Webフレームワーク、外部API。
- GREE BizCenの事例 では、pkgとしてアプリケーション外部に切り出しました。アドフリくんではストレージ層を作り、アプリケーション内部に実装しました。ここは好みの問題かと思います。
5. テスト駆動開発の実践
5.1 サービスとUnit Testのセット開発
Red-Green-Refactorサイクル すべてのビジネスロジックをTDDでの実装を目指しました。 以下のサイクルを徹底することで、高品質なコード作成を目指しました。
- Red: 失敗するテストを書く
- Green: テストを通すための最小限の実装
- Refactor: コードの改善とリファクタリング
しかし、実際はサービスコードを書いた後にUnitTestを書き、セットでPRを作る事が多い状況でした。 原因として、テストカバレッジを目標としたため、後から書いても問題無いという認識が広がったことです。 ここについては勉強会等を通じてTDDを普及させていこうと考えています。
6. 開発効率と品質の向上
6.1 チームへの影響
エンジニアのスキル向上
- 設計スキル: DDDとClean Architectureの実践により、設計力が向上
- テストスキル: テスト設計能力が改善
- コミュニケーションスキル: スクラム会議による対話力向上
コードレビューの質の改善 技術的な議論が活発化し、より本質的なレビューが実施されるようになりました。
ナレッジ共有の促進
- 社内Tech Blog投稿: 四半期1記事 → 月2記事
- 技術勉強会: なし → 定期開催
チーム全体の技術レベル底上げとアウトプット文化の醸成を実現しました。
7. 課題と改善点
7.1 導入時の困難
学習コストの高さ 新しい開発手法の習得には相当な時間とエフォートが必要でした。
- DDD理解: ドメインモデリングの考え方習得に2-3週間
- Clean Architecture: レイヤー設計の理解と実装パターン習得に1-2週間
- TDD実践: テストファーストの習慣化は未達成
対策として実施したこと:
- 勉強会での知識共有
- 段階的導入(スクラム → DDD → Clean Architecture → TDD)
段階的導入を行った結果、Clean Architectureまでは実施できましたが、TDDは普及途中です。
7.2 継続的改善への取り組み
チーム文化の醸成 技術的な手法だけでなく、チーム文化の変革にも注力しました。
- 心理的安全性の確保: 失敗を責めない、学習機会として捉える
- 透明性の重視: 進捗・課題・決定事項の可視化
- 顧客価値への集中: 機能実装よりもビジネス価値創出を優先
主観的には導入前に比べると改善しているように感じています。
まとめ
アジャイル開発手法は単なる開発技術ではなく、チーム文化とプロダクト品質を同時に向上させる総合的なアプローチです。 しかし、学習コストが高いため、大きめの開発プロジェクトでないとコストが見合わない可能性があります。 特に当初想定していたTDDは、いまだに導入に至っていないため、更なる改善が可能な状態です。 継続的な学習と改善により、さらなる価値創出を目指していきたいと思います。 この記事が皆様のお役に立てれば幸いです。