Upgrade to Pro — share decks privately, control downloads, hide ads and more …

レガシーなプロダクトからドメイン層を再設計する / iOSDC_takahashi_ishii

Recruit
PRO
September 09, 2022

レガシーなプロダクトからドメイン層を再設計する / iOSDC_takahashi_ishii

2022/09/11_iOSDC Japan 2022での、高橋/石井の講演資料になります

Recruit
PRO

September 09, 2022
Tweet

More Decks by Recruit

Other Decks in Technology

Transcript

  1. レガシーなプロダクトからドメ イン層を再設計する 高橋 陽太郎 石井 潤

  2. 自己紹介 石井 潤 • 株式会社リクルート( 2018.04-) • iOS/Android App Developer

    (2018.10-) 高橋陽太郎 • 株式会社リクルート • Engineering Manager
  3. None
  4. これまでのあらすじ:混乱に秩序をもたらすリアーキテクチャ奮闘中 での出来事 View 肥大化。 ロジックやデータが モリモリに入ってい る Presenter ほぼログ送信のロ ジックしかなく薄すぎ

    る Model APIやDBアクセス レイヤリングを適切にする ことでFat Viewから脱却 したい。 なぜか依存している DBアクセス用のモデル を生成してたりする
  5. リアーキテクチャは困難に困難を極め、 スコープを絞り、一旦既存制約を切り離したPoC実 装に方針を変換し、、、 時は流れ

  6. そしてFat Presenterが出来上がった View 表示とイベント通知 (簡素化に成功) Presenter 画面表示のための データやフラグ、 ビジネスロジック。 大量の状態を持っ

    て肥大化。 UseCase ほぼRepositoryの ラッパー Repository ほぼDataAccessの ラッパー DataAccess APIやDBアクセ ス DomainModel
  7. これがやりたかったことではなかったはずなのに、どうしてこうなったんだろう? View 表示とイベント通知 (簡素化に成功) Presenter 画面表示のための データやフラグ、 ビジネスロジック。 大量の状態を持っ て肥大化。

    UseCase ほぼRepositoryの ラッパー Repository ほぼDataAccessの ラッパー DataAccess APIやDBアクセ ス DomainModel 【疑問】 状態を置くレイヤーが適切ではない のでは? Presenter 画面表示のための データやフラグ、 ビジネスロジック。 大量の状態を持っ て肥大化。
  8. チームでは毎週技術顧問のtwadaさんに相談ペアプロする時間を持っていた。 そこで相談してみた。 「twadaさん、リアーキテクチャしたらPresenterが多数の状態を持ってしまい肥 大化してしまいました。これらの状態を管理するレイヤーを新たに作るべきか悩 んでいます」

  9. twadaさん「どのレイヤーがどんな責務を持つかという議論の前に (多くのエンジニアが陥りがちな問 題)、ドメインがどうなっているかを知ることが重要だよ」 「多くのエンジニアが陥りがちな問題ですが、 どのレイヤーがどんな責務を持つべきか という議論の前に、ドメインがどうなっているかを知ることが重要 です」

  10. ドメインがどうなっているかを知る?? これを機に自分たちのドメインモデルは何か?どんな状態やイベント/状態遷移を含むの か、などを理解するためにモデリングをしてみることに。

  11. 自分たちがモデリングしたものを再びtwadaさんにみてもらうと 既存の実装で扱われているデータのモデリングになってしまっていて、 UI/API/DBの実 装の影響を強く受けてしまっていますね。 本来、タウンワークアプリの本質って何でしょうね? 何の価値を提供しているんで しょう? 例えば、「求人情報」が「既読ステー タス」を持っているのって何かおかし くない?

  12. 実装詳細に魂をひかれていた!? 現状の実装に引っ張られていて、結果として、「レイヤリングによる交通整理」をしただけ に過ぎなかった。 そこからの脱出のコツは、APIやDBにまつわるもの、データの永続化や取得の都合は、 モデリングの際はメモリが無限にあってデータは全てメモリに乗っていると考えること。 UIの都合について(ページ数)、表示の制限についてもまずは考えなくて良い。

  13. ここまでのアドバイスから学んだことポイント 自分たちがやっていたのは、よく知られているアーキテクチャーを真似たレイヤリングと、ドメインモデリング を「技術的な側面」だけ見てやっていた。でも本当に我々に必要だったのはテクニックではなく、 「アプリの中に埋もれているドメイン・概念を捉え直すこと 」だった。 2回アドバイスをもらったが、結局それはどちらも同じことで、要するに ↓だとこの時気がついた。 タウンワークアプリの本質って何でしょうね? 何の価値を提供しているんでしょう?

  14. では、タウンワークアプリにとっての本質は何か?なんのためにあ るのか? タウンワークは、ユーザーに対して、求人情報を提供して応募してもらうことで、ユーザーにマッチングを提供するこ とが本質。 ユーザー 求人 重要なドメイ ンモデルの 発見 関係性

    (閲覧する、応募する etc)
  15. 知っていたはずなのに自明すぎて気づいていなかった

  16. 「ユーザー」の発見と、それまでのモデルへの違和感。 例えば、求人情報と既読ステータスを直接結びつけるモデリングをしていた。 しかし、既読はユーザーの行動の結果。 ユーザーと求人情報は独立して存在する。 そもそもユーザーがモデルとして表れていなかった(当然すぎて埋まっていた)

  17. 必要だったものは、アプリの本質から考えた基本構造のモデリング だった ユーザーをま ずは書く それにまつわる エンティティを書く ユーザーとエンティティとの関 係を洗い出す

  18. ここまでの気づき • 我々エンジニアはすぐに実装やレイヤリングに目がいってしまうが、それではドメイ ンモデルには辿り着かない。 • 実装から離れて、0ベースでドメインのことを考える。 ◦ まずはアプリの本質、どんな価値をユーザーに提供するかを考える ◦ その際、UI/DB/APIなど実装上の制約は考えない

    ◦ 別のUIや実行基盤でも考えてみて同じように価値を提供できるか確認する • これらを意識してモデリングをしてみたら、レイヤリングに注力していた最初期から はアプリの捉え方、認識の仕方がまるっきり変わっていた。 ↑スライドの途中ですが一番伝えたかったことです。
  19. 本日は 「アプリの本質に注目してドメインモデルをしたら アプリの捉え方がまるっきり変わっていた」 という感動が伝わればゴール。 なのですが、 やってみた中で色々なTIPsもあり、学びが多かったので、残り時間でそれを 紹介していきます。 (時間無くなったら途中で終わるのであとは読んでみてください。)

  20. TIP1: ドメインモデルには情報ではなく事実を持たせる 「掲載終了期限」には2通りの表現がある 「yyyy/mm/dd」「あと〜日で終了」 事実を目的に沿って加工したものが情報 そのため、ドメインには事実を持っていた方が変更に強い https://speakerdeck.com/twada/test-driven-architecture-aws-dev-day-tokyo-2018?slide=90(大元は『SQLアンチパターン』)

  21. 事実それとも情報?を深く考える ユーザーが求人 に関心を示すこと 「n回閲覧したこ と」は事実?情 報? 例えば、「ユーザーの滞在時間」を事実としてモデルに保持 すると、、、 「n回同じ原稿をみたユーザーに表示を増やしたい」といった 案件で、nの回数が変更になってもドメインモデルのデータ

    の保持の仕方には影響せず、加工する処理を変えてあげ れば達成できる。
  22. TIP2: ドメインモデルは現実よりも複雑で豊かなり タウンワークにおける検索時の駅選択のモデリング 【仕様①】 基本的にはユーザーが 選択している都道府県 の駅が選択できる 【仕様②】 同一路線上の他の都道 府県の駅が選択できる

    【仕様③】JR中央本線 の「新宿駅」を選択する と、別路線の新宿駅も 選択状態になる。 【仕様④】 ユーザーには選択した 都道府県+選択した駅 名で表示する
  23. 愚直にリレーションを書くとn:nの集合体のようなカオスに

  24. First attempt: まずは直感的に書いてみる →駅と路線/都道府県の関係性がわかりにくい。。。 駅・路線・都道府県 にそれぞれ関係性 があるはずなのに、 表現しにくい

  25. Try:「駅」という概念を「路線上の駅」と「地図上の駅」に 物理的な「駅」ではなく、アプリ上の概 念としての「駅」。同じ名前でもアプリ 上で区別することにした。 クラスベースではなく、インスタンス(具 体例)で考えるのもポイントだった。

  26. 気づき:現実世界と一致しなくてOK。より複雑で豊かに。 路線上の駅と都道府県を直接結びつ ける →ユーザーが選択中の都道府県で選 べる駅のリストの取得が容易になった

  27. TIP3: アプリの中のドメインモデリング • サーバーでモデリングを頑張りそれを表示するだけなら、アプリのモデリングは必要な い? ◦ 確かにそういうデータも存在する ◦ 例えば求人詳細の給与や時間を立体的なモデルにしてもうまみがない (左図)

    • でも、我々アプリの本質は「ユーザーと求人とのインタラクション」を実現すること。それ にまつわるドメインモデリングはアプリでも必要だった。 ◦ 例えば閲覧履歴や検索条件など、ユーザーと求人の関係を促進するためのデータはモデルにする価 値がある(右図)
  28. 多分この辺で時間がなくなるので あとは読んでおいてくださいスタイル (まとめへ)

  29. TIPS4: モデルの評価(モデルの馴染む感をどう判断する?) • ドメインモデルは単体で価値があるものではなく、ユースケースで利用されることに 価値がある ◦ プロトタイプの段階では想定されるユースケースでの運用に耐えられれば良い ◦ ユースケースが増えたときに不十分さに気が付く

  30. 書いたものを評価するときの三要素 1. 【理解容易性】コンテキストを共有していない人(未来のチームメンバー)も理解できる か 2. 【変更容易性】影響範囲を小さくできているか 3. 【テスト容易性】テストの書きやすさ

  31. 理解容易性 • IDが並んでいるより名前がついている方がわかりやすい • 内部構造に依存した名前は避ける • チームに日本人しかいなければ日本語の名前をつけるのも良い 数字だとわ かりにくい 内部構造に依

    存した名前で わかりにくい
  32. 変更容易性 • enumのケースやif文、ダウンキャストが増えていくのはよくない兆候(具象を直接 扱っている) ◦ デザインパターンの出番 • 利用者はインターフェースのみを扱う • インターフェースは極力シンプルにして、具象クラスに多くを任せる

    ◦ インターフェースに変更があると、具象クラス全てに影響が出てしまうため
  33. テスト容易性 • まずテストが書ける状態かでいろいろ気付ける ◦ 実際にテストを書こうとして不足しているユースケースに気がついた • その上で、テストを書こうとしてみるといろいろと気づきがある、例えば ◦ 疎結合になっているか≒依存性の注入などがしやすいか ◦

    内部状態に強く依存していないか、同じインプットに対して同じアウトプットを返すか ◦ インスタンスを生成する時に長大なセットアップを必要としていないか≒サイズは適切か
  34. 実際に書いてみて検証する 利用者視点でコードを書いて、使いやすいか、要求を満たせているか確かめる。方法は 複数あり、どちらもメリット・デメリットがある。 また、方法によらず、得られたフィードバックを元に改善し続けることがポイント。サービ スが続く限りモデルも進化し続けていく。 1. 実際にViewを作って検証 2. テストコードによって検証

  35. 実際にViewを作って検証 愚直な方法 󰢃色々時間がかかる • Viewも作る、Presenterも作る、AppDelegateも作る、Factoryも作る… 󰢏やることはわかりやすい なんたって本物だから • 機能を漏らすことはない •

    実際作ってみたことでユースケースに足りない機能があることを発見できた
  36. テストコードによる検証 利用者側の視点でIntegration Testを書く • 使われるケースを想像しながら 󰢏検証のための最小限のコードで済ませられる 󰢃想像力がいる/ドメインモデリング未経験だと最初はハードルが高い

  37. テストコードを書く際に気づいたミニTIP 1. テストはゴール(アサーション)から書くと目的がブレにくい a. 準備に手間がかかると目的を見失ったり、せっかく準備したのだからたくさ ん検証しようとなりがち 2. テストケースの名前の付け方、構造化の仕方、機能が先か、状況が先か a. 機能

    -> 仕様書的にテストを書ける b. 状況 -> データの準備、使い回しがやりやすい
  38. Viewを作る vs テストコード 我々の場合は、モデリングが不慣れだったことから、最初にViewを作って利用イメージ を作り、その後テストコードでの検証も取り入れて行った。(twadaさんに導いてもらって だんだん習熟度が上がって行ったのも大きかった) View テストコード 習熟度 👍低くても可能

    ある程度必要 コード量 動かすためのコードが結構必要 👍必要最小限 パターン網羅 データ準備や操作が大変 👍データ準備は必要、あとは実行するだけ 繰り返し検証 大変 👍簡単
  39. TIP5:モデルもメンテナンスする? モデルとコードの関係 • モデルとコードは一体 • 行ったり来たりしてフィードバックし合う ◦ モデルだけだと抽象的すぎて要素を見落とすことがあるし、コードだけだと具体的すぎて全体が見えなく なる ◦

    どちらかで変更があればもう一方にも反映する ▪ 項目→応募入力項目に名前変更 • コードが書けたならモデル(図)はメンテナンスしなくて良い? ◦ それぞれ目的が違う ▪ モデルは全体を俯瞰するために有用 • 全体像、要素の関係を把握しやすい • 仕様変更(新たな仕様)の際に全体の中での位置、既存の要素との関係がすぐわかる モデル コード 全体、俯瞰、 要素の関係 具体、詳細
  40. まとめ このセッションで触れた内容 • アーキテクチャに秩序をもたらすべく、リアーキテクチャに取り組んだらFat Presenterになってしまった • レイヤリングに意識を向けていたが、ドメインを掘り起こす作業の中で、アプリケー ションの本質を理解することが重要だと気づいた • モデリングする上でたくさん疑問にぶつかり、それらに自分たちなりの解答を出せ

    た ◦ ドメインには事実を持たせる?情報を持たせる? ◦ ドメインは現実世界のものと対応するべき? ◦ サーバーサイドではなく、アプリでもドメインに注意を払う必要ってあるの? ◦ 作ってみたドメインがしっくりきているかってどうやったらわかるの? ▪ 気づいたらテストコードの書き方も練度が上がっていた ◦ 動作するコードが出来上がったら、モデルもメンテナンスしなければいけないの?
  41. 一番衝撃的だったのは、ドメインに意識を向ける中で我々のアプリ の捉え方がガラッと変わったこと このセッションで触れた内容 • リアーキテクチャに取り組んだらFat Presenterになってしまった • レイヤリングに意識を向けていたが、ドメインを掘り起こす作業の中で、アプリケー ションの本質を理解することが重要だと気づいた •

    モデリングする上でたくさん疑問にぶつかり、それらに自分たちなりの解答を出せ た ◦ ドメインには事実を持たせる?情報を持たせる? ◦ ドメインは現実世界のものと対応するべき? ◦ サーバーサイドではなく、アプリでもドメインに注意を払う必要ってあるの? ◦ 作ってみたドメインがしっくりきているかってどうやったらわかるの? ▪ 気づいたらテストコードの書き方も練度が上がっていた ◦ 動作するコードが出来上がったら、モデルもメンテナンスしなければいけないの?
  42. この感動が少しでも伝わったのであれば幸いです。 もし今後ドメインに意識を向けたときに 同じ感動を共有できたらぜひ教えてください このセッションについてのフィードバックもいただけると、このセッ ションのドメインモデルも豊かになります!

  43. ご清聴ありがとうございました!