関数の引数にEntityを丸ごと取るのと、fieldごとに取ることの差異
例えばこんなEntityがあるとする
code:ts
type User = {
id: UserId;
name: string
age: number
address: Address;
}
ここで、以下のような関数を作るとする
code:ts
const hello = (???) => {
return ${name} is ${age} years old
}
内部で使っているのは、nameとageの2つである
この場合、引数はどうするべきか?
考えられるのは以下の2パターン
code:ts
hello: (name: string; age: number): string
hello: (user: User): string
この2つは、interfaceの表す意味合いが全く異なる
その関数が、そのentityと、意味的にどれぐらい親しいものなのか、を考える必要がある
当然、entityを丸ごと取るほうが、その関数と密に結合することになる
そのentityの構造が変わった時に、その関数に影響があって然るべきか?を問う
意味的に異なる場合は分ける
わかりやすい例として、UI Componentの引数にentityそのものを取るケースは少ない気がするmrsekut.icon
entityにおける変更と、Viewに何を表示するかが、何の関連性もない場合は、引数を分けるべき
無駄にentityに依存させない
例えば、ツイートを表す1つのComponentがあったとする
https://gyazo.com/d260b95d2e188512eefeb1f8a6437d80
元のUser Entityが、{name: string, nickname: string: img: string}で、
後に{age: number}が追加されようと、このComponentにとっては知ったこっちゃない
「Entityにそのfieldがあること」と「Viewに表示すること」に何の関連性もない
例え、デザイン的にたまたま年齢も表示することがあったとしても、それは「Entityにそのfieldがあること」が理由なわけではない
デザインとして必要があったから表示しているだけ
意味的に親しい場合は、interfaceを考える
同じmodule内に配置している関数は、そこで定義されるentityに関連する関数であることは自明に決まる
ただ、「意味的に親しい」場合に、常に塊で取るべきなのか
いくつかの観点がありそう
その関数の利用者は、どの形式であるのが一番扱いやすいのか
どの形式の関数だとテストしやすいのか
どの形式の関数だと変更に耐えるのか
どの形式の関数だと意図を明示できるだろうか
引数を塊で取ることの問題点は、
そのentityと、その関数が密結合になる
従って、そのentityに変更が入った際に、それらの関数全てに影響する
そのentityを後から分割したとか、構造を変えた、場合
引数を個別に取ることの問題点は、
利用者が毎回個別に値を指定しなければならず面倒くさい
型が同一の場合に、引数を渡す順序を間違える
変更容易性に倒しすぎた結果、利用者の認知コストが上がりうる
ただ、塊で取る場合は、その塊が、そのプロダクト内で整合性のあるものじゃないと意味がない
これはentityの設計の話mrsekut.icon
その関数の利用者が、関数を利用するためだけに、毎回塊を作っているようでは何も便利になってない
無駄なfieldも含まれるので、個別に取るよりもむしろだるくなってる
どうするか
関数にレイヤーを設ける
module内のprivateな関数は、個別に引数を取り、publicなものは塊でとるとか?
例えば、entity内の関数は個別に取り、usecase内の関数は塊で取るとか?
これ解決になってる?
entityを小さく区切っていき、その塊を引数に取るようにするとか
最初の問題は、objectの構造が変わった時に意味が変わってしまう、というものだった
だから、最初からatomicなグループに分けて作ることでその可能性を小さくする
まあobjectならまだマシか
配列でデータを表現してるのはかなりキツイ
しかも動的型付言語でやるのは狂気の沙汰とも思える
配列の0番目がnameで、1番目がageみたいなデータ
当たり前過ぎて考えもしなかった
RubyではSturct.newを使う
PHPでは小さいclassを作る
そのオブジェクトにしようとしている組が概念として密ならば、そうするのはアリという感じらしい
マジで「密」ならそうかも知れないが、迷うぐらいならバラバラにすべきだと思うmrsekut.icon