境界を考える
特にfpにおける境界の表現方法をまとめたい
それらの表現を何らかでグルーピングしたい
この辺
getterを用意する
中間構造を用意する
型クラスを用いた境界
code:hs
-- ServiceBoundary.hs
class ServiceBoundary s where
execute :: s -> IO ()
-- ServiceImpl.hs
data ServiceImpl = ServiceImpl
instance ServiceBoundary ServiceImpl where
execute _ = putStrLn "Executing service..."
-- Client.hs
run :: ServiceBoundary s => s -> IO ()
run service = execute service
runは抽象であるServiceBoundaryにのみ依存している
具体的なServiceImplには直接依存していない
具体的な実装はinsntance内に定義している
関数型を用いた依存
code:hs
type ServiceBoundary = () -> IO ()
serviceImpl :: ServiceBoundary
serviceImpl = putStrLn "Executing service..."
run :: ServiceBoundary -> IO ()
run service = service
tsでもcallbackとして依存をinjectionするパターンとして使える
テストとDBで実際の処理を変えるなど
具体的な型に依存
code:hs
-- Service.hs
data Service = Service
executeService :: Service -> IO ()
executeService _ = putStrLn "Executing service..."
-- Client.hs
runWithService :: Service -> IO ()
runWithService service = executeService service
runWithServiceは具体的なデータ型Serviceに依存している
関数の境界について
関数をラップして関数を作る?
どういう工夫をしてるんだっけ
関数に多態性をもたせて、関数自体が特定の具体型に依存しないようにしている
データ構造側にもなにかもっと工夫がありそうだが
moduleの境界について
関数等を考える時にinterfaceが大事なのと同様に、moduleに対してもinterfaceが大事、となるはず
抽象度が違うだけでずっと同じ話をしている
https://gyazo.com/8047afecd9a2bbb33d2f8bcd1aea3108
moduleのinterfaceとはなにか?というと、
import文とexport文ということになる
privateな関数はmoduleに閉じている
publicな関数がmoduleから開かれている口である
publicな口さえ変わらなければ、privateな部分はいくら変更しても外に影響を与えない
外部からprivateなものにも触りたくなった場合は、interfaceを設計し直す必要がある
外部がやりたいことがおかしい
publicなもので表現しているものが弱すぎる
moduleを分離して関係性を設計し直すとか
https://gyazo.com/406f3f71193619c5cc58131633867e4c
境界がどうのこうのを考えるとき
依存の方向を一定にする、というのはだいぶ前提にある
抽象度を分けて、具体的なものを隠していく
どこまでがこの概念のpackage内なのか、という判断が必要