カンファレンスで学んだことをアウトプットしたい
先日開催したObject-Oriented Conference 2024に参加してきました。
初めて大規模なカンファレンス参加し、非常に多くの学びを得ることができました。
ある登壇者の方が、「とにかくアウトプットしろ!アウトプットする中で新しい発見がある!」とおっしゃっていた(個人的解釈も含む)ので、自分もそれに倣い、経験が新しいうち学んだことや感想をバーッと書いていこうと思います。
主に自分のための備忘録的な記事になると思いますが、この記事を読んだ方が何か新しい知識や考えを得ることができると幸いです。
記載している内容に誤植や間違いがあればご指摘いただけると幸いです!
Object-Oriented Conference 2024とは?
"Object-Oriented"とはオブジェクト指向のこと。このイベントはオブジェクト指向に関係のあるテーマが扱われ、オブジェクト指向、DDD、カプセル化や設計の話が多い印象でした。
各セッションを振り返る
ここからは私が当日参加したセッションごとに、振り返っていこうと思います。
Speaker Deckのリンクを載せておくので、もし細かい内容が気になった方は直接スライドを見ていただくといいと思います。
戦略的DDDを実践するための跳躍力@pictiny
DDDには3つの領域が存在し、
ドメイン理解 → ドメインモデリング → 実装 → ドメイン理解…
それぞれの領域を循環していくようなイメージである。
"戦略的DDD"とは、"戦略的設計"のことであり↑の領域だと「ドメイン理解」に該当する。つまりドメインエキスパート(ドメインに精通している人。開発者やPOではない場合がほとんど)と密にコミュニケーションをとり、プロダクトやサービスにドメイン知識を反映させていくことに近い。
戦略的DDDができるとなぜいいのか
端的に言うと、「顧客やユーザーにとっての課題・解決策をある程度明確にした上で開発をすることができるから」 だと思う。
当たり前だけど、プロダクトを作ってもある人の課題解決に役立たないとサービスとしては成り立たない。市場での競争に勝っていくためには顧客やユーザーの視点を取り込むことは必須である。
"ある程度"とつけたのは、おそらくドメインに関して完全に理解している人はいない or ドメインそのものが変化していくことを考えると、完璧な回答を持っている人はいないので、常に模索し続けるというイメージを持っているから。
DDDを実践するには泥臭くいく
結局ドメインの知識を得ることはある程度泥臭くいく必要がある。
- Biz側の人たちに、サービスがクライアントのどのような課題を解決しているのかヒアリング
- ドメインエキスパートに直接聞く
- 自分の会社(ourly)はWeb社内報のサービスを作っているので、Web社内報を運用する人(コーポレートや広報)にどのような悩みを抱えているのかを直接聞くことができそう
- 1次情報に触れる、にイメージは近い
1人のエンジニアである自分だけがドメイン知識を得るだけではもったいない!それだけでは大きな変化を生みづらいので、周りのエンジニアにも得た知識をアウトプットしていくことが大事である。(聞いてなんとなく理解して満足してしまいがち)
またドメイン知識獲得のために、クライアントとの商談動画を見る、Biz側の人たちにourlyというサービスがどのような強みを持っているのかを聞く、ということは自分でもすぐにできそうだと思った。身近なところから行動を変えていきたいなと思ったので、今度に活かしたい。
クソコード動画『カプセル化 Mk-II』で考える、上手くカプセル化できない理由@minodriven
カプセル化しても想定と異なるデータや処理によって壊れやすい
カプセル化:データとデータを操作する処理をひとまとめにすること
カプセル化はRubyで考えると、Modelに近い。
カプセル化をしてデータとその処理を上手く書けたつもりでも、実際の現場では仕様の漏れや変更によりカプセル化が壊れることが多々ある。
関心の分離 = 目的の分離
関心の分離という有名な考え方がある。関心の分離ができている状態とは、他の関心を考慮せずにコードや設計の修正をすることができること(ざっくりですがイメージ)。
ミノ駆動さんは、この「関心」を「目的」に言い換えると考えやすいと述べていた。つまり目的が分離されていると、カプセルやシステムは壊れにくくなるということである。
そもそもシステムとは「目的達成のための手段」である(例:マップアプリ→目的地にいくための道順を調べる)。大きなシステムを考えると複雑だが、どのシステムも目的の階層構造に分けることができる(上位目的と下位目的)。
例えば、マップアプリで考えた時に、
ある上位の目的から、下位の目的に細かく枝分かれしていく。こうして目的の粒度を小さくしていくことがまず大事。
そして小さくした目的を見て、「この目的を満たすためには何が必要なのか」特徴を抜き出していく。
手段から見て目的は一意にする!複数の目的を持つとバグの原因
↑で満たした特徴を実際のシステムやモデルとして構築していく。この時に重要なのは「手段が達成したい目的は必ず1つにする」ことである。一つの手段(システム、モデル、カプセル)で複数の目的を満たそうとすると、上で言ったように思わぬ仕様漏れや変更で壊れる原因となる。
実際に今自分が開発しているプロダクトを見ても、1つのモデルが複数の目的達成に扱われてしまっているなと感じた。Userモデルなんかは、認証やメール送信、プロフィールなどたくさんの目的に使われているので、こういうところも後の変更を難しくする一因になりうるのかなと。
ビジネスロジックを「型」で表現するOOPのための関数型DDD@Yuiiitoto
オブジェクト指向と関数型の両者の良さを組み合わせる
Yuiiitotoさん曰く、オブジェクト指向に関数型プログラミングのテクニックを入れられるとさらにいい開発ができるようになるとのこと。
普段RubyやRailsを扱っているので、関数型がなんたるかをあまりわかっていないが、この後の話はとても面白いし勉強になったので整理してみる。
コンパイルエラーでモデルのデータ不整合を防ぐ
例えばあるモデルで nullable
のカラムがある際に、扱いたいデータによってそのカラムの処理が分かれる場合を考える。
スライドで提示している例では、注文(Order)クラスを例に挙げている。注文が、「未確定」、「確定済み」、「キャンセル済み」、「お届け済み」の4つの状態に分かれるという具合である。この時に、注文の状態をOrderモデルだけで管理するのは大変なので、Orderクラスを4つに分ける。
言葉で説明するのがこれ以降複雑になりそうな気がしたので、気になる方はぜひスライドを直接見てみてください。
以下で、ざっくりとまとめられるように頑張ります。
- 直積集合:特定のデータの組み合わせで得られるデータの構造(≒ class)
- 例:クラスが持つカラムを組み合わせて一つのレコードが作られる
- 直和集合:ある要素が存在するときに、必ずある一意の要素に一致する構造
- 例:今回のOrderクラスなら、「未確定」、「確定済み」、「キャンセル済み」、「お届け済み」のいずれかに必ず該当する
上記の直積集合と直和集合の組み合わせで得られるデータ構造を「代数型データ構造」と呼ぶ。
先ほどOrderクラスを状態に分けて4つの別々のクラスに分けたが、これらをまとめてOrderクラスの直和集合として定義する(コード単位はスライドを参照)。
それぞれのクラスでは必須のカラムのみを定義し、直積集合としてのクラスとする(ここは割と無意識にできていそう)
こうすることで、ある注文のインスタンスを作成する際に、用いるクラスによってOrderの状態を分けることができる。さらには、過不足なくカラムを指定することができる。もしも直積集合から外れた要素を用いた場合は、コンパイルエラーとしてその場で検知されるので楽。
ルールを型で守る
上記で扱ってきた注文のステータスなどのビジネスロジックをプロダクトに適用する際は、なるべくコンパイルエラーでルール適用をテストできるようにする。
その一方で、ハンドリング(エラーメッセージやHTTTステータス)は自動テストでテストできるようにする。
このように全てをテストで補おうとするのではなく、コンパイルエラーも活用することに旨みがある。全てを自動テストで補おうとすると、仕様の考慮漏れが否めないので怖い。
終わりに
拙い文章でしたが、ここまでお付き合いいただきありがとうございました。
素晴らしいカンファレンスだったので、ただ参加して終わるのは勿体無いと思い本記事を執筆しましたが、やはりアウトプットする際には自分にとって理解できていないところを明確にすることができる&一度聞いた内容を再度咀嚼することができるのでいいなと思いました。