4. What is a domain model ?
A domain model in problem solving and software engineering is a
conceptual model of all the topics related to a specific problem. It
describes the various entities, their attributes, roles, and
relationships, plus the constraints that govern the problem domain.
It does not describe the solutions to the problem.
Wikipedia (http://en.wikipedia.org/wiki/Domain_model)
特定の問題領域に関する概念モデル
エンティティ/関連/制約などを記述
Saturday, 30 January 16
5. The Functional Lens ..
“domain API evolution through algebraic
composition”
関数型レンズ
代数的合成を通じたドメイン API の進化
Saturday, 30 January 16
13. A Bounded Context
• has a consistent vocabulary
• a set of domain behaviors modeled as
functions on domain objects
implemented as types
• related behaviors grouped as modules
境界づけられたコンテキストは、統一された語彙を持つ
ドメインの振る舞いは関数、オブジェクトは型として実装するSaturday, 30 January 16
14. Domain Model = ∪(i) Bounded Context(i)
Saturday, 30 January 16
16. Domain Model = ∪(i) Bounded Context(i)
Bounded Context = { f(x) | p(x) ∈ Domain Rules }
• domain function
• on an object of type x
• composes with other functions
• closed under composition
• business rules
f はドメイン関数で、他の関数と合成できる
p はビジネスルール
Saturday, 30 January 16
21. Domain Model Algebra
(algebra of types, functions & laws)
explicit
• types
• type constraints
• expression in terms of other generic algebra
これを明示的にすると、型、型の制約、他の代数を用いた表現
Saturday, 30 January 16
22. Domain Model Algebra
(algebra of types, functions & laws)
explicit verifiable
• types
• type constraints
• expr in terms of other generic algebra
• type constraints
• more constraints if you have DT
• algebraic property based testing
確認可能なのは型制約、代数的プロパティーベースのテスト
依存型があればより強い制約を検証できる
Saturday, 30 January 16
32. Domain Model = ∪(i) Bounded Context(i)
Bounded Context = { f(x) | p(x) ∈ Domain Rules }
• domain function
• on an object of type x
• composes with other functions
• closed under composition
• business rules
Domain Algebra
Domain Algebra
「境界づけられたコンテキスト」はドメイン代数のこと
Saturday, 30 January 16
33. Client places order
- flexible format
1
クライアントが注文を出す
フォーマットは様々
Saturday, 30 January 16
34. Client places order
- flexible format
Transform to internal domain
model entity and place for execution
1 2
内部でのドメインモデルエンティティに変換して、
実際に注文を出す
Saturday, 30 January 16
35. Client places order
- flexible format
Transform to internal domain
model entity and place for execution
Trade & Allocate to
client accounts
1 2
3
取引し、結果をクライアントのアカウントに紐づける
Saturday, 30 January 16
38. def clientOrders: ClientOrderSheet => List[Order]
def execute: Market => Account => Order => List[Execution]
def allocate: List[Account] => Execution => List[Trade]
Types out of thin air No implementation till now
Type names resonate domain language
どこからともなく降ってきた型。今の所実装の話はゼロ。
型の名前はドメイン言語を反映
Saturday, 30 January 16
42. Algebraic Design
• The algebra is the binding contract of the
API
• Implementation is NOT part of the algebra
• An algebra can have multiple interpreters
(aka implementations)
• One of the core principles of functional
programming is to decouple the algebra from
the interpreter
代数的設計手法: 代数は API が準拠する制約
実装は代数に含まれず、実装からは分離されている
Saturday, 30 January 16
43. def clientOrders: ClientOrderSheet => List[Order]
def execute: Market => Account => Order => List[Execution]
def allocate: List[Account] => Execution => List[Trade]
let’s do some algebra ..
代数の練習
Saturday, 30 January 16
44. def clientOrders: ClientOrderSheet => List[Order]
def execute(m: Market, broker: Account): Order => List[Execution]
def allocate(accounts: List[Account]): Execution => List[Trade]
let’s do some algebra ..
Saturday, 30 January 16
45. def clientOrders: ClientOrderSheet => List[Order]
def execute(m: Market, broker: Account): Order => List[Execution]
def allocate(accounts: List[Account]): Execution => List[Trade]
let’s do some algebra ..
Saturday, 30 January 16
46. def clientOrders: ClientOrderSheet => List[Order]
def execute(m: Market, broker: Account): Order => List[Execution]
def allocate(accounts: List[Account]): Execution => List[Trade]
let’s do some algebra ..
Saturday, 30 January 16
47. def clientOrders: ClientOrderSheet => List[Order]
def execute(m: Market, broker: Account): Order => List[Execution]
def allocate(accounts: List[Account]): Execution => List[Trade]
let’s do some algebra ..
Saturday, 30 January 16
48. def clientOrders: ClientOrderSheet => List[Order]
def execute(m: Market, broker: Account): Order => List[Execution]
def allocate(accounts: List[Account]): Execution => List[Trade]
let’s do some algebra ..
Saturday, 30 January 16
49. def f: A => List[B]
def g: B => List[C]
def h: C => List[D]
.. a problem of composition ..
これは ... 合成の問題だ
Saturday, 30 January 16
50. .. a problem of
composition with effects ..
def f: A => List[B]
def g: B => List[C]
def h: C => List[D]
これは ... 作用付きの合成の問題だ
Saturday, 30 January 16
51. def f[M: Monad]: A => M[B]
def g[M: Monad]: B => M[C]
def h[M: Monad]: C => M[D]
.. a problem of composition with
effects that can be generalized ..
これはモナドとして抽象化できる作用付きの合成の問題だ
Saturday, 30 January 16
52. case class Kleisli[M[_], A, B](run: A => M[B]) {
def andThen[C](f: B => M[C])
(implicit M: Monad[M]): Kleisli[M, A, C] =
Kleisli((a: A) => M.flatMap(run(a))(f))
}
.. function composition with
Effects ..
It’s a Kleisli !
作用付きの関数の合成と言えば、Kleisli!
Saturday, 30 January 16
57. def tradeGeneration(
market: Market,
broker: Account,
clientAccounts: List[Account]) = {
clientOrders andThen
execute(market, broker) andThen
allocate(clientAccounts)
}
Implementation follows the specification
and we get the Ubiquitous Language for
free :-)
.. the complete trade generation
logic ..
実装は仕様に従い、
そこからユビキタス言語を読み取ることが出来る
Saturday, 30 January 16
58. algebraic & functional
• Just Pure Functions. Lower cognitive load -
don’t have to think of the classes & data
members where behaviors will reside
• Compositional. Algebras compose - we
defined the algebras of our domain APIs in
terms of existing, time tested algebras of
Kleislis and Monads
代数的かつ関数型の設計は、
純粋関数のみで構成する、合成可能な設計
Saturday, 30 January 16
59. def clientOrders: Kleisli[List, ClientOrderSheet, Order]
def execute(m: Market, b: Account): Kleisli[List, Order, Execution]
def allocate(acts: List[Account]): Kleisli[List, Execution, Trade]
.. our algebra still doesn’t handle errors
that may occur within our domain
behaviors ..
.. function composition with
Effects ..
そう言えばエラー処理どうする?
Saturday, 30 January 16
62. def clientOrders: Kleisli[List, ClientOrderSheet, Order]
return type constructor
What happens in case the operation fails ?
演算が失敗したらどうなる?
Saturday, 30 January 16
63. Error handling as an
Effect
• pure and functional
• with an explicit and published algebra
• stackable with existing effects
def clientOrders: Kleisli[List, ClientOrderSheet, Order]
モナド作用としてのエラー処理
純粋で関数型に。明示的な代数。既存の作用と積み上げ可能。
Saturday, 30 January 16
64. def clientOrders: Kleisli[List, ClientOrderSheet, Order]
.. stacking of effects ..
M[List[_]]
作用の積み上げ
Saturday, 30 January 16
65. def clientOrders: Kleisli[List, ClientOrderSheet, Order]
.. stacking of effects ..
M[List[_]]: M is a Monad
List をエラー処理のためのモナド M で囲む
Saturday, 30 January 16
66. type Response[A] = String / Option[A]
val count: Response[Int] = some(10).right
for {
maybeCount <- count
} yield {
for {
c <- maybeCount
// use c
} yield c
}
Monad Transformers
モナド変換子
Saturday, 30 January 16
67. type Response[A] = String / Option[A]
val count: Response[Int] = some(10).right
for {
maybeCount <- count
} yield {
for {
c <- maybeCount
// use c
} yield c
}
type Error[A] = String / A
type Response[A] = OptionT[Error, A]
val count: Response[Int] = 10.point[Response]
for{
c <- count
// use c : c is an Int here
} yield (())
Monad Transformers
Saturday, 30 January 16
68. type Response[A] = String / Option[A]
val count: Response[Int] = some(10).right
for {
maybeCount <- count
} yield {
for {
c <- maybeCount
// use c
} yield c
}
type Error[A] = String / A
type Response[A] = OptionT[Error, A]
val count: Response[Int] = 10.point[Response]
for{
c <- count
// use c : c is an Int here
} yield (())
Monad Transformers
richer algebra
代数として扱いやすいのは OptionT を使った方
Saturday, 30 January 16
69. Monad Transformers
• collapses the stack and gives us a single
monad to deal with
• order of stacking is important though
モナド変換子は積み上げたモナドを一つに潰すことができる
ただし積み上げる順番は大切
Saturday, 30 January 16
70. def clientOrders: Kleisli[List, ClientOrderSheet, Order]
.. stacking of effects ..
case class ListT[M[_], A] (run: M[List[A]]) { //..
ListT モナド変換子を使う
Saturday, 30 January 16
91. .. the algebra ..
trait OrderLaw {
def sizeLaw: Seq[ClientOrder] => Seq[Order] => Boolean =
{ cos => orders =>
cos.size == orders.size
}
def lineItemLaw: Seq[ClientOrder] => Seq[Order] => Boolean =
{ cos => orders =>
cos.map(instrumentsInClientOrder).sum ==
orders.map(_.items.size).sum
}
}
laws of the algebra
(domain rules)
代数の法則
Saturday, 30 January 16
92. Domain Rules as
Algebraic Properties
• part of the abstraction
• equally important as the actual
abstraction
• verifiable as properties
代数的プロパティとしてのドメインルール
プロパティとして検証可能となる
Saturday, 30 January 16
93. .. domain rules verification ..
property("Check Client Order laws") =
forAll((cos: Set[ClientOrder]) => {
val orders = for {
os <- clientOrders.run(cos.toList)
} yield os
sizeLaw(cos.toSeq)(orders) == true
lineItemLaw(cos.toSeq)(orders) == true
})
property based testing FTW ..
プロパティベーステスト最強
Saturday, 30 January 16