業務システムのための型システム

30
業務システムのための型システム ビジネスモデルを表現する 振る舞いと構造の変更に型クラスを使う 2010/0818

Upload: zenji-kanzaki

Post on 19-Jul-2015

970 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 業務システムのための型システム

業務システムのための型システム

ビジネスモデルを表現する

振る舞いと構造の変更に型クラスを使う

2010/0818

Page 2: 業務システムのための型システム

㈱バリューソース 代表取締役

神崎 善司

[email protected]

はてな:good_way

twitter:@zenzengood

普段は 要件定義関連のコンサルテーション

セミナー開催(要件定義、オブジェクト指向、モデリング)

「要件のツボ」の開発

関数型との関係 7年くらい前から関数型に興味を持ち

CleanやF#をつまみ食いしながらScalaを発見!

以来サンデープログラマーとしてScalaを利用

「要件のツボ」のサーバーサイドで利用

札幌の技術者との交流の中で関数型がだんだんわかりかけてきた…

わたしは…

2

Page 3: 業務システムのための型システム

なにがしたいの?

ビジネスモデルを構造として定義する

ニーズ

コンサルの初期段階でお客さんのビジネスモデルを早く把握する必要がある

ビジネスモデルの基本構造を記述

シナリオベースで動かして確認したい

コードにすることでメタ構造を洗い出す

Page 4: 業務システムのための型システム

ビジネスモデル 販売管理

会社顧客

入金

注文

請求

BtoC 前払いサービス提供不特定多数の顧客に対して継続的なサービス提供

人のサービス

ライセンスサービス

ワークフロー管理

サービス提供

or

会社得意先

商品

入金

注文

BtoB 後払い商品販売特定顧客に対して商品の販売

請求書

与信

検収 債権管理デリバリ

在庫引当

会員登録

Page 5: 業務システムのための型システム

ビジネスモデルによるデータ構造の違い

会社顧客

入金

注文

請求

人のサービス

ライセンスサービス

ワークフロー管理

サービス提供

or

会員登録

受注 受注明細

後払:

請求 入金

受注・請求が同時入金確認後出荷

検収

前払:

受注 受注明細

請求 入金

検収確認後請求・入金

債権残高売上

BtoC 前払いサービス提供不特定多数の顧客に対して継続的なサービス提供

BtoB 後払い商品販売特定顧客に対して商品の販売

受注

出荷

受注明細

出荷明細

売上

債権残高

請求 入金

・分割納品・出荷まとめ

・請求まとめ・一部入金

債務残高

支払い

相殺

会社得意先

商品

入金

注文

請求書

与信

検収 債権管理デリバリ

在庫引当

Page 6: 業務システムのための型システム

販売管理 典型的なデータ構造

受注 受注明細

出荷 出荷明細

売上

債権残高

入金

受注明細受注明細

出荷明細

受注

出荷

受注明細

出荷明細

分納がある場合は受注1に対して出荷は多になる

前払いの場合は債権残高がない

売上 請求入金

売上

債権残高

請求

入金

複数の受注をまとめて出荷する場合は出荷1で受注多になる

受注 受注明細

出荷明細

・分割納品・出荷まとめ

請求請求

入金

・請求まとめ・一部入金

債務残高支払い

相殺

出荷指示

出荷指示出荷

検収

オブジェクトモデル クラスモデル

明細単位で処理しない場合は受注・出荷で結びつく

複数の請求分をまとめて入金(都度請求)

分割入金

工程

Page 7: 業務システムのための型システム

例えば 販売管理のバリエーション

商品 得意先

A単価商品

B単価

単価の設定

見積・受注 → 見積もり・受注先出荷 → 出荷先請求・入金 → 請求先

顧客との関係

例)Webベースのサービスデリバリがないので出荷先が必要ない請求先はメールだけで請求書送付がない

例)単価の決まり方商品に直接単価が紐尽く得意先によって商品の単価が異なる

例)前払い 後払い後払いには与信が必要前払いは債権残高がない~

ビジネスシステムは一つ一つは簡単だが、バリエーションと組み合わせが多岐にわたる

Page 8: 業務システムのための型システム

シナリオ 前払いのサービス提供

//田中商事(101)からリンゴ10個、ミカン20個を受注val 田中商事受注 = CE受注(1,Date.valueOf("2012-01-21"),1,2)受注機能.受注登録(田中商事受注)//佐藤商事(102)からメロン20個、ミカン10個を受注val 佐藤商事受注 = CE受注(2,Date.valueOf("2012-02-21"),2,3)受注機能.受注登録(佐藤商事受注)

//出荷指示対象の受注一覧受注機能.受注残一覧.foreach( e => println(e.body))

//田中商事の受注に対して出荷指示val 田中商事出荷指示 = CE出荷指示(1,Date.valueOf("2012-01-22"),1)出荷指示機能.出荷指示登録(田中商事出荷指示)

受注機能.受注残一覧.foreach( e => println(e.body))

単純なシナリオでビジネスモデルの確認を行う

Page 9: 業務システムのための型システム

型クラスとは

ビジネスモデルの多様性を型クラスを使って表現したい

Page 10: 業務システムのための型システム

型クラス type classtrait Ord[T] {

def compare (x: T, y: T): Boolean } case class MyModel(val data: Int) implicit object ordMyModel extends Ord[MyModel] {

def compare (m1: MyModel, m2: MyModel) = m1.data <= m2.data }

def greedy[T](m1: T,m2: T)(implicit ordM: Ord[T]) = if (ordM.compare (m1,m2)) m2 else m1

-------------------val m1 = new MyModel(3) val m2 = new MyModel(5)greedy(m1,m2)

Sideways Coding:http://www.sidewayscoding.com/2011/01/introduction-to-type-classes-in-scala.html

Ord[T]

Ord[MyModel]

構造Tを型パラメータにもつOrdのサブクラス(Ord[MyModel])を割り当てる

これは何????

Ord[XXModel]

MyModelのcompareの実装

Page 11: 業務システムのための型システム

振る舞いを汎化し構造を型パラメータで変える

振舞クラス[型]

振舞の拡張[型拡張]

振る舞いを汎化で拡張 構造は型パラメータにより任意のクラスを使える

振る舞いの拡張にあわせて型の拡張も可能

構造

構造

構造

構造

Xxxxx[T <: 構造]

型パラメータを汎化

Ord[T]

Ord[MyModel]implicit object ordMyModel extends Ord[MyModel] {

def compare (m1: MyModel, m2: MyModel) = m1.data <= m2.data }

Page 12: 業務システムのための型システム

例:グラフを処理する

A

B

Node

Node Link

アルゴリズム

総当たり戦~~

AからBまでの2地点の経路を求める

構造

構造と振る舞いを変えられるようにするにはどう考えればいいのか?

Page 13: 業務システムのための型システム

グラフ構造を抽象化する

<trait>Neighbors[Edge]

neighbors

<object>Route

routes

trait Neighbors[Edge] {def neighbors(e:Edge):List[Edge]

}

def routes[Edge](from:Edge,to:Edge) (implicit nghbrs:Neighbors[Edge]) :List[List[Edge]] ={

neighborsで得られたEdgeを使って経路を導き出す

}

<routes>neighborsで得られたEdgeを使って経路を導き出すロジックをもつ

構造にあったNeighborsを与えることで任意の構造に対応するNeighborsを処理できる

<Neighbors[Edge]>グラフ構造をお隣さんという概念で抽象化する

実際の構造にあったお隣さんを返す

Page 14: 業務システムのための型システム

経路処理を実際の構造に注入する<trait>

Neighbors

neighbors

<object>Route

routes

Base Pathwayedge1

edge2

links

trait Neighbors[Edge] {def neighbors(e:Edge):List[Edge]

}

def routes[Edge](from:Edge,to:Edge)(implicit nghbrs:Neighbors[Edge]):List[List[Edge]] ={

Service

getRoutes

implicit def base2route(b:Base):{def routes(to:Base):List[List[Base]]} = new Object{ def routes(to:Base):List[List[Base]] = Route.routes(b,to)

}

implicit object BaseNeighbors extends Neighbors[Base]{def neighbors(base:Base):List[Base] = {base.links.map(_.opposite(base)).toList

}}

def getRoutes(from:Base,to:Base):List[List[Base]] = from.routes(to)

Baseにroutesを後付けする

今回Edgeに対応するデータ構造

外部からの入り口

routes

Page 15: 業務システムのための型システム

ビジネスモデルを表現する

ビジネスモデルのバリエーションを型クラスを使って表現する

ビジネスモデルの違いを振る舞いと構造の違いととらえる

その違いを型クラスで表現する

Page 16: 業務システムのための型システム

ビジネスモデルの要素を組み替える

会社顧客

入金

注文

請求

BtoC 前払いサービス提供不特定多数の顧客に対して継続的なサービス提供

人のサービス

ライセンスサービス

ワークフロー管理

サービス提供

or

BtoB 後払い商品販売特定顧客に対して商品の販売

会員登録

<<消込残>>ピッキング

リスト

<<消込残>>納品書

<<消込残>>見積書

<<消込残>>請求書見積 受注

出荷指示

出荷 入金<<消込残>>

注文書

見積もり 受注 出荷指示 出荷 請求書 入金

会社得意先

商品

入金

注文

請求書

与信

検収

債権管理

デリバリ

在庫引当

Page 17: 業務システムのための型システム

ビジネスモデルによってフローが変わる<<消込残>>ピッキング

リスト

<<消込残>>納品書

<<消込残>>見積書

<<消込残>>請求書見積 受注

出荷指示

出荷 入金<<消込残>>

注文書

見積もり 受注 出荷指示 出荷 請求書 入金

後払い商品販売

前払いサービス提供

Page 18: 業務システムのための型システム

importでコンテキスト変える

<<消込残>>ピッキング

リスト

<<消込残>>納品書

<<消込残>>見積書

<<消込残>>請求書見積 受注

出荷指示

出荷 入金<<消込残>>

注文書

見積もり 受注 出荷指示 出荷 請求書 入金

Meta Layer

消込 残高

リソース

管理単位

Business Layer

見積 受注 出荷指示 出荷 請求書 入金

実装 implicit

A B

ビジネスモデルの違いをコンテキストを変えて実現

少数の概念でBusinessLayerを実現

Business Layerの知識でプログラミング

BtoC 前払いサービス提供不特定多数の顧客に対して継続的な

サービス提供

BtoB 後払い商品販売特定顧客に対して商品の販売

Import A or B ⇒ コンテキストを変える

Page 19: 業務システムのための型システム

ビジネスレイヤー

実現

<<消込残>>ピッキング

リスト

<<消込残>>納品書

<<消込残>>見積書

<<消込残>>請求書見積 受注

出荷指示

出荷 入金<<消込残>>

注文書

メタレイヤー消し込み 残高

見積もり 受注 出荷指示 出荷 請求書 入金

コンクリートレイヤー:後払い商品販売

コンクリートレイヤー:前払サービス提供

APP

Import A or B ⇒ コンテキストを変える

一般的な振る舞いと構造を定義する

ビジネスモデルとしての具体的な構造と振る舞いを定義

メタレイヤーで処理の前後関係をつなぐ

ドメインを利用するアプリケーションはビジ

ネスレベルを利用する

具体的な永続化の機構もここで指定する

Page 20: 業務システムのための型システム

Meta Level

受注

出荷

消込対象

消込対象

消込残

消込残

消込対象

個々のEntityで消し込み済みのもの

消込済

ビジネスの基本概念

・消込と残高という2つの概念でビジネスを捉える

・消し込み受注→在庫引き当て 消込在庫引き当て→出荷 消込

・残高出荷→在庫減 残高入荷→在庫増 残高

商品を受注したら出荷して受注を消し込む

<<trait>>T消込操作

消込対象():Seq[Tentity]消込済():Seq[T消込Wrapper]消込残():Seq[T消込Wrapper]クエリー(条件)後続機能()

後続機能()

Page 21: 業務システムのための型システム

ビジネスレベル

<<消込残>>ピッキング

リスト

<<消込残>>納品書

<<消込残>>見積書

<<消込残>>請求書見積 受注

出荷指示

出荷 入金<<消込残>>

注文書

見積もり 受注 出荷指示 出荷 請求書 入金

・一般的な業務処理をビジネスレイヤーで記述・各処理の前後関係は記述しない・前後関係はコンクリートレイヤーで記述する

object受注機能

受注登録受注残一覧

trait受注消込

TE受注

_id:TID_受日:Date _顧客CD: TCID_管理組織CD:TOCD

消込済(ent)消込残(ent)copy

TE受注明細

_商品:TID_数量:Date _金額: TCID

Page 22: 業務システムのための型システム

出荷

コンクリートレベル販売管理 後払い商品販売

受注

モジュール

見積もり

得意先 商品 組織

出荷

請求・入金

得意先 商品 組織

見積もり 受注 受注明細

出荷予定

売上 債権残高 入金

見積 受注

R

CRUD

<<消込>>見積消込済

<<消込残>>見積残

<<CRUD>>見積登録

見積明細

R

CRUD<<消込残>>

受注残

<<CRUD>>受注登録

RCRUD

<<消込残>>出荷残

CRUD

<<CRUD>>入金登録

<<CRUD>>出荷指示登録

出荷指示

出荷 入金

<<CRUD>>売上登録

CRUD

CR

<<消込残>>ピッキング

リスト

注文を登録

<<消込残>>納品書

見積もり登録 出荷を指示する 出荷登録

在庫

在庫引き当て

入荷

消込 消込

<<消込残>>見積書

消込

<<消込残>>請求書

終端消込

残高

<<請求残>>請求データ

作成

終端消込

<<減算>>債権減

<<加算>>債権減

消込消込

U U

出荷 出荷明細

CRUD

<<CRUD>>出荷登録

消込

型クラス

<<消込>>受注消込済

R

<<消込>>出荷指示消込済

<<消込>>出荷消込済

予定明細

Page 23: 業務システムのための型システム

コンクリートレベル販売管理 前払いサービス提供

受注

得意先 商品 組織

サービス請求・入金

得意先 商品 組織

受注 受注明細サービス

売上

請求入金

受注

R

CRUD

<<消込>>受注消込済

<<消込残>>受注残

<<CRUD>>受注登録

RCRUD

CRUD

<<CRUD>>入金登録

サービス開始登録

入金

請求データ作成

<<CRUD>>売上登録

CRUD

CR

R

一定時間経過

メール請求書

自動継続

X月X日YYサービスを開始

消込

消込残

消込

終端消込

<<消込>>請求残

契約情報

消込

<<消込>>請求消込

毎月繰り返される

Page 24: 業務システムのための型システム

実装

Page 25: 業務システムのための型システム

基本構造

シナリオ

<<object>>業務機能

<<trait>>業務操作

<<trait>>T消込操作

消込対象():Bool消込済():Seq[Entity]消込残():Seq[Entity]クエリー(条件)

後続機能()

<<trait>>コンクリート操作

implicit

<<object>>業務機能

<<trait>>業務操作

<<trait>>コンクリート操作

implicit

<<object>>業務機能

<<trait>>業務操作

<<trait>>コンクリート操作

implicit

<<trait>>コンクリート操作

<<trait>>コンクリート操作

<<trait>>コンクリート操作

後続機能()

後続機能()

後払い商品販売

前払いサービス提供

型クラス

<<消込残>>見積書見積

受注<<消込残>>

注文書

見積もり

受注

Importにより切り替え

このレイヤーでは処理の前後関係を持たない このレイヤーでは処理の前後関係を持つ

<<消込残>>ピッキング

リスト

出荷指示

出荷指示

Page 26: 業務システムのための型システム

基本構造

シナリオ

<<trait>>T受注操作

<<trait>>T消込操作

消込対象():Seq[Tentity]消込済():Seq[T消込Wrapper]消込残():Seq[T消込Wrapper]クエリー(条件)後続機能()

<<trait>>受注

implicit

<<object>>出荷指示機能

<<trait>>T出荷指示操作 <<trait>>

出荷指示

implicit

object 後払い商品販売シナリオ extends Application {import business1.後払い商品販売._

val 佐藤商事受注 = CE受注(2,Date.valueOf("2012-02-21"),2,3)受注機能.受注登録(佐藤商事受注)受注機能.受注残一覧.foreach( e => println(e.body))val 田中商事出荷指示 = CE出荷指示(1,Date.valueOf("2012-01-22"),1)出荷指示機能.出荷指示登録(田中商事出荷指示)

<<trait>>コンクリート操作

<<trait>>コンクリート操作

後続機能()

後払い商品販売

前払いサービス提供

<<object>>受注機能

受注登録受注残一覧

persistence消込対象():Seq[TEntity]消込済():Seq[T消込Wrapper]消込残():Seq[T消込Wrapper]後続機能():出荷指示

Persistence消込対象():Seq[TEntity]消込済():Seq[T消込Wrapper]消込残():Seq[T消込Wrapper]後続機能():出荷指示

object 受注機能 {def 受注登録[TENTITY <: TEntity](ent:TENTITY)(implicit p受注消込:T受注消込[TENTITY]): T受注消込[TENTITY]={

p受注消込.追加(ent)p受注消込

}def 受注残一覧[TENTITY <: TEntity](implicit p受注消込:T受注消込[TENTITY]) = p受注消込.消込残()

<<trait>>TCRUD

追加参照変更削除persistence

シナリオ

trait T受注消込[TENTITY <: TEntity] extends T消込操作 with TCRUD[TENTITY] {

Page 27: 業務システムのための型システム

基本構造

<<trait>>T受注操作

<<trait>>T消込操作

消込対象():Seq[Tentity]消込済():Seq[T消込Wrapper]消込残():Seq[T消込Wrapper]クエリー(条件)後続機能()

<<trait>>受注implicit

後続機能()

後払い商品販売

<<object>>受注機能

受注登録受注残一覧

persistence消込対象():Seq[TEntity]消込済():Seq[T消込Wrapper]消込残():Seq[T消込Wrapper]後続機能():出荷指示

<<trait>>TCRUD

追加参照変更削除persistence

シナリオ

object 後払い商品販売 {implicit object 受注 extends T受注消込[CE受注] {

type TID = Inttype TMONEY = Inttype TENTITY = CE受注val persistence = new Persistence[CE受注]

/** 対応する受注の集合を返す */def 消込済() :Seq[T消込Wrapper] = {

for(ent1 <- 消込対象(); ent2 <- 後続機能().消込対象(); if ent1._id == ent2._受注id) yield ent1.empty消込Wrapper}/** 対応するものがない受注の集合を返す */def 消込残() : Seq[T消込Wrapper] = {

消込対象().filterNot( jc1 => 後続機能().消込対象().exists( e => e._受注id == jc1._id)).map(e => e.empty消込Wrapper)}def 消込対象() : Seq[CE受注] = persistence.query( e => true )//全件返すdef 後続機能() = 出荷指示

}

Page 28: 業務システムのための型システム

実装:Meta Layer&Business Layer

<<trait>>T消込操作

消込対象():Seq[TEntity]消込済():Seq[TEntity]消込残():Seq[TEntity]

クエリー(条件)

後続機能()

見積機能

見積登録見積一覧

受注機能

受注登録受注一覧

出荷機能

出荷登録出荷一覧

M商品

//

M顧客

//

M組織

//

消込TEntity

id

<<trait>>ParentEntity

明細合計

<<trait>>T消込終端操作

対応消込可能消込残消込

入金機能

入金登録入金一覧

M管理単位

//

残高

リソース

在庫機能

入荷出荷在庫

債権残高機能

請求書発行債権残高

Persistence

createreadupdatedeletequery

<<trait>>残高操作

追加参照変更削除

加算一覧()減算一覧前残高現残高

加算機能()減算機能()

Entity

Business Layer

Meta Layer

出荷指示機能

出荷指示出荷予定一覧

売上機能

売上登録売上一覧

T消込Entity

is消込対応()消込済()消込残()消込状態()//消込()

class 消込状態object 未消込 extends 消込状態object 消込中 extends 消込状態object 消込済 extends 消込状態

CRUD[T]

追加参照変更削除persistence

永続化

Page 29: 業務システムのための型システム

実装クラス

object受注機能

受注登録受注残一覧

後払い商品販売

<<trait>>T消込操作

消込対象():Bool消込済():Seq[Entity]消込残():Seq[Entity]クエリー(条件)

後続機能()implicit受注

消込対象消込済消込残persistence

前払いサービス提供

受注

消込対象消込済消込残

後払い商品販売シナリオ

import 後払い商品販売

前払いサービス提供シナリオ

import前払いサービス提供

implicit出荷指示

出荷指示出荷予定一覧

trait受注消込

CE受注

消込済(ent)消込残(ent)copy

TEntity

id:TID

T消込Wraper

id

TE受注

_id:TID_受日:Date _顧客CD: TCID_管理組織CD:TOCD

消込済(ent)消込残(ent)copy

TE受注明細

_商品:TID_数量:Date _金額: TCID

object出荷指示機能

出荷指示登録出荷指示残一覧

traitT出荷指示消込

TE出荷指示

_id:TID_受日:Date _出荷指示日:Date_受注id: TID

消込済(ent)消込残(ent)copy

<<trait>>TCRUD

追加参照変更削除persistence

TParentEntity

合計

明細

T消込Entity

消込済():T消込Entity消込残(): T消込Entity消込状態empty消込Wrapper

メタレイヤー ビジネスレイヤー

コンクリートレイヤー

Page 30: 業務システムのための型システム

END