設計もマネジメントもカレーづくりで考える「具体⇆抽象」の往復思考法

カレーをかき混ぜるように思考を絶えず攪拌する——「具体⇆抽象」を行き来する思考法についての記事を書きました。
設計から実装、マネジメント、説明の各フェーズで、具体的視点と抽象的視点を行き来する技術がプロジェクトに深い「コク」をもたらす様子を、身近なカレー作りのメタファーでわかりやすく解説しています。
お酒の肴程度に、肩肘張らず気軽にご覧ください。

## TL;DR

![curry-article-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/9a8cacf8-f206-4771-9983-34073d1b72e7.png)

- 「具体 ⇆ 抽象」の往復運動は、ソフトウェア設計・実装からプロジェクト管理、関係者調整まで使える普遍的思考法
- カレー作りのプロセスに例えると、初学者にも直感的に理解できるテクニック
- この記事では「具体⇆抽象」往復の具体的な実践方法とチェックリストを紹介します

## はじめに：「設計もマネジメントもカレー作り」

![curry-intro-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/2512732c-01e4-4547-9d24-ac5afe30fb9b.png)


ソフトウェア開発でもプロジェクトマネジメントでも、最も重要なスキルのひとつが「具体と抽象を行き来する能力」です。これはちょうど、美味しいカレーを作るプロセスに似ています：

- **ルーの種類** = アーキテクチャの選定（Java/Spring? Ruby on Rails? マイクロサービス?）
- **具材** = 機能要件やタスク（ユーザー認証、検索機能、データ保存など）
- **スパイス** = 非機能要件やリスク要素（パフォーマンス、セキュリティ、スケーラビリティ）

カレーの完成イメージを「抽象」、実際の手順や材料を「具体」と考えると、上手く開発を進めるコツが見えてきます。

---

## 具体と抽象とは？

![concrete-abstract-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/ca556058-eb7c-4bf3-8e5c-1c4ecb2e40b0.png)


### 抽象的思考
「今日は欧風ビーフカレーを作ろう」と決めることは、プロジェクトの方向性を定めることに似ています。完成イメージという「抽象」があるからこそ、具体的な作業に意味が生まれます。

### 具体的思考
「玉ねぎ2個をみじん切りにして、弱火で30分炒める」といった手順は、「ユーザーテーブルにこれこれのカラムを追加し、バリデーションを実装する」という具体的なコーディングタスクと同じです。

### レードルの上下運動
カレー鍋をかき混ぜるレードルの動きは、思考の「ズームイン（具体）」と「ズームアウト（抽象）」に例えられます。常に両方を行き来することで、全体と部分の整合性を保ちながら開発を進められます。

```mermaid
graph TD
A[抽象：完成イメージ] <--> B[具体：材料・手順・実装]
A -->|ズームアウト| C[全体の方向性確認]
B -->|ズームイン| D[細部の詰め]
```

---

## 設計フェーズでの往復

### 抽象→具体
1. **ドメインモデル**：「カレーには肉と野菜が入る」というレベル
2. **クラス図**：「Meat」クラスと「Vegetable」クラスの関係を定義
3. **コード実装**：実際のコードに落とし込む

```python
# 具体的なコード
class Curry:
    def __init__(self):
        self.ingredients = []
        self.taste_value = "not cooked"
    
    def add_ingredient(self, ingredient):
        self.ingredients.append(ingredient)
    
    def cook(self):
        for ingredient in self.ingredients:
            ingredient.prepare()
        # 調理ロジックを実行
        self._simmer()
        
        # 食材の組み合わせで味が決まる
        meat_count = sum(1 for i in self.ingredients if isinstance(i, Meat))
        veg_count = sum(1 for i in self.ingredients if isinstance(i, Vegetable))
        
        if meat_count > 0 and veg_count > 0:
            self.taste_value = "delicious"  # 具材のバランスが良い
        else:
            self.taste_value = "needs more ingredients"  # バランスが悪い
    
    def _simmer(self):
        print("弱火でコトコト煮込んでいます...")
    
    def taste(self):
        return self.taste_value

# 抽象化されたインターフェース（Pythonの場合は抽象基底クラス）
from abc import ABC, abstractmethod

class Ingredient(ABC):
    @abstractmethod
    def prepare(self):
        pass
    
    @abstractmethod
    def get_nutrition_value(self):
        pass

class Meat(Ingredient):
    def __init__(self, name, amount):
        self.name = name
        self.amount = amount
    
    def prepare(self):
        print(f"{self.name}を{self.amount}g下処理しています...")
    
    def get_nutrition_value(self):
        return self.amount * 2  # 簡易的な栄養価計算

class Vegetable(Ingredient):
    def __init__(self, name, count):
        self.name = name
        self.count = count
    
    def prepare(self):
        print(f"{self.name}を{self.count}個カットしています...")
    
    def get_nutrition_value(self):
        return self.count * 10  # 簡易的な栄養価計算
```

### 具体→抽象
実装してみると「あれ、玉ねぎと人参で下処理方法が違うな」という気づきが生まれます。これを「野菜の種類によって前処理が異なる」という抽象的なパターンとして認識し、設計に反映します。

カレー比喩でいえば、実際に作ってみて「コクが足りない」と気づき、設計（レシピ）を修正するようなものです。

---

## 実装フェーズでの往復

### TDD（テスト駆動開発）のサイクル

TDD（テスト駆動開発）はカレー作りでいえば：

1. **レシピを読む**：テストを書く（期待する動作を定義）
2. **実際に炒める**：コードを実装
3. **味見**：テスト実行
4. **レシピ修正**：リファクタリング

「ルーを割って入れるタイミング」はリファクタリングポイントと同じです。いきなり全部入れると失敗することがあるように、少しずつ改善を重ねていくことが大切です。

実行例（コンソール出力）：
```
弱火でコトコト煮込んでいます...
beefを200g下処理しています...
onionを2個カットしています...
テストに成功しました: test_curry_should_have_good_taste
```

### TDD（テスト駆動開発）のサイクル

```python
# TDDのサイクル（テスト実行のプロセス）
import unittest

class CurryTest(unittest.TestCase):
    def test_curry_should_have_good_taste(self):
        # Arrange：準備（材料を用意）
        curry = Curry()
        curry.add_ingredient(Meat("beef", 200))
        curry.add_ingredient(Vegetable("onion", 2))
        
        # Act：実行（調理）
        curry.cook()
        
        # Assert：検証（味見）
        self.assertEqual("delicious", curry.taste())

if __name__ == "__main__":
    unittest.main()
```

---

## プロジェクトマネジメントでの往復

### 抽象レベル
マイルストーン：「今日中に煮込み完了」「今週中にベータ版リリース」

### 具体レベル
タスク：「13時までに玉ねぎを炒める」「明日までにログイン機能を実装」

ガントチャートを「煮込みタイマー」に見立てると、進捗管理の説明が直感的になります。「カレーは弱火でコトコト」がプロジェクトの「少しずつ着実に」に対応します。

```bash
# プロジェクトWBS例（カレー風）
├── 準備フェーズ（食材の買出し）
│   ├── 要件定義（どんなカレーにするか決める）
│   └── 環境構築（鍋や調理器具の準備）
├── 開発フェーズ（調理）
│   ├── 下ごしらえ（設計）
│   ├── 炒め工程（コア機能実装）
│   └── 煮込み（統合テスト）
└── リリースフェーズ（盛り付け）
    ├── デプロイ（皿に盛る）
    └── 運用開始（いただきます。）
```

---

## 関係者説明での往復

![stakeholder-communication-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/ab1b056b-c0a9-4372-ba70-1b01251c6038.png)

ソフトウェア開発において、技術者とビジネス側のステークホルダーとのコミュニケーションは常に課題です。ここでも「具体⇆抽象」の往復が役立ちます：

### "食レポ"（経営層・顧客向け抽象説明）
「このシステムは堅牢なセキュリティと直感的なUI、柔軟なスケーラビリティが特徴です」

これはカレーで言えば：「このカレーは深いコクと程よい辛さが特徴で、素材の旨味を引き出しています」

### "レシピ"（開発者向け具体説明）
「認証システムはJWTベースで、UIコンポーネントはReactの再利用可能なパターンに基づき、インフラはKubernetesでオートスケールします」

これはカレーで言えば：「玉ねぎ2個をきつね色になるまで弱火で40分炒め、そこにカットトマト1缶を加えて...」

### ソフトウェア開発での実践
異なるステークホルダーごとに説明の「粒度」を調整することは、カレーの「辛さ」や「具材の量」を調整するようなものです：

- **経営層向け**：ROI、市場優位性、リスク軽減（＝カレーの完成イメージと味わい）
- **プロジェクトマネージャー向け**：スケジュール、リソース、機能セット（＝調理時間と主要材料）
- **開発者向け**：実装詳細、技術的制約、コード構造（＝具体的な調理手順と調味料）
- **QA向け**：テスト条件、想定シナリオ（＝試食ポイントと味のチェック項目）

同じプロダクトの説明でも、聞き手によって抽象度を調整することで、各関係者が自分の役割において必要な情報を適切に得られるようになります。これはまさに料理人がお客様には「味の特徴」を、修行中の弟子には「火加減と手順」を説明するのと同じです。

---

## 実践チェックリスト

- [ ] 高レイヤ構成図⇆クラス図を行き来したか
- [ ] タスク分解がWBSと整合しているか
- [ ] 日次ふりかえりで抽象レベルに戻る時間を確保したか
- [ ] 関係者に合わせた説明粒度を用意したか
- [ ] 定期的に「味見」（レビュー）を行っているか

---

## まとめ：今日のカレーは明日の設計をうまくする

具体と抽象の往復を習慣化することは、毎日の「味見」のようなものです。この習慣があれば、どんなプロジェクトも理解しやすく、管理しやすくなります。

カレーをかき混ぜるように、思考も「具体」と「抽象」をまんべんなく攪拌することで、設計もマネジメントも"コク深い"仕上がりになるのです。

![curry-stirring-animation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/798e09e0-c574-48b7-82a0-a7ed4f656ac4.png)

## 免責事項
本記事の作成にあたり、文章や図解の生成にClaude Sonnetを、ファクトチェックにChatGPTを活用しました。最終的な編集と確認は筆者が行っています。