社内制度で学ぶドメイン駆動設計
はじめに
こんにちは、キャベたまご と みみぞう です。
今回は、キャベたまごが社内制度の「技術トレーニング」を通してドメイン駆動設計を学んだ体験を対談形式で紹介します。
対象の読者
ドメイン駆動設計を勉強したことがある人
ドメイン駆動設計の学習方法に興味のある方
ナビタイムジャパンの社内制度に興味のある方
用語の紹介
技術トレーニング (以下、技トレ)
ナビタイムジャパンの社内制度のひとつ。トレーニーのスキルアップのために、個別に目標、育成手法を設定し、トレーナーと1対1で実施して、技術力を高める制度です。
ドメイン駆動設計 (以下、DDD)
Eric Evans氏が「Domain-Driven Design: Tackling Complexity in the Heart of Software」にて唱えた開発手法。モデリングによってソフトウェアの価値を高めることを目指すもの。
登場人物の紹介
🥚キャベたまご (トレーニー)
新卒2年目のエンジニア (学生時代は未経験)
カーナビアプリのBFF開発をしている
昼食はだいたいキャベツとゆでたまご
🦉みみぞう (トレーナー)
新卒13年目のエンジニア
システムや開発環境、チームの改善業務を担当
アプリ開発・Web開発・API開発・データ開発など一通りの経験あり
はじめに
みみぞう: 4ヶ月間の技トレお疲れさまでした。終わってみての感想をお願いします。
キャベたまご: 技トレ開始前よりも、DDDに対する理解が広がったと思います。一方で、まだまだ理解が足りないとも感じています。
みみぞう: どのような部分が足りないと感じていますか?
キャベたまご: DDDという概念や、そのあるべき形はある程度理解できたと思っています。ただ、実際の業務で実装できるかと言われるとまだまだかなと。
みみぞう: 設計や実装は勉強だけでなく、経験も大事ですからね。
キャベたまご: 「経験も大事」と話されましたが、設計手法を学ぶ際に意識していることはありますか?
みみぞう: 学んでから体験するのではなく、体験してから学ぶようにしていますね。私の場合、どうしても体験していないことを学ぶのが苦手な節がありまして…。開発で悩みに遭遇して調べた後、自身の考えと答え合わせするように学習することが多いです。
キャベたまご: 確かに、いきなり正解を知るよりも、一度失敗やアンチパターンと言われるようなものを踏んでおいたほうが、その効力がより理解できそうですね!設計に問わず、他の学習にも言えそうです。
みみぞう: それでは、時系列順に振り返っていきましょう。
技トレに申し込むまでの話
みみぞう: 技トレを受ける前に、DDDの経験はありましたか?
キャベたまご: 配属後にチームメンバから推薦された『ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本』を読み、DDDに基づいたBFFの開発も半年ほど経験していました。
キャベたまご: ただ、それ以前の開発経験がほぼ無かったのと、知識不足もあり、あまり理解できなかったです。
みみぞう: ドメイン駆動設計は様々な知識が必要となる高度な概念のため、開発を始めてすぐでは難しいと思います。私も7年目に初めて学習したときは理解できませんでした。その後、『ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本』の著者の方が公開されていたスライドを見て、初めて理解できたという経緯があります。ですので、初めてDDDを学ぶ方には必ず『ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本』をオススメするようにしていますね。
キャベたまご: そんなに難しい概念だったんですね…。それでも、既存の実装と似た部分は、それを参考に業務は進められていたと思います。ただ、既存と異なるタイプの実装が必要になると応用が利かず、本質的なDDDの理解が必要だなと感じていました。
みみぞう: その流れで技トレに申し込んだのですか?
キャベたまご しばらくは自分で調べたりしていたのですが、それでも理解できていない部分が多く、自分一人では解決できなそうだなと悩んでいたところ、ちょうどSlackで技トレの案内が流れてきたので、即申し込みました!
みみぞう: 行動力があっていいですね! 私も以前にDDDのnoteを書いたり、社内でDDDを推進していたのもありお声がけしてもらったので嬉しかったです。
↑ (以前に書いたnoteの記事)
題材選定の話
キャベたまご: 申し込んだ当時は、実際に開発現場で使用していたDDDに基づいたプロダクトコードを使おうと思ってました。
みみぞう: プロダクトコードの理解から始めましたね。初めはそれでいいかと思ったのですが、プロダクトコードにはDDD以外の要素も多かったのでノイズになりそうだと思いました。たとえばフレームワークやORMがそれにあたります。それならいっそのこと1からDDDベースの設計で何か作ってもらった方がいいなと。以下2つの条件を満たす題材を考えてもらいました。
みみぞう/キャベたまご の両方がドメインエキスパートになれる
ある程度複雑なドメインである
キャベたまご: 6つほど候補を出したのですが、1と2のバランスをとって『RPGの戦闘』を題材に決定しました。
みみぞう: 『割り勘』っていう題材もありましたが、単純そうだったので却下しましたね(笑)
モデリングの話
みみぞう: まずはユビキタス言語の洗い出しをして、それからドメインモデルの定義を始めました。まずは用語の説明、特に値オブジェクトとエンティティは使い分けが難しいので、しっかり理解してもらうようにしました。
キャベたまご: そこで得た知識を使って、戦闘画面の画像からモデルの定義を始めましたね。
みみぞう: 実際にドメインモデルを定義してみてどうでしたか?
キャベたまご: モデルの抽出は比較的スムーズにできた気がするのですが、そのモデルが値オブジェクトなのかエンティティなのかを決めるのが難しかったです。
みみぞう: 値オブジェクトとエンティティの使い分けは、ある程度経験を詰んでいても難しいと思います。同じモデルでも考え方が異なるだけで、どちらを使うべきかが変わることもあります。
みみぞう: 一番難しいと感じたモデルはなんでしたか?
キャベたまご: Enemy ですね。はじめは敵が1体しか出ない前提だったので、敵の種族を Enemy としていました。たとえば、デーモンなら id = demon といった感じです。
みみぞう:一見、問題なさそうですね。
キャベたまご: ただ、これだと敵が複数出現するように仕様変更した場合に対応できないことに気づきました。デーモンが3匹出現した場合、どのデーモンも id = demon となってしまい、戦闘中の敵を特定できません。
キャベたまご: そこで、Enemy とは別に Target というモデルを追加し、エンティティとして実装しました。
みみぞう: Enemy と Target が分離されたことによって、戦闘中のステータス変動も扱いやすくなりましたね。たとえば、攻撃力が2倍になるような魔法があった場合、 Target の strength を2倍すればいい。Enemy だけで実現するならば、strength の他に initialStrength みたいな基準値が必要となり、モデルも複雑になるところでした。
キャベたまご: ドメインエキスパートとの対話の重要性を体感した場面でした。
みみぞう:私は当初、 Enemy モデルは Target のような役割だと思っていたので、モデリング時点で認識あわせられて良かったです。このような作業を通じて、ドメインエキスパートと認識をあわせつつ、一体感を持って開発に取り組むことは、気持ちの面でも大切ですね。
実装の話
みみぞう: 今回のトレーニングでは、以下のようなフローを何度か反復する形式をとってみました。
ドメインエキスパート(みみぞう)と会話し、定義したユビキタス言語をMiroに可視化する
1をベースにKotlinでコードを実装する
このやり方はどうでしたか?
キャベたまご: DDDの効力を体感的に学ぶ上で非常によかったと思います。特に、実装とモデルのずれに気づきやすかった点が良かったのかなと思います。例えば、定義していない言葉が実装で出現した時に、モデリングの不足に気づいて、一旦モデリングに立ち戻れたことがありました。 また、Miroにまとめた内容自体がモデル兼仕様書であったので、Miroを見れば、どのように実装を進めていけば良いのか想像しやすく、スムーズに実装を進められた点でも、DDDの良さを学びました。
キャベたまご: 少し話が逸れるのですが、1.のモデリング時に印象的だったこととして、ドメインオブジェクトの名前を日本語と英語の対応を明記して付けるようにアドバイス頂いたことがあったのですが、この点について何かお考えがあるのですか?
みみぞう: ユビキタス言語の使用を徹底してもらうためですね。コーディングするときは英語の名前を使いますが、ここで英語のユビキタス言語がないと、後で認識がずれやすくなります。はじめから日本語と英語を定義しておけば、開発時もそのまま英語名が使える。お互い嬉しいわけです。
キャベたまご: モデリングが完了した時点で命名作業も完了しているので、名前を考える時間が抑えられ実装に集中しやすかったです。
みみぞう: 開発チームと扱うドメインによっては、テストコードを日本語で書いた方が分かりやすい場合もあります。文字数も抑えられますしね。
// 英語の場合
class BattleFunctionTest {
@Test
fun multiTargetHealingMagicOnlyHealsPlayersWhoAreEnabledToFight() {
// 省略
}
}
// 日本語の場合
class BattleFunctionTest {
@Test
fun 全体回復魔法は戦闘不能ではないプレイヤーのみHPを回復する() {
// 省略
}
}
キャベたまご: その発想はなかったです💡!!DDDの利点の話に戻るのですが、しっかりモデリングすると、仕様と実装のずれに気づきやすいため、DDDで実装されたコードはレビューがしやすいのでは?と感じました。
みみぞう: 過去にDDDで開発して引き継いだプロダクトをレビューすることが多いのですが、それはとても感じています。当初そこまで考えていなかったのですが、DDDを導入して本当に良かったと思ったことの1つです。
キャベたまご: やはり、レビューしやすさという恩恵も得られるのですね!あと、仕様が変更しやすいとも思いました。具体的には、戦闘にゲーム性を持たせるために、命中確率( Accuracy )という値オブジェクトを追加したのですが、Miroで迷いなくモデルを追加でき、実装もそのままスムーズにできたことはちょっと感動しました。
技トレを通じて学んだこと
みみぞう: 今回の技トレを通じて、学んだことはあります?
キャベたまご: まず、DDDの威力やどう有るべきかについて体感的に学べました。同時にDDDに付随する、アーキテクチャ、オブジェクト指向等々への理解が深まったことは嬉しい誤算でした。
みみぞう: DDDをコードに反映させるには、前提として必要なスキルがいくつかありますからね。設計以外にも、ドメインエキスパートとのコミュニケーションをとる能力、ドメインをドキュメントとして管理する能力なども必要だと思います。
キャベたまご: DDDに関係しないことでも多くの学びがありました。みみぞうさんのプログラミング自体や学習についてなどの考え方、Vimについて学べたことも現在の開発スタイルに大きく影響しています。
みみぞう: 多くの学びがあったようで嬉しく思います。逆に課題と感じたことはありますか?
キャベたまご: 実装スキルがまだまだ足りないことでしょうか。今、DDD以外にも、設計周りを積極的に学習しているのですが、実装との両輪で学ばないといけないんだなと痛感しています。上司からも指摘されたことなのですが、『すべての局面でいいコードを書き続けられたら理想だが、実際はそうもいかない。 そのようなコードに直面したときは、それがダメであることを指摘するだけでなく、なぜそのようなコードになってしまったのかを考え、都度対応していく力が必要になる』という言葉が頭に残っています。
みみぞう: それは同感です。当初は優れた設計の下、綺麗に書かれていたコードが、数年後に面影をなくしてしまうケースは度々目にしてきました。ただ、このようなケースは成功したプロダクトによくある傾向だと思います。私も個人プロダクトで同様の体験をしましたが、機能追加が面白すぎて、コードの綺麗さなどどうでもよくなってしまうんですよね😅
キャベたまご: よくあることなのですね...それを減らすためにオススメの学習の仕方などあったりしないですかね...汗
みみぞう: その経験をするまでの私は今より完璧主義だったと思います。ただ、先の経験を通じて、今動いているコードの背景を以前より推測できるようになりました。なので、自分で開発したものを数年継続してメンテすることは非常にオススメです。ユーザーがいて、機能追加をし続けられるようなプロダクトで...ですね。プロダクトの大小はそこまで関係ないので、ちょっとしたツールでもいいと思います。
キャベたまご: 数年継続したプロダクト開発...ハードル高そうですが、ぜひやってみたいです。理論を学ぶだけでなく、自分自身でしっかりアンチパターンを経験しておくことが設計を真に理解する上で重要なのかもしれないですね。
みみぞう: 仕事だとなかなか機会がないと思うので、個人開発の方がやりやすいですね。自分で作りたいものがある方には特にオススメしています。
技トレ制度の有意義さ
みみぞう: 今回、初めて技トレを利用したと思いますが、この制度はどうでしたか?
キャベたまご: とっても有難い制度だと思います。今回、週1の1時間で対面のペアプロ形式でやらせていただきましたが、若手からすると『ベテランエンジニアの時間を合法的に確保できる機会』はなかなかないので、普段の業務で上司の時間を確保するよりは心理的なハードルが低いように感じました。
みみぞう: 直属の上司の時間をたくさん確保するのは気が引けてしまうかもしれませんね。特に、新卒配属直後は業務を遂行することで精いっぱいになると思うので、自発的に新しい分野を開拓しようとする余裕もないでしょうし...。
キャベたまご: 確かに目の前の業務で精一杯だったので、設計までじっくり学習する余裕はなかったと思います。 ただ、余裕がないからこそ、業務と切り離した時間で理解にじっくりと時間をかける機会をいただけるのは有難く、積極的に利用した方が良いなと思いました。
みみぞう: キャベたまごさんと同じ新卒2年目の猫じゃらし太郎さんも、技トレ制度を活用していましたね。ベテランエンジニアとしても、若手と共有できる機会は貴重ですし、楽しみにしている人も多いと思いますので、遠慮せずに有効活用してもらえると嬉しいですね。
トレーナーとしての感想
キャベたまご: 今回、トレーナーをされていて感じたことはありますか?
みみぞう: DDDのモデリングから実装まで、リアルなシミュレーションを通じて人に教えることは初めてだったのでいい経験になりました。特に、ドメインエキスパートとの会話を通じてユビキタス言語を決めていくことの重要性を、繰り返し伝えられたのが良かったです。
キャベたまご: 今回のようなやり方が初めてというのは意外でした! それ以外の観点ではいかがでしたか?
みみぞう: 他には...Kotlinの勉強にもなりました。普段Kotlinを書かないので、逆にキャベたまごさんに教えてもらったり、一緒に調べたりと。お互いスキルアップできる機会は貴重なので楽しかったです。それと、DDDとは関係ないのですが、Vimの話題も出てきましたね。
キャベたまご: アウトプットの速度をあげるためには...という話題でお話しした時に出てきた気がしますね。Vimの存在自体は知っていたのですが、その効力については半信半疑な部分がありました。今となってはもっと早く実践していればと思います...汗
みみぞう: 慣れていないにも関わらず、モブプロ中も諦めずにVimキーバインドで操作し続けてくれましたね。すぐ諦めてしまう人が多いので、とても嬉しく思いました。あ、私からは一切強制はしていませんよ? (笑)
キャベたまご: 生まれたての小鹿のごとくおぼつかない操作を優しく見守っていただいて感謝です(笑)。おかげさまで、すっかり虜です。トレーニングを終えた、今でも開発でVimのキーバインドや機能を使っています。
みみぞう: 操作にはなれましたか?
キャベたまご: 全然です....まだまだVimmerへの道のりは長いですね...汗
みみぞう: Vimについては以前にnoteを書きましたので、そちらも参考にしてみてください。キャベたまごさん同様、Vimを学び始めようとした人のnoteもあわせて載せておきます。
トレーナーとして伝えたかったこと
キャベたまご: 改めまして、4ヶ月に渡ってご指導いただき本当にありがとうございました!最後に今回のトレーニングで最も伝えたかったことがあればお願いします。
みみぞう: 2つあります。1つ目は、『DDDではドメインエキスパートと一緒にユビキタス言語やドメインモデルを定義すること』が何より大事だということ。 2つ目は、『適したドメインモデルは時間とともに変化する』ということです。 今回の技トレではこれらを体験してもらうため、『ドメインエキスパートと会話をしてドメインモデルを定義し、それに従って実装する流れ』のサイクルを重要視しました。実際の開発業務でも、同じようなフローを通して、ユーザーや顧客が本当に求めるプロダクトを作り続けていってもらえれば嬉しく思います。
キャベたまご: 確かにトレーニング中も何度も口にされていた部分ですね。そういう意味で、ドメインエキスパートと会話し、モデリングをしていくという実践知の部分がまだまだ不足していると思っています。 引き続き、学習を進めていきます!ありがとうございました。
みみぞう: ありがとうございました。