Gadenin では、システム設計の考え方としてドメイン駆動設計 (Domain-Driven Design / DDD) を取り入れている。
DDD を採用した理由は、単純に「複雑なシステムだから」ではない。
むしろ大きなきっかけになったのは、AI 駆動開発との相性だった。
Gadenin の開発では、AWS が公開している AI-DLC (AI-Driven Development Life Cycle) の考え方を参考に、まず AI と対話しながら Spec を作り、その Spec をもとに Construction フェーズへ進み、AI に実装を任せるという開発スタイルを取り入れている。
この方法を続けていく中で、一つ重要なことに気づいた。
AI にコードを書かせるのであれば、その前に「AI がどのような世界観でシステムを捉えるべきなのか」を決めておく必要がある。
そこで Gadenin では、その世界観を整理するための枠組みとして DDD を採用した。
全体としては、こういう流れで開発している。
┌──────────────┐
│ 要求 / 課題 │ 「株ごとに時系列で記録したい」
└───────┬──────┘
│ AI と対話しながら言語化 ← AI-DLC / Inception
▼
┌──────────────┐
│ Spec │ ユーザーストーリー / Unit of Work
└───────┬──────┘
│ 概念をシステムの語彙へマッピング ← DDD
▼
┌──────────────┐
│ ドメインモデル │ Entity / Value Object / Domain Service
│ (人間が設計) │ ★ ここが AI に与える「制約」
└───────┬──────┘
│ このモデルの中でだけ実装させる
▼
┌──────────────┐
│ 実装 (AI) │ ← AI-DLC / Construction
└──────────────┘
上から下へ流れているように見えるけれど、実際には Spec とドメインモデルの間を何度も往復する。 そこを人間が握っているかどうかが、この開発スタイルの分かれ目だと思っている。
DDD周りの用語を理解するために
エリック本と呼ばれるド定番の書籍は高価で難しいから、私はこの入門書を皆さんにおすすめしている。非常にわかりやすく実践的な内容になっている。

ドメイン駆動設計において、実践が難しいものは後回しにして、 理解しやすい実装パターンからドメイン駆動設計の世界に 飛び込んでもらうことを目的としています。 そこで初心者にとって、理解しやすい、そして実践しやすいパターンからスタートできるよう、 解説を工夫しています。 またドメイン駆動設計で頻出するパターンの記述方法やその目的も併せて解説しています。
¥3,960 (2026年9月9日 時点の参考価格)
AIにコードを書かせる前に、世界をどうモデル化するか
AI は Spec を渡せばコードを書いてくれる。
しかし、「動くコードを書けること」と「システム全体が一貫した設計になっていること」は別の問題だ。
機能単位で AI に実装を任せ続けると、それぞれの実装自体は正しくても、システム内部で似た概念が別々の方法で表現されたり、機能ごとに異なる言葉が使われたりする可能性がある。
人間だけで開発していても起こる問題だけど、AI によって実装速度が上がるほど、この設計上のブレも高速に蓄積していく。
そこで、
Gadenin というサービスが扱う現実世界を、システム上ではどのような概念として表現するのか
を先に定義することにした。
そのための道具として、DDD の Entity、Value Object、Domain Service といった考え方を利用している。
AI には自由にシステムを設計させるのではなく、定義されたドメインモデルの中で実装してもらう。
これによって、AI による実装を増やしても、コンポーネント内部の設計が散らかりにくい状態を作れるのではないかと考えた。
現実世界とシステムで、同じ言葉を使う
DDD を採用したもう一つの理由が、ユビキタス言語だ。
Gadenin が扱っているのは、家庭菜園やガーデニングという現実世界に存在するものだ。
植物があり、種をまき、苗を植え、育て、肥料を与え、病害虫が発生し、やがて収穫する。
ここには、もともと園芸の世界で使われている言葉がある。
それにもかかわらずシステム内部で独自の用語を作り始めると、
「現実世界では○○と呼んでいるものを、Gadenin 内部では△△と呼ぶ」
という翻訳が必要になる。
できる限りこれを避けたいと考えた。
ユーザーが認識している概念、開発者が会話するときの概念、Spec に登場する概念、そしてコードに登場する概念を可能な限り一致させる。
✕ 翻訳が必要な状態 ○ ユビキタス言語
園芸の世界 「品種」 園芸の世界 「品種」
│ ↕ 翻訳 │
ユーザー 「品種」 ユーザー 「品種」
│ ↕ 翻訳 │
Spec 「バリエーション」 Spec 「Cultivar」
│ ↕ 翻訳 │
コード variant_type コード Cultivar
│ ↕ 翻訳 │
AI ??? AI 迷わない
翻訳が挟まるたびに、人間も AI も解釈を間違える余地が増える。 これは人間同士のコミュニケーションだけでなく、AI にシステムを理解させるうえでも非常に重要だと考えている。
「植物を登録する」とは、どういうことなのか
Gadenin を設計するとき、意外と難しかったのが「植物」の単位だ。
例えばトマトを育てるとして、
- 1 株を 1 つとして管理するのか
- 同じ品種を 3 株植えたら 1 つとして管理するのか
- 種を 10 粒まいた段階では何を 1 つと数えるのか
- 畑で同一品種を一区画に 50 株植えた場合はどうするのか
という問題がある。
家庭菜園だけを考えるのであれば、「植物 1 株 = 1 データ」としてしまうこともできる。
しかし、それでは育苗から始めるケースや、同じ品種を複数株まとめて管理したいケース、さらに農家が一区画単位で管理したいケースでは扱いづらくなる。
そこで Gadenin では、Plant を栽培記録の基本単位として扱うことにした。
Plant は必ずしも「植物 1 株」を意味しない。
1 株のミニトマトを Plant として登録してもいいし、同じ品種を複数株まとめて一つの Plant として管理してもいい。種まきから育苗を開始する場合もあれば、園芸店で購入した苗から栽培を開始する場合もある。
さらに、畑の一区画で同一品種をまとめて栽培する場合には、そのまとまり自体を Plant として扱うこともできる。
つまり Plant は、植物そのものというより、
「ユーザーが一つの栽培対象として継続的に記録する単位」
として定義している。
ここは Gadenin のドメインモデルを考えるうえで、かなりこだわった部分だ。
Plantを中心としたモデル
概念的には、次のような構造になっている。
Plant
「継続して栽培記録する単位」
│
┌────────────────┼────────────────┐
│ │ │
1株 複数株 一区画
│ │ │
ミニトマト1株 同一品種3株 農家の栽培区画
│ │ │
└────────────────┼────────────────┘
│
栽培ライフサイクル
│
┌────────┬───────┼───────┬────────┐
種まき 定植 施肥 病害虫 収穫
重要なのは、現実世界の「植物」という言葉をそのままデータベースの 1 レコードに押し込めるのではなく、Gadenin にとって何をライフサイクルのある Entity として扱うべきなのかを定義したことだ。
そのうえで、株数や栽培方法、栽培開始の形態など、その Entity を説明するシステム固有の値を Value Object として表現していく。
整理すると、こういう住み分けになる。
┌─────────────────────────────────────────────┐
│ Entity — 識別子を持ち、状態が時間とともに変わる │
├─────────────────────────────────────────────┤
│ Plant 栽培対象そのもの │
│ GrowthRecord その日の観察・写真 │
│ WorkLog 施肥・剪定などの作業 │
└─────────────────────────────────────────────┘
▲ 持つ
┌─────────────────────────────────────────────┐
│ Value Object — 不変。値が同じなら同じもの │
├─────────────────────────────────────────────┤
│ PlantName 栽培対象につけた名前 │
│ StartType 種まき / 定植 / 植え替え │
│ Memo 記録に添えた文章 │
│ WeatherSnapshot 記録時の天気と気温 │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Domain Service — どの Entity のものでもない振る舞い │
├─────────────────────────────────────────────┤
│ Plant を消したら、ぶら下がる記録をどう扱うか │
│ といった、複数の Entity にまたがるルール │
└─────────────────────────────────────────────┘
Entity、Value Object、Domain Service の責務を先に整理しておけば、AI が新しい機能を実装するときにも「この値はどこに置くべきなのか」「この振る舞いは誰の責務なのか」という判断基準を持たせることができる。
家庭菜園だけに閉じないモデルにしたかった
もう一つ意識したのが、利用規模によってモデルを作り直さなくて済むことだ。
Gadenin は家庭菜園・ガーデニングからスタートしている。
一方で、「植物を育て、その過程を記録する」という行為自体は家庭菜園に限定されない。
ベランダでミニトマトを 1 株育てる人もいれば、庭で同じ品種を 5 株育てる人もいる。
さらにその先には、畑の一区画を同一品種で管理する生産者もいる。
規模はまったく違うけれど、Gadenin のドメインモデル上では同じ Plant という概念で表現できるようにした。
利用者の規模が変わるたびにシステムの根本的なモデルを作り直すのではなく、同じ概念を使いながらスケールできることを意識している。
Plantを正しく定義すると「人とのつながり」も表現しやすくなる
これは Gadenin にとって特に重要だ。
Gadenin は単なる栽培記録アプリではなく、自分と同じものを育てている人の実際の栽培記録を参考にできることを大きな特徴の一つにしている。
例えば、自分がブルーベリーを育てているなら、同じブルーベリーを育てている人がどのような管理をしているのかを見ることができる。
同じ地域で栽培している人を見つけることもできる。
「自分と同じ地域では、今の時期に何を育てている人が多いのか」
「同じトマトを育てている人は、どんな病害虫に遭遇しているのか」
「その人はどう対処したのか」
「逆に、何をやったらうまくいかなかったのか」
こうした情報は、一般的な栽培マニュアルとは違う価値を持っている。
園芸では気候、地域、品種、栽培環境などによって結果が大きく変わるからだ。
だから Gadenin では、
User
│
├── Plant ── Crop / Cultivar
│ │
│ └── 栽培記録
│
└── Area
↓
同じ作物を育てている
同じ品種を育てている
同じ地域で育てている
↓
他のUser / Plantとのつながり
という関係を自然に表現できることを重視している。
User、Plant、作物、品種、地域、栽培記録といった概念が明確にモデル化されていれば、それらの関係を使って新しい機能を作ることができる。
つまり DDD は、コードを綺麗にするためだけのものではない。
Gadenin が将来どのようなサービスになれるのか、その可能性をドメインモデルとして残しておくための設計でもある。
AI時代だからこそ、設計の「制約」が重要になる
Gadenin で DDD を採用してみて特に感じているのは、AI 駆動開発と DDD の相性の良さだ。
AI によってコードを書くコストは急激に下がっている。
一方で、コードを書くコストが下がったからといって、システムをどう設計するかという問題までなくなるわけではない。
むしろ AI が大量のコードを高速に生成できるようになるほど、
「何をどの概念として扱い、どこに責務を持たせるのか」
という設計上のルールが重要になると考えている。
自由にコードを書ける AI に対して、DDD はある意味では制約になる。
Gadenin では層の構成と依存の向きもあわせて固定していて、新しい機能を足すときの置き場所は、この図でだいたい決まる。
┌──────────────────────────────┐
│ presentation 画面・UI │
├──────────────────────────────┤
│ application ユースケース │
├──────────────────────────────┤
│ domain Entity / VO / │ ← 外側に依存しない
│ Domain Service │ ここが「世界の定義」
├──────────────────────────────┤
│ infrastructure API / DB / 端末機能 │
└──────────────────────────────┘
依存の向き ───────▶ 常に内側 (domain) へ
「この値はどこに置くか」「この振る舞いは誰の責務か」という問いに、 毎回ゼロから答えを考えなくてよくなる。
その制約があるからこそ、AI は既存のシステムと整合したコードを生成しやすくなる。
AI-DLC によって要求から Spec へ落とし込み、DDD によってその Spec をシステム上の概念へマッピングし、そのモデルの中で AI に Construction を任せる。
Gadenin では、この流れを一つの開発プロセスとして育てていきたいと考えている。
グローバル展開しても、同じ「世界」を使えるように
Gadenin は将来的に日本だけではなく、海外への展開も考えている。
もちろん言語や気候、栽培される作物、園芸文化などは国によって異なる。
しかし、
「人が植物を育てる」
「その植物には栽培のライフサイクルがある」
「その過程を記録する」
「同じ作物や地域を通じて、他の人の栽培から学ぶ」
という根本的な概念は大きく変わらない。
だからこそ、UI や言語ごとにシステムを作るのではなく、そのさらに下にあるドメインをきちんとモデル化しておく。
そうすれば、同じドメインモデルの上に日本向けの Gadenin も、海外向けの Gadenin も構築できる。
まだ Gadenin 自体は成長途中だし、ドメインモデルもこれからサービスの成長とともに変わっていくと思う。
ただ、AI によって開発速度を上げるからこそ、その土台となる「世界の捉え方」は人間がしっかり設計する。
それが、Gadenin でドメイン駆動設計を採用した一番大きな理由だ。
この記事は広告を含みます。