クラウドワークス エンジニアブログ

クラウドワークス エンジニアブログ

日本最大級のクラウドソーシング「クラウドワークス」の開発の裏側をお届けするエンジニアブログ

DDD未経験が約1年DDDに触れて感じた理想と現実

はじめに

こんにちは、@momo-0826です。

約1年程前からクラウドリンクスで主にバックエンドを中心とした開発業務に携わっています。

クラウドリンクスではDDDを使用した開発が行われているのですが、DDD未経験だった私が約1年程DDDに触れて感じた自分なりの感想を書いていこうと思います。

この記事の対象者

この記事ではDDDの簡単な概要や実際にDDD未経験の私が触れてみての感想を記載しています。

よって読者は以下のような方を想定しています。

  • DDD未経験や初心者の方
  • DDD導入するか迷われている方
  • DDD導入して実際に良いことあるの??と疑問をお持ちの方

クラウドリンクスで採用している詳細なアーキテクチャについてはこちらの記事を参照してください。

結論

早速ですが、私個人の結論としては以下になります。

  • DDDは保守性に非常に富むが、全てを解決するものではない
  • 長期的な開発に対するメリットは大きいが、導入には考慮すべき点がある

銀の弾丸は存在しないということは色々なところで言われていることなので当たり前なのですが、何故この結論に至ったのかをDDDとは何かというところから振り返っていこうと思います。

DDDとは

ドメイン駆動設計(DDD)とはビジネス領域に焦点を当て、ドメインの複雑な仕様を適切にシステム設計に落とし込むアプローチのことです。

ビジネスルールをシステムの中心に据えることでビジネスロジックの分散を防ぎ、保守性の高い開発を実現できます。

DDDで解決できること

DDDの概要を説明しましたが、そもそもDDDとは何を解決してくれるものなのでしょうか??

ここではDDDが解決することを抜粋して簡単に説明しようと思います。

  • ビジネスルールの欠如・分散
    • ビジネスルールに関連するコードの漏れや、様々な箇所に分散して修正時のコスト増加を防ぐことができます。
  • 保守が困難なコードを生み出すこと
    • DDDによりビジネスルールの欠如・分散を防ぐことで、コードがスパゲッティコードとなることを防ぐことができます。
    • その結果として、システム肥大化による保守の難しさの増加率を抑えることができます。
  • ドメイン知識の偏り
    • DDDではビジネスメンバとエンジニア間で共通の言葉を使用します。
    • その結果として、特定の人物のみがドメイン知識を保有し、開発する上での会話の齟齬やコミュニケーションコストが増加することを防ぎます。

DDDを構成する要素

ここではDDDを行う際に出てくる基本的な要素について簡単に説明しようと思います。

  • 境界づけられたコンテキスト
    • ある言葉が特定の意味を持つ範囲のことです。
    • 言葉はその文脈によって意味が変化するのでそもそもの文脈を決める必要があります。
    • 例えばソーシャルゲームアプリで考えると、ゲームコンテキストにおける「お金」はゲーム内で使用できるマネーという意味を持ちますが、課金コンテキストにおける「お金」はリアルマネーという意味を持つので文脈を決めることは重要になってきます。
  • ドメインオブジェクト
    • ドメインオブジェクトはビジネスロジックを表現してシステムの中心となる要素です。
    • 以降に紹介するエンティティや値オブジェクト、集約といった要素を含みます。
    • ビジネスルールを適切にドメインオブジェクトに落とし込むことで、システムの整合性を維持することができます。
  • エンティティ
    • システム内で一意に識別されるオブジェクトになります。
    • ライフサイクルを持ちます。
    • 例えば、ユーザーは識別子としてユーザーIDを持ち、最初に登録した住所が変化したとしてもそのユーザーは同じユーザーであることに変わりはありません。
  • 値オブジェクト
    • エンティティとは異なり識別子によって同一性のチェックは行われません。
    • 例えば、ユーザーAとBが同じく「山田太郎」という名前を保持していた場合、ユーザーというエンティティの観点では別物ですが、名前という値オブジェクトでは同じものと見なされます。
  • 集約
    • 集約は関係するエンティティと値オブジェクトをグループ化して一貫性を保つことを目的に作成されます。
    • 集約内のエンティティの変更は必ず集約のルート(Aggregate Root)となるエンティティを通して変更されることを保証し、グループ単位でDB操作を行うことで一貫性を保つことができます。
    • クラウドリンクス(https://crowdlinks.jp/projects)の例では以下のようになります。
      Project集約
      • クラウドリンクスではプロジェクトを掲載する機能があり、上の図に示すように「Project」には「Project Title」という値が存在します。
      • クラウドリンクスでは集約のルートとなるエンティティを通して変更しており、決められたグループ単位でDB操作を行うので、タイトルの変更のみであっても他のテーブル、例えばプロジェクトが「公開中」なのか「下書き」なのかといったステータスを管理するテーブルへのDB操作も併せて行っています。
      • ユースケースによって集約が分かれることもあります。
    • 集約を決めるということはある意味で、トランザクション境界を決めるといったことに近いのかと思います。

DDDのメリット、デメリット

  • メリット
    • ドメイン毎の責任の範囲が明確で修正や拡張が行いやすい
    • 変更対応が容易
      • コアとなるドメインモデルが適切に作成されていると仕様変更や機能追加が行いやすくなる
    • コミュニケーションコストが低くなる
  • デメリット
    • DDD自体に様々な概念が出てくるので、理解に時間がかかる
      • クリーンアーキテクチャやCQRSといった関連技術も出てくることが多いので、更にキャッチアップのコストが高くなる
    • モデリングを適切に行う必要があるので開発初期のコストが高い
      • プロトタイプとして早く実装する必要がある場合には向いていない
    • 小規模や単純なシステムでは過剰な設計になってしまう

実際にDDDでの開発に触れて感じた良かった点、苦労した点

ここまでは教科書的にDDDの概要やメリット、デメリットを見てきました。

ここからは実際にDDD未経験の私がDDDを使用した開発で感じた良かった点と苦労した点を見ていこうと思います。

  • 良かった点
    • ドメイン毎に責務が明確なため、コードの修正時などに影響範囲の特定が容易
      • クラウドリンクスでは、コンテキストとして「プロジェクト」や「メッセージ」などが存在しています。
      • それぞれは独立しているため、例えば「メッセージ」コンテキストに関する修正を行う場合は影響範囲は基本的に「メッセージ」コンテキスト内のみになるため、予想外のデグレも発生せず心理的負担も少なく開発を進めることができました。
    • DB関連の操作は集約にまとまっているため、Aという処理では必要なテーブルが正しく更新されるのに、Bという処理では漏れがあるなどということが起きない
      • システムのリプレイスに伴い、ユーザーの新規登録機能を開発した際にこの点が個人的には感動しました。
      • ユーザーの新規登録なのでユーザープロフィールのデータを作成する必要がありましたが、当然様々なテーブルへの登録が必要でした。
      • この場合関係するDB更新処理を漏れなく呼び出す必要がありますが、DDDではデータの一貫性を保つため集約を使用するのでその集約の処理さえ呼び出せば容易にDB更新を行うことができました。
    • 共通の言葉をビジネスサイドとエンジニア間で使用するので仕様確認や説明時にコミュニケーションコストを抑えることができた
      • 前職では特定の人物のみがドメイン知識を保有している環境で開発を行っており、ドメイン知識を都度聞き出す必要があったり、同じ言葉でも会話の文脈で意味が変わって齟齬が発生したりなど開発する上で苦戦をしていたので、DDDによるドメイン知識の共有は効果を実感できました。
    • コードを見ればある程度仕様がわかる
      • ビジネスルールがエンティティや値オブジェクトにコードとして反映されるのでチームへのジョイン時などにコードを読むことでも仕様の把握ができます。
  • 苦労した点・課題
    • DDDの概念の理解自体も難しい上に、ヘキサゴナルアーキテクチャやイベントソーシング、CQRSといった要素も出てきて初期のキャッチアップコストが高かった。
      • 前職まではMVCモデルの経験しかなかったため、あまり理解ができていなかった時はコードを書きながら回りくどい書き方をしているような感覚があったのを覚えています。
      • クラウドリンクスでは疑似的なイベントソーシングを用いてコンテキストを跨ぐ処理の呼び出しを行なっていますが、複数回コンテキストを跨ぐ場合に処理を追うのが難しくなってくるのでコードの理解に時間がかかりました。
    • 疑似的なイベントソーシングを用いてコンテキストを跨ぐ処理を行なっている関係でイベントで発行した処理が失敗した際のリトライ機能などが充分ではないことが課題として残っています。
    • シンプルな機能実装に対して書くコード量が多く感じる
      • 新規でコンテキストを作成する場合ドメインモデルから作成する必要があるため、コードを書く際に他のコンテキストにも存在するような値オブジェクトを再度作成する必要があるなど、コードを書く量が増える傾向がありました。
    • 初期リリースまでに時間がかかりそう(あくまで予想)
      • クラウドリンクスでは初期開発を行なったメンバーが丁寧にモデリングをしてくれていた関係で非常に保守性の富んだコードとなっています。
      • しかしそのコードを見ながら思うのが初期のモデリングに時間がかかっただろうということです。
      • そのため、DDDはとにかく早くリリースすることが優先される場合などには向いていないのかもしれません。

まとめ

これらの経験を踏まえて私個人のDDDに対する印象としては以下のようになりました

  • DDDは全てを解決する魔法のツールではない
  • しかし、適切に使うことで長期的な保守がしやすいシステムを作り上げることができる
  • チームの状態やビジネスの要件を考慮して導入を検討すべき

私自身モデリングがまだまだ上手くできなかったりと自分の知識が足りない点があることは認識しているので、これからもより良いプロダクトにしていけるように日々学んでいきたいと思います!!

クラウドワークスではエンジニアを募集しています。興味のある方は以下のリンクからご応募ください。

crowdworks.co.jp

Terraform / OpenTofuでtfstate関連のブロックの削除を便利に行う

こんにちは。クラウドワークス SRE チームの田中(@kangaechu)です。

12月はアドベントカレンダーで重めの記事を書いたので、今回は軽いネタです。

手動での削除が手間だったTerraform/OpenTofuの import/moved/removed ブロックをGitHub Actionsを活用して効率化しました。その具体的な仕組みをご紹介します。

  • 背景と課題
  • 解決策
  • 実装
    • hcledit
    • git diff --ignore-blank-lines
    • Pull Requestの作成
    • 動作結果とメリット
    • まとめ
続きを読む

プロダクト開発の2024年総括とシステム思考

2024年総括とシステム思考

年の瀬ご多端の折、皆様におかれましては本年も大変お世話になりました。プロダクト開発部部長の塚本 @hihatsです。 本記事はクラウドワークスグループAdvent Calendar 2024 シリーズ4の25日目の記事です。

昨年に引き続き、プロダクト開発部として今年取り組んできたことと、全社におけるプロダクト開発の動きから整理していきますが、 3ヶ月ほど前に書いた自社の開発組織の強みを定義するという記事の中でも軽く触れたシステム思考の話を中心軸に置きつつ進めていきます。 *1

engineer.crowdworks.jp

また今年はアドベントカレンダーの数も昨年より倍に増えました。 アドカレの記事もまとめつつふりかえっていきます。

*1: 「システム思考」については紹介するだけで連載記事になるのでここでは割愛します。機を見て書く意思はある

続きを読む

crowdworks.jp のデザインシステム構築活動を振り返る 2024 (実装編)

この記事はクラウドワークス Advent Calendar 2024 シリーズ 1 の 18日目の記事です。

こんにちは、crowdworks.jp のデザインシステム構築に携わっているエンジニアの @t0yohei です。

昨年は、crowdworks.jp のデザインシステム構築活動を振り返る 2023 (実装編)という記事で、デザインシステム実装の 0 -> 1 について書きました。

デザインシステム実装 2 年目である今年は、1 -> 10 として「やったこと」と逆に今の段階では「やらなかったこと」を書いてみたいと思います。

デザインシステムを実装中の方、これからデザインシステムを実装していこうという方の参考になれば幸いです。

目次

  • 状況整理
  • やったこと
    • Design Token と Component Library を用いたヘッダーリプレイス
    • Component Library の拡充
    • Linter 整備
    • 新規コンポーネントお披露目会の実施
    • やったことのまとめ
  • やらなかったこと
    • ドキュメントサイトの外部公開
    • Component Library の npm パッケージ化
    • やらなかったことのまとめ
  • 最後に
続きを読む

© 2016 CrowdWorks, Inc., All rights reserved.