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

Chatworkのドメインをモデリングした / Modeling Chatwork domain

Chatworkのドメインをモデリングした / Modeling Chatwork domain

yoshiyoshifujii

February 16, 2020
Tweet

More Decks by yoshiyoshifujii

Other Decks in Technology

Transcript

  1. 自己紹介 - FUJII Yoshitaka - @yoshiyoshifujii - Chatwork株式会社 - Scala関西

    - 登壇 - ScalaMatsuri2019 - 実践 Clean Architecture - 趣味 - ⛰ ⛺ ‍♂ 庭DIY
  2. RDRA 2.0でトップダウン - RDRAは、要件定義の工程を通してシステム 化するものは何かを明らかにする - システムコンテキスト図でシステムに関係す るアクターと外部システムを洗い出す - システムコンテキスト図の目的でまとまった

    資料などはなかった - 関係しそうな部署を洗い出し有識者によるレ ビュー - ほぼすべての部署 - SPOFとなる個の存在 - 特定の個人しかできない業務の発覚
  3. RDRA 2.0でトップダウン - 早く失敗することを優先 (Fail First) - 1つの業務に着目して、以下の図を描いた - ビジネスコンテキスト図

    - ビジネスユースケース図 - 業務フロー図 - バリエーション・条件図 - ユースケース複合図 - 情報モデル図 - 状態モデル図 - 業務を理解しモデルに落とすのはとても大変 - そもそも業務を把握していない - すべての業務ってどれぐらいあるのだろう… - 関係する部署すべてにヒアリング
  4. RDRA 2.0でトップダウン - 縦に遂行する労力と、横に展開する労力を見積る - その結果得られる成果物が、今の時点で必要か? - RDRA 2.0の成果物がとても有効なのは分かった -

    目的を再確認 - 現状を把握し概念モデルを描く - このプロジェクトの先には必要 - 仕様バグのエビデンス - いったん、このアプローチは止める
  5. データ構造を分析 - 既に存在するシステムなので、現状の成果物 に着目する - 情報モデル図の延長線上に出来る成果物 - RDBMSのテーブル定義、YAMLなど - 正規化されていない…

    - 意味のあるまとまりを理解するために コードを読む… - チョモランマ・ディペンデンシー - とにかく… - そのままの構造をJavaのクラスに書き起こす - JIG (Java Instant-document Gazer) で出力 - https://github.com/dddjava/jig
  6. 言葉を定義する - 既存の言葉の意味を調べる - 有識者へのヒアリング - ドキュメントを熟読 - 「つまりこうだよね」って言葉を定義する -

    省略された言葉を正しい言葉にしたうえで分解する - その言葉が必要とされるシーンに合わせて分解する - つまりこういうことだよねと核心に迫る言葉に置き換える - 単純に言い換える - 言葉の置き換えを、リファクタリングで実施する
  7. Roleオブジェクト - Factory Methodは、JIGでレポートすると相互の 関連で出力される package groupChat import message.Message trait

    GroupChat { def createMessage(accountId: AccountId, body: String): Message = ??? } package message import groupChat.RoomId trait Message { val roomId: RoomId }
  8. Roleオブジェクト - メッセージパッケージにRoleオブジェクトを作る - Scalaの場合、型クラスとして作成すると扱いやすい package message import groupChat.GroupChat trait

    MessageRole[A] { def createMessage(self: A)(accountId: AccountId, body: String): Message } object MessageRole { implicit val groupChatMessageRole = new MessageRole[GroupChat] { override def createMessage(self: GroupChat)(accountId: AccountId, body: String): Message = ??? } implicit def toMessageRoleOps[A: MessageRole](self: A) = new { def createMessage(accountId: AccountId, body: String): Message = implicitly[MessageRole[A]].createMessage(self)(accountId, body) } }