ITと哲学と

IT系エンジニアによる技術と哲学のお話。

エリックエヴァンスのドメイン駆動設計を読んでいる(第2部 第6章-2)

ファクトリ

オブジェクトの作成をどこの責務にするべきか?

オブジェクトは作成された後に用途にあった様々な責務を持つ。 自分自身を作成するということはオブジェクトのライフサイクルの一番最初にはあるが、それ以降は出てこない。 責務はカプセル化して明快なものをシンプルにもたせたいので、一番初めに一度しか使われないような責務は持たせるべきではないという意味だと思います。

一方でオブジェクトを使用するクライアント側にその責務を持たせるのはより問題が大きくなる。 様々な箇所で自由にオブジェクトが生成されるようになるので、リファクタリングができないし、オブジェクトの生成についての知識をクライアントが知っている必要があるためです。 ドメインでの知識が別のそうに流出しているという表現をしますが、これはレイヤー化アーキテクチャ的によくないわけです。

なので、ファクトリというエンティティやバリューオブジェクトとは異なる新たな要素をドメイン層の要素として追加します。

ファクトリの責務は、オブフェクトを生成することであり、集約の制約から、集約の範囲内のオブジェクトはすべて同じタイミングで扱われるべきであるため、ファクトリはオブジェクトを作成する際には集約のすべてのオブジェクトを一度に作成します。

うちのプロジェクトではScalaを使ってますが、エンティティをcase objectとして定義し、そのコンパニオンオブジェクトのapplyメソッドをファクトリとして扱うことが多いです。あえて別にファクトリを作成してもいいんですが、結局ファクトリでやっていることとコンパニオンオブジェクトのapplyメソッドでやろうとすることに違いはなかったのでそのような形にしています。

エリックエヴァンスのドメイン駆動設計を読んでいる(第2部 第6章-1)

ドメインオブジェクトのライフサイクル

全てのオブジェクトにはライフサイクルがあり、また他のオブジェクトとの関連もある。

あるオブジェクトが消えるときは他のオブジェクトも同時に消えなくてはいけなかったり、あるオブジェクトが作成されたタイミングで必ず作成されなくてはならないオブジェクトもある。

これらのトランザクションの整合性を保つために、明確にその領域を区別する必要があるということらしい。

そしてその領域をそれぞれアグリゲートと呼びます。

アグリゲートごとにオブジェクト群を作成するやつをファクトリと呼び、オブジェクト群に対する操作を提供するやつをリポジトリと呼びます。

一言でいうと、アグリゲートで区切るスコープによって不変条件が維持されなければならない範囲が示され、ファクトリとリポジトリはアグリゲートごとに存在してオブジェクトの生成や操作を提供ということ。

アグリゲート(集約)

例えば複数のクライアントで同時に同一オブジェクトにアクセスするようなシステムを考えてみる。

同時に編集されたりした場合に備えてトランザクションを保つ必要のある範囲で排他処理を行うことは一般的だと思うが、 この排他処理の範囲が広すぎた場合、いたるところでロックが発生してしまい、とても使いにくいシステムになることが容易に想像がつく。

ではどの範囲で区切るか?という設計を行うのがアグリゲート。 簡単に言うと、関連するオブジェクトの集まりであり、データを変更するための単位として扱われるものがアグリゲート。

これはビジネス領域の知識がとても大切。 今の現場にいるDDD師匠的な人はDDDはアグリゲートだというようなことを言っていた気がする。 真意はまだわからないですが、わかる日が来るのかな。

各アグリゲートにはルートと境界がある。

ルートはアグリゲートに1つだけ存在し、エンティティである。 アグリゲートのメンバの中で、外部のオブジェクトが参照していいのはルートだけ。

あるアグリゲートへのアクセスの口を1つに制限したいためこのような制約が必要になる。

アグリゲートに関わる約束事

  • 集約のルートエンティティはグローバルな同一性を持ち、不変条件をチェックする責務を負う ルートエンティティは集約外から見て一意じゃなくてはいけないとかそういうことだと思われます。

  • 集約の外にあるオブジェクトは集約のルートエンティティのみを参照可能。ルートエンティティは内部のエンティティへの参照を他のオブジェクトに渡せるが、受け取ったオブジェクトはそれを一時的に扱うだけ。参照を保持してはならない。バリューオブジェクトの場合はどうでもいい。

  • 集約内部のオブジェクトは他の集約のルートエンティティへの参照を保持することができる

  • 削除の操作は境界内部に存在するあらゆるものを一度に削除しなければならない。 これはあれですね。トランザクションの範囲が集約なのでなんとなくイメージどおりの話かと。

  • 集約内部に存在するオブジェクトに対する変更がコミットされるときには集約全体の不変条件がすべて満たされてなければならない。 変更をコミットするタイミングで不変条件を満たすチェックを行う必要があるということか?だとするとルールの一番上にあるように、ルートエンティティがそれをチェックする責務を負う形になりそう

エリックエヴァンスのドメイン駆動設計を読んでいる(第2部 第5章)

関連

関連を扱いやすくする方法は以下の3つの通り * 関連をたどる方向を強制する * 限定子を付与して多重度を減らす * 本質的ではない関連を除去する

関係の方向性が双方向にあるということは、それぞれのオブジェクトが存在するときにのみその挙動が把握できるということを意味する。これを単方向に変えることができれば、プログラムを把握することが容易になる。

参照の方向性を絞ることによって単純化し、限定子を使って絞ることでより単純化する。

証券取引口座の例がとてもわかりやすいですね。モデルとコードがそれぞれ示されて、知識を取り入れることでモデルとコードが変わる様子が見えるのは実践のイメージがつかめるのでいい感じです。

エンティティ

ライフサイクルを通じた連続性を持ち、アプリケーションのユーザーにとって重要な同一性の区別が属性から独立して行われる場合はそのモデルはエンティティである。

人は住所や年齢は変わるし、名前も変わるかもしれない。そんな人の同一性を区別することがアプリケーションのユーザーにとって重要なことであれば、それを区別するためのIDが必要になる。この場合はエンティティである。

モデル化する上では、エンティティオブジェクトの定義を極限まで削ぎ落とすことが大切になる。

本質的に必要なものと操作に絞り込み、そこから外れたものは別のモデルとして切り出す必要があるだろう。

あくまでそのモデルを使うユーザー側がIDによって一意に区別する必要があるかどうかで変わるものみたいです。

バリューオブジェクト

IDで区別される必要がないオブジェクトにはIDを振るべきではない。設計ではすべて必要最小限な状態を保つべきなんでしょう。

バリューオブジェクトはインスタンス化される際に何であるか?は重要だが、誰であるか?とかどれであるか?は関係がない。

例えば色は赤であるとか青であるとかは大切だが、どの赤であるか?とかどの青であるか?ということを考える人はいない。

このように設計においてあるモデル要素がその属性しか関心の対象とならない場合、その要素はバリューオブジェクトとして分類すること。バリューオブジェクはイミュータブルなオブジェクトとして扱うこと。

バリューオブジェクトを設計する上で、関連性はエンティティと同様に簡素な形にするべきである。

一点異なるのはバリューオブジェクトは双方向の参照を持たないようにするべきであるという点で、バリューオブジェクトは双方向性を持つべきではない。双方向性が解決できないような事態になったらそもそもそれはバリューオブジェクトにするべきではない。まだ隠れている同一性があるはずだ。 筆者の経験からそんなことが述べられていた。

サービス

エンティティやバリューオブジェクトにしっくりと当てはめることができないような操作がドメインに含まれることがある。

無理やり当てはめようとするとせっかくモデルがシンプルで正しく簡潔に現実を反映していたのによくわからなくなってしまうかもしれない。そんな時は無理をせず、新たなサービスという概念を取り入れよう。

ただし、安易にサービスに逃げるようなことがあってはダメ。エンティティやバリューオブジェクトにおいて存在するべき操作は確実にそれらに持たせること。

責務に従うことが何より大事。

サービスはエンティティなどとは異なり純粋にクライアントに対して何ができるのか?という視点で設計される。

サービスは下記の3つの点を意識して設計する

  • 操作がドメインの概念に関係しており、かつエンティティやバリューオブジェクトの自然な一部ではない
  • ドメインモデルの他の要素の観点からインタフェースが定義されている
  • 操作に状態がない

モジュール

パッケージの切り方についても同様に責務を意識して低結合、高凝縮な区切り方をしていきましょうという内容。

まあうちの現場的にはとりあえずレイヤーごとに区切りつつその中はサービスごとに区切るというルールがあるので一周目はスルーしておこうと思います。

ギャラクシー街道を見ました。

ギャラクシー街道を見ました。感想を書こうと思います。ちなみにネタバレ含む長文です。

最初に結論から言うと、二度と三谷幸喜の作品は見ないと思います。

まとめ

  • PC的にとか言いたくないけど、差別的な要素が強すぎて不快
  • 登場人物の考えていることが理解できないレベルで不快
  • そんな不快な人たちが成長せずに物語が終わるので不快

こんなところです。

西田さん問題

西田敏行さんと香取慎吾さんが会話しているところから始まるのですが、 西田さんに関するある事実がわかった上で思い返すと、意味がわからない。 どのボタンにあの応答をなぜ登録したのか?となります。

不要な設定ですねあれは完全に。 笑いにつながるわけでもない。

綾瀬はるかさんのネックレス問題

意味不明。 面白くないし、意味がわからないです。

振りに相当する箇所は「今日も仕入れに行ってからなかなか帰ってこなかったんですよー」だと思いますが、綾瀬さん、真相伝えてから仕入れに行けばいいんじゃないですかね。大した話でもないですし。というよりそれ習い事だとしたらお金かかるし相談してからの方がよいと思いますよ。

まあ大したことない話なので、この件まるまる不要だわという感じです。

西川さん問題

これは根が深い。

西川さん扮する宇宙人が香取さんの店に来店した時に、香取さんがあの星の人が来ると店が汚れるから帰ってもらえとかいう。 気分が良くない場面だなとか思っていると、最終的には席の上にブルーシートを敷いて、そこに西川さんを座らせるという結論に行き着きます。 これ現実でやったら色々と問題になるのではないかと。

しかも、西川さんは西川さんで、何も文句言わずにニコニコしてハンバーガー食べてる。 怒って店を出るとかしたほうがよかったのではないかと思います。

そんな扱いを受ける西川さんですが、次の出番は最後の最後、主人公たちを引き立てるために歌を歌います。

不当な扱いを受け続け、最後に主人公たちに奉仕して終了。

もうね、不快です。

途中、西川さんが特性を生かして活躍できそうなところもあったんです。 西川さんは常に濡れているという特性を持つ宇宙人ですが、その特性を使って活躍できそうな場面があったんです。

なのにそこで西川さんはスルー。代わりに活躍したのは昆布でした。謎すぎる。

ここで西川さんを活躍させて、登場人物たちが個性は大切だ!尊重しよう!今までごめんな!的なことを学んで成長するとかそういう展開にもできただろうに。 というか、そういう展開にしないのであれば、変な設定つけるのやめたらいいのに。不快です。

まあそんな展開になってもありきたりすぎて面白くないですけどね。不快になるよりマシでしょう。

コールガールとかあの辺問題

早い話が、おっさんが地方に行って風俗に行くという話です。 基本的にどうでもいい。

ここでは綾瀬さん問題につながる伏線?(ETのあれ)を出したかっただけと思われます。

ちなみにコールガールはなんかこう、特定の国の人を連想させる感じ。 いいのかなこれw

遠藤さん問題

今時女装したおっさんを出してわらわせるとかwwww

幼稚だしおもんないわーという感じです。

テレビパッとつけて画面をパッと見た人を笑わせるっていうことならそれでもいいですけど、映画見に来てそんなの見せられても面白くない。 お話として笑わせてくれないなら映画でやる必要ないでしょ。

思い出してみれば、映画始まる前になんかもったいぶってFuji [TV] Movieとかってやってましたねそういえば。

完全にすべってると思います。

あ、「大丈夫大丈夫。」は面白かったです。笑いました。 でもあれオリジナルではないですよね。 トゥルルさまーずで似たような件見た事あるし。

そして遠藤さんの別れの挨拶とかいうあの件。そしてそこから派生するこの物語の山場の出産シーンがもう大問題。ここまでいろいろたくさん問題あったのにそれらを凌駕する問題。

綾瀬さん問題

遠藤さん問題から派生して出産シーンになるわけですが、これって倫理的に許される話じゃないでしょ。

ここから本格的なネタバレです。

遠藤さん扮する宇宙人はおデコを相手とくっつけるだけで子供ができるという設定です。 宇宙人は地球人と生殖方法が違うというのがコールガールのところで前振りされてましたね。

綾瀬さんは知らない間に遠藤さんとの間に宇宙人式の子供を作る行為をされたわけです。

これって、僕たちの常識からしたら暴行事件ですよね完全に。

物語の中で、宇宙で生きるための条件とかいうことで優香さんが「宇宙では私たちの常識は通用しない」とか言うんですけど、こんなん受け入れられません。

見てる我々は地球人であり、現代の常識を持っています。こんな言い訳されても無理です納得できない。

というか登場人物に言い訳言わせないでくださいよ三谷さん。不快です。

で、遠藤さんが妊娠して出産するわけですが、なんかその場に居合わせたみんなが出産に手を貸してあげ始めちゃうんですよね。

そしたらなぜか綾瀬さんも私の子供だし頑張って産んで!的な感じで応援を始める始末。 全く理解できません!僕が綾瀬さんの立場だったら絶対嫌だわwwwww

香取さんも意味不明です。なんか、応援し始めちゃうんですよ。 自分の奥さんと知らないおっさんの間に子供ができて、その出産を応援する夫っていうなかなかない構図でした。

「出産」という行為は絶対的に祝福されるべきで、絶対的にいいことなんだ!という否定しがたい価値観の奥に様々な問題を隠しています。 そして出産という行為を盾に、この物語を批判しにくいものにしているように感じます。

いい話っぽくまとめてますが、ぜんっぜんいい話じゃないですよこれ。 ふざけてます。不愉快です。

ということで

僕はこの映画で三谷幸喜さんが大っ嫌いになりました。

エリックエヴァンスのドメイン駆動設計を読んでいる(第2部 第4章)

ドメインを隔離する

うちの現場でも採用されているレイヤー化アーキテクチャについての章。 プロダクトをUI層、アプリケーション層、ドメイン層、インフラストラクチャ層の4つに分けている。

上の層は下の層にただ一方的に参照を行うことができる。

このような制約をもたせて、各層に分けることで各層は凝縮度が高く、層ごとに疎結合な設計ができるらしい。

これによって例えばUIを変えたいのにインフラ周りまで影響を及ぼしていたりとかってことがなくなる。 これを守っていないと伝統的なスパゲッティ状態になるわけですね。

そう考えるとこれはとても大切な気がする。これを守らずに死んでいった開発者たちはきっと多いんだと思う。 そう考えるとなんか味わい深いですね。

UI層

ユーザーに情報を表示してユーザーのコマンドを解釈する責務を負う。

アプリケーション層

ソフトウェアが行う仕事を定義し、ビジネスにとって意味のあるものか、あるいは他のアプリケーション層と相互作用するために必要なものを扱う。このレイヤーは決してビジネスルールや知識は含まず、薄く保つことが大切。

ビジネスの状況は保持しないが、トランザクションなどの処理の状態は持つことができる。

ドメイン

ビジネスロジックを持つ。一番大事な核心部。

インフラストラクチャ層

上位のレイヤを支える技術的な機能を提供する。 DBにデータを永続化したり、他の層から利用される部品を入れておいたりする。

何より、ドメイン層を分離するということが大事

ここら辺についてはまた別の資料でお勉強する必要がありそう。

レイヤを関係づける

上位のレイヤ破壊のレイヤにある要素を直接使用したり操作したりできる。 これは、公開インタフェースを呼び出したり、要素の参照を保持したりするか、相互作用のための従来の手段を使用することによって行われる。

相互作用のための従来の手段を使用することってどういうことですかね?なんかイメージがわかないです。

アプリケーションがメールを送る必要がある場合、何らかのメッセージ送信インタフェースがインフラ層にあり、アプリケーション層がメッセージの送信を行う。アプリケーション層をシンプルにして、アプリケーション層が担うべき「メッセージをいつ送信するのかは知っているが、どのように送信するのかは知らない」という責務を果たさせる。

ここ今日まさに仕事中に考えてたことだw正解だったよかった。メッセージ送信のための部品はユーティリティとしてインフラ層に置いておいて、アプリケーション層が直接それを呼び出すように仕事でも設計した。メッセージングが別のサービスに切り替わる可能性も考えて、別のサービスとやりとりさせる場合に備えてアプリケーション層に実装しました。

エリックエヴァンスのドメイン駆動設計を読んでいる(第1部第3章)

モデルと実装を結びつける

ドメインモデルを持たないプロジェクトは知識のかみ砕きとコミュニケーションによる恩恵を受けることができない。

モデルを初期段階でのみ作成しモデルとコードとの結びつきを維持していないプロジェクトはモデルがだんだんと的外れになっていき、プロジェクトに悪影響を与えることすら出てくる。

モデル駆動設計では分析モデルと設計と分けずに、両方の目的に使える単一のモデルを作り出す。

モデル駆動設計では 分析としても設計としても利用可能なモデルとするために以下の2つの目的を満たすようにモデルを設計する。

  • 実装にとって実用的であること
  • ドメインの主要な概念を忠実に表現していること

感じたこと

ここはうちのプロセスと少し異なっているように感じています。

ドメインエキスパートを含むチームで概念モデルと呼ばれるモデルをまず作あ成し、それを受けて開発チーム内で分析モデルを作成しています。必要に応じて概念モデルはメンテナンスされるが分析モデルは実装前に作成されて、その後メンテナンスはされません。

チーム内では分析モデルは実装されたコードに現れるため別途作り出すのは無駄が多いという判断が行われました。概念モデルはドメインにとって主要な概念を表現し、文政モデルは実装にとって実用的であることを目指して作られている感じです。

あ、でも大きく外れていないかもしれない。

分析モデルは概念モデルの粒度を細かくしたもので概念モデル上のつながりなどなどは分析モデルでも守られるので。

分析モデルをそれぞれつなぎ合せて粒度を荒くしたら概念モデルが出来上がると思うので、プロジェクトの中でモデルは間違いなく1つと言えるのかもしれない。

ドメインエキスパートからドメイン知識を引き出す上では粒度が細かすぎない概念モデルの方が有利という判断なのかもしれない?

ここら辺はまた勉強していこう。別の現場での事例とかも知りたいかもしれない。

実践的モデラ

ソフトウェア開発は製造工程がなく全てが設計工程であり、単純な作業はない。

筆者の経験が語られている。過去に磨き上げたモデルがプロジェクトで使われなかったことがあり、その理由を2つ考えている。

  • モデルの意味が引き継ぎの際に失われた おそらくUML図やらなんやらでモデルを残していたのだろうがコードとして残すことはしなかった。そのため失われたのではないかと考察している。コードを通してが一番詳細が伝わりやすいということでしょう。

  • モデルが実装からフィードバックを得られなかった モデルのある側面が実装上うまくできていないなどの問題があったときでもモデラへのフィードバックはなかった。 そのため開発者は問題を含んでいるモデルを遵守することなく自分たちで実装を進めた。 同じような状況になったら同じことが起こりそうな気がします。というより自分がその実装者の立場だったらモデルは無視してしまうだろうなぁと感じる

心に留めておきたいことが書かれていました。 アプリケーションのためにモデルを機能させる方法を理解していない場合、そのモデルはソフトウェアと無関係になる

これ、上に書かれていることと全く同じことを、つい最近した気がします。とりあえず動いたらレビューに持っていけるしそれでいいじゃないか!という考え方でコーディングしていて爆死しました。この言葉はしっかりと心に刻んでおきましょう。。。

プログラマはモデラである必要がある。 モデルに貢献する人は誰しも一定の時間をコードに触れることに費やさなくてはならない。 コードの変更に責任を負う人は誰でも、コードを通じてモデルを表現することを習得しなければならない。

うん。すいません本当に。気をつけます。

ここまで読みながら、うちの現場では概念モデルを作っているアーキテクトの人はコードに触ってないなーと思って現場との違いを感じていましたが、どうやら第4部の「戦略的設計」のところでそこらへんのトピックを扱っていそうな雰囲気を感じる。気になるので先にそっちを読んでもいいかもしれない。

エリックエヴァンスのドメイン駆動設計を読んでいる(第1部第2章)

エリックエヴァンスドメイン駆動設計を読んでいます。 第1章第2部のまとめと感想をつらつらと書きます。 感想は斜体で書いてみてます。

コミュニケーションと言語の使い方

ユビキタス言語の重要性についてが語られている。

それぞれ異なる背景を持った開発者やドメインエキスパートがモデルの知識を蒸留していく過程において、用いる言語が統一されたユビキタスなものではなくてはいけない。

そうではない場合どうなるか?

そうでない場合は議論の中で、それぞれが使う言語を相手が理解できるように翻訳する必要が出てくる。これは手間であるし、そもそも翻訳が間違っていて正しく知識を伝えることができなかったりもする。

すると知識を蒸留していく中でズレが生じ、精製されたモデルに正しく知識が反映されていない状態になる。 モデルはそのままコードに反映されるため、得られるプロダクトは的外れなものになる可能性がある。

コミュニケーションミスを減らす意味でも、コストを減らす意味でもユビキタス言語が大切になる。 ドメインモデルはそのユビキタス言語の基盤となる。 ドメインモデルに、モデルが従うべきルールやドメインモデルに対して適用されるパターンの名前によってユビキタス言語は構成される。

そのためチームのメンバーはこれらの概念を理解している必要があるのではないかと考えるのですが、ドメインエキスパートにそれを求めてもなかなかハードルが高いのではないですかね。各現場ではどうやっているのだろう。というかうちではどうやってるのだろうか。確認してみよう。

ユビキタス言語を使って議論をしていくわけだが、その中である単語がどうにもしっくりこない場面があるだろう。 その場合はユビキタス言語を更新するわけだが、その際には同時にモデルも変更されるという点を意識する必要がある。しっくりこないようなモデルは使い続けるべきではなく、フィードバックを受けて改良されるべきだからだ。

声に出してモデリングする

モデルを中心に会話をしていくことが大事だと述べられている。 声に出すことで話していることが整理できるという経験はいくらでもあるし、議論を行う上で一番優れているのは直接会話することだと思うので、会話することが大事であるというのはその通りなんだと思う。

ドキュメントと図

モデルを図示するにあたり、全ての要素を詳細に図示する必要はないということが述べられている。 詳細はコードが示すので、モデルでは大切な考え方の骨格を提供することが肝要だ。 うちの現場ではモデルを概念モデルと詳細モデルに分けているが、詳細モデルであっても全ての詳細を書き出したりはしない。概念モデルはその名前の通りモデルの相互作用を表した概念を示すものであり、詳細モデルは開発する上で参考にするハンズオンなモデルという位置付けという感じにしていたはず。概念モデルとか詳細モデルとかってこの本で後々出てくるのかな?まあ読み進めてみます。

読んで感じたこと

今の現場においてこれはなかなか徹底されていないようにも思う。 アカウントや人というモデルが出てくるが、ユーザーという呼び方をしていたりするところもある。 統一するべきということを念頭に置きつつ、ユーザーというモデルに変えるべきか否かという観点も持っておこう