
Lean Architecture(リーン・アーキテクチャ)は、「Lean(リーン)=無駄をなくす」という思想に基づいたアーキテクチャ設計手法です。
トヨタ生産方式(Lean Manufacturing)の原則をソフトウェア開発に応用した考え方なんです。
「必要なものを、必要なときに、最小限で作る」ことを目的とします。
Clean Architecture や Hexagonal Architecture のような厳密な構造よりも、"軽量・実用・継続改善"を重視するアプローチです。
基本思想
Lean Thinkingの5原則
1. 価値(Value)
顧客が価値を感じるものだけを開発する。
2. バリューストリーム(Value Stream)
価値が生まれる流れを明確にし、全体を最適化する。
3. フロー(Flow)
作業を途切れさせず、スムーズに進むようにする。
4. プル(Pull)
必要になったときに必要な作業をする(やりすぎ禁止)。
5. 完璧(Perfection)
継続的に改善し、無駄を減らしていく。
基本原則
1. YAGNI(You Ain’t Gonna Need It)
まだ必要でない機能や構造は作らない。
2. KISS(Keep It Simple, Stupid)
シンプルさは最強の防御。理解・修正・再利用を容易に。
3. Fast Feedback(高速フィードバック)
ユーザーやテストから早く学び、設計を即座に修正。
4. Decouple Everything(疎結合化)
コンポーネントを独立させ、変更の影響を局所化。
5. Continuous Evolution(継続的進化)
初期から完璧を目指さず、進化しやすい構造を採用。
6. Empowered Teams(自律的チーム)
アーキテクチャを管理するのは、組織の層ではなく開発チーム自身。
Lean Architectureの特徴
・明確な「層構造」ではなく、価値提供に基づく柔軟な構成を目指す。
・コード構造よりも、**フローと改善サイクル(PDCA)**を重視。
・「アーキテクチャを守る」より、「価値を素早く届ける」を優先。
・ドメイン駆動設計(DDD)やマイクロサービスと相性が良い。
構造イメージ(概念図)
実践アプローチ
アーキテクチャの段階的進化
最初から完璧を目指さず、小さく構築してリファクタ。
自動テスト・CI/CD
無駄な手動作業を排除してフィードバックを高速化。
計測と改善
実装よりも「学習サイクル」を早める。
チーム全体で設計判断を共有
アーキテクトだけでなく、開発者全員が設計に責任を持つ。
メリット
・変化に強く、ビジネス要求に即応できる。
・アーキテクチャ設計のオーバーヘッドが少ない。
・チーム全体が改善サイクルを意識して動ける。
・継続的デリバリーとの親和性が高い。
デメリット
・構造を軽くしすぎるとスパゲッティ化のリスクがある。
・「最小限」を誤解すると品質軽視になりがち。
・ドキュメント不足や属人化の危険もある。
他アーキテクチャとの関係
| アーキテクチャ |
主眼 |
特徴 |
| Layered |
責務の階層分離 |
上下構造で明確 |
| Hexagonal |
技術依存分離 |
ドメイン中心 |
| Clean |
層+依存制御 |
原則重視の厳格設計 |
| Lean |
無駄の排除と継続改善 |
柔軟・実践志向 |
サンプルコード
Lean Architectureの思想を反映した最小構成のToDoアプリを、JavaScriptで実装してみましょう。
目的は「軽量で進化可能」な構造を示すことです。
つまり、最初は小さく・分離可能な構成にして、後からHexagonalなどに発展できるようにします。
ファイル構成
src/
├─ index.js // エントリーポイント
├─ app/
│ ├─ TodoService.js // アプリケーションロジック
│ └─ Todo.js // ドメインモデル
├─ infra/
│ └─ LocalStorageRepo.js // インフラ層(DB代わり)
└─ ui/
└─ consoleUI.js // プレゼンテーション層(UI)
1. ドメイン層:Todo.js
// src/app/Todo.js
export class Todo {
constructor(id, title, done = false) {
this.id = id;
this.title = title;
this.done = done;
}
toggle() {
this.done = !this.done;
}
}
2. アプリケーション層:TodoService.js
// src/app/TodoService.js
export class TodoService {
constructor(repo) {
this.repo = repo; // 抽象的なリポジトリ(LocalStorage, APIなど差し替え可能)
}
getAll() {
return this.repo.load();
}
add(title) {
const todos = this.repo.load();
const newTodo = { id: Date.now(), title, done: false };
todos.push(newTodo);
this.repo.save(todos);
return newTodo;
}
toggle(id) {
const todos = this.repo.load().map(todo => {
if (todo.id === id) todo.done = !todo.done;
return todo;
});
this.repo.save(todos);
}
remove(id) {
const todos = this.repo.load().filter(todo => todo.id !== id);
this.repo.save(todos);
}
}
3. インフラ層:LocalStorageRepo.js
// src/infra/LocalStorageRepo.js
export class LocalStorageRepo {
constructor(key = 'todos') {
this.key = key;
}
load() {
return JSON.parse(localStorage.getItem(this.key) || '[]');
}
save(data) {
localStorage.setItem(this.key, JSON.stringify(data));
}
}
4. UI層:consoleUI.js(最小限のUI)
// src/ui/consoleUI.js
import { TodoService } from '../app/TodoService.js';
import { LocalStorageRepo } from '../infra/LocalStorageRepo.js';
const service = new TodoService(new LocalStorageRepo());
console.log("=== Lean ToDo App ===");
service.add("学習する");
service.add("休憩する");
console.table(service.getAll());
service.toggle(service.getAll()[0].id);
console.table(service.getAll());
service.remove(service.getAll()[1].id);
console.table(service.getAll());
実行方法(ブラウザまたはNode.js)
node src/ui/consoleUI.js
Lean的なポイント
・最初はLocalStorageだけ(シンプルスタート)
・依存注入で拡張可能(APIやDBへ進化)
・レイヤー分割は最小限(理解しやすく、変更容易)
・無駄な抽象化を避け、必要になった時に導入
あとがき
かなり複雑に感じる人は、サンプルコードの内部構造を見るだけでも参考になると思います。
このLean Architectureというデザインパターンは、哲学のようなもので、冒頭に書いた「無駄をなくすデザインパターン」を理解しましょう。
単なる「軽い構造」ではなく「変化に強く、無駄を排除し、価値を最大化する設計哲学」です。
「すぐ作れる構造」ではなく「すぐ変えられる構造」を設計する事が重要で、初期は単純な構成(例:単一サービス+DB)でもOK。
スケールが必要になったら、責務ごとにモジュールを分割すれば良いんです。
大規模化の段階で、必要なパターン(DDD, Hexagonalなど)を導入するという意識しながら学習して構築していく、思考的なデザインパターンですね。
0 件のコメント:
コメントを投稿