の振り返りの振り返りの見てて思い付きのメモです。
お題は、タイトル通り
適切な場所で情報開示することが難しい
と、抽象データ型
の相性ってやっぱ悪いよねー?という話
カプセル化の問題点(再載)
悪い側面
-
状態管理を隠匿するアイディアの失敗今回は削り - 適切な場所で情報開示することが難しい
また、カプセル化は、あくまでも情報隠匿であり、良い悪いがあるはずなのに、"良い"のイメージが強く乱用されている。
"悪い"の分かりやすい例として、ValueObject(同時に盛り上がってた)の文脈で出てくる、局所化しすぎて不適切な場所からの情報開示がある。
例えば、
年齢によるサイトの利用制限がある際に、利用制限の判定メソッドを年齢オブジェクトに生やしてしまう。
たぶん、どっかにもっと良い記事あるはず。
さらに、本来開示されるべき情報さえも、不要に情報隠匿してしまうことがある。処理の流れを理解のに大きな妨げになる。Inputに対してのOutputとしてシンプルに表現した方が分かりやすいことも多い。
-- ここまで
今回は、"不要に情報隠匿してしまう"を取り上げたいと思います。
やっぱりカプセル化の情報開示がうまくいかない
お題
これをお題として、コード上の抽象表現を考えてみます。
🐶 解決対象
「GoogleまたはFacebookで認証属性を取得したい」
🐶 モデル
* 認証属性を取得する
* GoogleまたはFacebookを取得に利用する
安易にinterfaceで抽象化
interface AuthAttributeProvider
getAttribute()
よくある抽象化に見えますが、このオブジェクトを利用する「ユーザー」からは、Google
とFacebook
が利用されることが、完全に分からなくなります。"getAttribute
を正しく履行することが出来ます。その中身は教えません"というinterfaceとしては正しいのですが、Google
とFacebook
は本来開示されるべき情報で、それさえも不要に隠匿されてしまいます。(だよね?)
あえて抽象型を導入しない
class GoogleAuthAttributeProvider
getAttribute()
class FacebookAuthAttributeProvider
getAttribute()
だったら愚直に定義してしまえとなり、こうするとGoogle
とFacebook
を利用するという情報が伝えられるようになります。が、これはこれで普通に問題があります。(前回、推してたやつですが、前回は開発手法ありきの文脈なわけで、今回は抜き去って考えます)
"認証属性を取得する"という共通性の情報が隠れるどころか"消えて"しまいます。そして、これは"ユーザー"の利用上の負担を増大させます。"関連するデータの集合とその振舞いを閉じ込める"という、そもそものカプセル化という目的がうまくいっていません。
組み合わせる
interface AuthAttributeProvider
//の実装で
class GoogleAuthAttributeProvider
class FacebookAuthAttributeProvider
//↑を利用する
だったら全部盛り
AuthAttributeProvider
の実装で、Google
とFacebook
に移譲するなりして分割すればよい。こちらはオブジェクトとモデルが対応するため、↑二つに比べると良い分割が出来たように感じます。
ですが、"ユーザー"視点に立ち返るとどうでしょうか。Google
とFacebook
が見えないことは同じで、不要な情報隠匿してることは変わりません。
すると、代数的データ型?
言語とか抜きで、"ユーザー"の視点に対して、全ての情報を開示したまま分割を考えるとどうでしょうか。代数的データ型とかぱっと思いつきます。
type AuthAttributeProvider = GoogleAuthAttributeProvider | FacebookAuthAttributeProvider
これなら、定義情報にもGoogle
とFacebook
が残り、両者の共通性をもって適切に抽象化されてるので、良い感じに感じます(語彙なし)?
まとめ抽象データ型あまりいらなくない?
まとめると、単一の抽象データ型と振る舞い(ポリモーフィズム)だけでは、現実世界のそれをうまく分割できないため、やはり歪みを感じます。複数のデータ型と、それにまたがるインターフェースが必要です。それが無ければ自然な表現が出来ません。これは代数的データ型や型クラス的なアレがないと無理なんじゃないかなと感じます。
あとは暴論で、個人の開発能力の成長の過程で、抽象データ型によるカプセル化が難しいと感覚的に気付くタイミングがある気がします。気づいてしまうと、抽象データ型がめんどくて窮屈なものでしなく、interface(抽象型)を使って疎結合に保つ機構としてしか使わなくなります。これが今のオブジェクト指向プログラミングの正体ではないでしょうか。それって、抽象データ型としてのオブジェクト指向プログラミングは、終わった。よね!
抽象データ型に、直和
を足してあげれば良いだけとか言われそうだけど、まあまあ。
あとがき
カプセル化の情報隠蔽ってそういう意味じゃないよーとか、分かる方は教えて頂けると助かります。なんか不安。