VSEA: 新しい開発手法で業務アプリを爆速開発した実践記録
はじめに
業務効率化アプリケーションの開発で、新しい開発手法「VSEA (Vertical Slice Evolutionary Architecture)」を実践しました。この記事では、その実践記録と得られた知見を共有します。
開発したもの
スケジュール自動登録システム
- CSVファイルからスケジュールデータを読込み、CMSに自動登録
- スタッフマスタ照合、週単位登録、エラーハンドリング
- Python + tkinter + Playwright
- 開発期間: 1日(実働8時間)
VSEAとは?
VSEA (Vertical Slice Evolutionary Architecture)は、機能を縦に切って段階的に実装していく開発手法です。
基本コンセプト
従来のレイヤー分割(横割り):
[UI層] → [ビジネスロジック層] → [データ層]
問題: すべての層が完成しないと動かない
VSEAの縦スライス(縦割り):
[機能A: UI→ロジック→データ] (完結)
[機能B: UI→ロジック→データ] (完結)
[機能C: UI→ロジック→データ] (完結)
利点: 各スライスが独立して動作可能
フェーズ構成
フェーズ①: UX整合設計
- ユーザーストーリー定義
- 画面遷移設計
- エラーケース特定
- GUIモックアップ作成
フェーズ②: 共通スケルトン作成
- 各モジュールのインターフェース定義
- 最小限の実装で全体像を作成
フェーズ③: 縦スライス実装
機能単位でend-to-endに実装:
- Slice 1: CSV読込 + GUI表示 + 検証
- Slice 2: スタッフマスタ取得(Webスクレイピング)
- Slice 3: スケジュール登録(ブラウザ自動化)
- Slice 4: 不一致対応ダイアログ
フェーズ④: 肉付け
- 検証強化
- エラーハンドリング
- UX改善
実践で分かったVSEAの威力
1. 常に動くものがある安心感
各縦スライスがend-to-endで動作するため、いつでもデモ可能な状態を維持できました。
# Slice 1完了時点で、すでにこれが動く
csv_data = csv_reader.read("schedule.csv")
csv_reader.validate(csv_data)
gui.display_validation_result(result)
従来手法だと「全部実装し終わるまで動かない」問題がありますが、VSEAではそれがありません。
2. 問題の早期発見
実例として、Slice 3実装中にログイン処理のタイミング問題を発見しました。
問題: フォーム入力が早すぎてログイン失敗
# 修正前(失敗)
page.goto(login_url)
page.fill('input[name="login_id"]', self.login_id) # ページ未準備
page.click('button:has-text("ログイン")')
# 修正後(成功)
page.goto(login_url)
page.wait_for_load_state("networkidle")
page.wait_for_selector('input[name="login_id"]', timeout=10000) # 要素待機
page.fill('input[name="login_id"]', self.login_id)
page.wait_for_timeout(500) # 入力確定待機
page.on("dialog", lambda dialog: dialog.accept()) # モーダル対応
page.click('button:has-text("ログイン")')
page.wait_for_timeout(1000) # モーダル処理待機
このような問題がSlice 3完了時点で発見できたため、後工程への影響を最小化できました。
3. 要件変更への柔軟な対応
開発途中で「週単位でURL遷移したい」という要件変更が発生しました。
当初の想定: 「次の週へ」ボタンをクリック
問題: ボタンクリックで入力がリセットされる
新要件: URLパラメータで週指定
# 新実装: 週単位URL直接遷移
def get_schedule_url(self, staff_id: int, week: int = 1) -> str:
if week == 1:
return f"{self.schedule_base_url}?id={staff_id}&p=1"
else:
return f"{self.schedule_base_url}?id={staff_id}&p=1&w={week}"
既存のSlice 1, 2を一切変更せず、Slice 3の改善として対応できました。これがVSEAの柔軟性です。
4. 段階的な複雑性増加
各スライスで徐々に複雑な処理を追加していきました。
Slice 1: CSV読込(pandas) → 比較的シンプル
Slice 2: Webスクレイピング(BeautifulSoup) → ページネーション対応
Slice 3: ブラウザ自動化(Playwright) → 非同期処理、待機制御
Slice 4: ダイアログUI(tkinter) → 状態管理
各段階で学習曲線が緩やかになり、技術的負債を最小化できました。
開発タイムライン
実際の開発時間配分を公開します。
| フェーズ | 時間 | 主な成果 |
|---|---|---|
| ① UX整合設計 | 30分 | ユーザーストーリー6件、画面遷移フロー、エラーケース5件 |
| ② スケルトン作成 | 30分 | 4モジュールのインターフェース定義 |
| ③-1 Slice 1 | 1.5時間 | CSV読込・検証・GUI(540件処理成功) |
| ③-2 Slice 2 | 1時間 | スタッフマスタ取得(103名取得成功) |
| ③-3 Slice 3 | 2時間 | Playwrightスケジュール登録(dry_run成功) |
| ③-4 Slice 4 | 30分 | 不一致対応3択ダイアログ |
| ④ 肉付け | 1.5時間 | 週単位ロジック、検証強化、UX改善 |
| パッケージング | 30分 | PyInstaller、README、技術仕様書 |
| 合計 | 8時間 | 実稼働可能なアプリ完成 |
たった**1日(実働8時間)**で完成しました。
VSEAと他手法の比較
vs ウォーターフォール
| 項目 | ウォーターフォール | VSEA |
|---|---|---|
| リスク管理 | 最後まで動かない | 常に動くものがある |
| 変更対応 | 大規模リファクタリング | 追加改善で対応 |
| フィードバック | 後工程で発覚 | 各スライスで即座に |
| 心理的安全性 | 低い(不確実性高) | 高い(常に進捗確認可) |
vs アジャイル/スクラム
似ている点:
- 反復的開発
- フィードバック重視
- 段階的な価値提供
VSEAの独自性:
- 縦スライスの概念: 技術層ではなく機能単位で切る
- フェーズ構成: UX設計→スケルトン→縦スライス→肉付け
- 進化的アーキテクチャ: 各スライスが独立しつつ、全体として進化
VSEAはアジャイルの具体的な実装手法として位置づけられます。
実装時のポイント
1. スライスの粒度
各スライスは1-2日で完了するサイズが最適でした。
良い例:
- Slice 1: CSV読込 + GUI表示 + 検証(1.5日)
- Slice 2: スタッフマスタ取得(1日)
悪い例:
- Slice X: 全機能を一気に実装(5日) → 大きすぎる
- Slice Y: ボタン1個追加(0.1日) → 小さすぎる
2. 依存関係の管理
Slice間の依存関係を明示的に管理しました。
Slice 1 (独立)
↓
Slice 2 (独立)
↓
Slice 3 (Slice 1, 2に依存)
↓
Slice 4 (Slice 1, 2, 3に依存)
依存関係が少ないスライスから実装すると、並行開発の余地が生まれます。
3. インターフェース駆動開発
フェーズ②で各モジュールのインターフェースを定義したことで、実装がスムーズでした。
# フェーズ②で定義
class CSVReader:
def read(self, filepath: str) -> pd.DataFrame:
pass
def validate(self, df: pd.DataFrame) -> bool:
pass
# フェーズ③で実装
class CSVReader:
def read(self, filepath: str) -> pd.DataFrame:
# 実装...
return df
def validate(self, df: pd.DataFrame) -> bool:
# 実装...
return True
インターフェースが確定していたため、他モジュールとの連携がスムーズでした。
苦労した点と解決策
1. ログイン処理のタイミング制御
問題: Playwrightでフォーム入力が早すぎてログイン失敗
解決策:
-
wait_for_selector()で要素待機 -
wait_for_timeout()で適切な待機時間追加 - モーダルダイアログの事前ハンドラー設定
2. 日付フォーマットの不一致
問題: CSV日付がYYYY/MM/DDだが、コードはYYYY-MM-DDを期待
解決策:
# 柔軟な日付パース
date_str = schedule['date']
if '/' in date_str:
schedule_dt = datetime.strptime(date_str, '%Y/%m/%d')
else:
schedule_dt = datetime.strptime(date_str, '%Y-%m-%d')
3. 深夜帯時間の扱い
問題: 20:00-1:30のような翌日にまたがる時間
解決策:
# 退勤時間が出勤時間より小さい場合は翌日扱い(+24時間)
if leave_hour < going_hour or (leave_hour == going_hour and leave_min < going_min):
leave_hour += 24
これらの問題は各スライスの実装中に早期発見できたため、修正コストが最小限でした。
VSEAの改善点
実践を通じて見えてきた改善の余地:
1. テスト自動化との統合
各スライス完了時にユニットテストを追加すれば、リグレッション防止がより強固になります。
提案: VSEA + TDD
Slice 1: テスト作成 → 実装 → テスト成功
Slice 2: テスト作成 → 実装 → テスト成功
...
2. フェーズ④の明確化
「肉付け」という表現が曖昧だったため、より具体的な定義が必要:
- 検証強化フェーズ
- エラーハンドリングフェーズ
- UX改善フェーズ
3. ドキュメント生成の自動化
各スライス完了時に自動的にドキュメントを生成する仕組みがあれば、さらに効率的です。
まとめ
VSEAの強み
- リスク管理: 常に動くものがある安心感
- 早期フィードバック: 問題の早期発見と修正
- 柔軟性: 要件変更への対応力
- 段階的学習: 複雑性の段階的増加
適用シーン
VSEAが特に有効なケース:
- 業務アプリケーション開発
- 要件が流動的なプロジェクト
- 小〜中規模チーム(1-5人)
- 技術的負債を最小化したい場合
次のステップ
VSEA + 以下の組み合わせで、さらなる進化が期待できます:
- TDD: 品質向上
- CI/CD: 自動デプロイ
- ドメイン駆動設計: より良い境界設定
- マイクロサービス: 各スライスの独立性向上
おわりに
VSEAは実用的で効果的な開発手法であることが実証されました。特に業務アプリケーション開発において、リスクを最小化しながら高速に価値を提供できる手法です。
今後、より多くのプロジェクトでVSEAを実践し、ノウハウを蓄積していきたいと思います。
質問やフィードバックがあれば、コメント欄でお待ちしています!
Discussion