Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

1,850 views

Published on

クラウド温泉3.0で発表した資料
型クラスを業務系のシステムで使うことを

  • Be the first to comment

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

  1. 1. 業務システムのための型システム ビジネスモデルを表現する 振る舞いと構造の変更に型クラスを使う 2010/0818
  2. 2. わたしは…  ㈱バリューソース  代表取締役  神崎 善司  zkanzaki@vsa.co.jp  はてな:good_way  twitter:@zenzengood  普段は  要件定義関連のコンサルテーション  セミナー開催(要件定義、オブジェクト指向、モデリング)  「要件のツボ」の開発  関数型との関係  7年くらい前から関数型に興味を持ち  CleanやF#をつまみ食いしながらScalaを発見!  以来サンデープログラマーとしてScalaを利用  「要件のツボ」のサーバーサイドで利用  札幌の技術者との交流の中で関数型がだんだんわかりかけてきた…2
  3. 3. なにがしたいの? ビジネスモデルを構造として定義する ニーズ  コンサルの初期段階でお客さんのビジネスモデルを早く把握 する必要がある  ビジネスモデルの基本構造を記述  シナリオベースで動かして確認したい  コードにすることでメタ構造を洗い出す
  4. 4. ビジネスモデル 販売管理BtoB 後払い商品販売 BtoC 前払いサービス提供 特定顧客に対して商品の販売 不特定多数の顧客に対して継続的なサービス提供 注文 注文得意先 会社 顧客 会社 請求 与信 会員 登録 入金 商品 在庫引当 人の サービス 検収 デリバリ 債権管理 ワークフロー管理 請求書 or ライセンス サービス 入金 サービス提供
  5. 5. ビジネスモデルによるデータ構造の違いBtoB 後払い商品販売 BtoC 前払いサービス提供 特定顧客に対して商品の販売 不特定多数の顧客に対して継続的なサービス提供 注文 得意先 会社 顧 注文 会社 与信 請求 客 入金 会 商品 員 在庫引当 登 録 人の 検収 デリバリ 債権管理 サービス ワークフ ロー管理 請求書 or ライセンス サービ サービス ス提供 入金 前払: 請求 入金 受注 受注明細 受注・請求が同時 受注 受注明細 入金確認後出荷 ・分割納品 ・出荷まとめ 後払: 出荷 出荷明細 ・請求まとめ 受注 受注明細 ・一部入金 検収確認後請求・入金 売上 請求 入金 検収 請求 入金 債権残高 相殺 売上 債権残高 債務残高 支払い
  6. 6. 販売管理 典型的なデータ構造オブジェクトモデル クラスモデル 受注 受注明細 工程 受注 受注明細 受注明細 受注明細 ・分割納品明細単位で処理しな 出荷指示 出荷 出荷明細 ・出荷まとめい場合は受注・出荷 検収で結びつく 売上 出荷指示 出荷 出荷明細 出荷 出荷明細 請求 出荷明細 分納がある場合は 債権残高 入金 受注1に対して出 相殺 ・請求まとめ 荷は多になる 受注 受注明細 ・一部入金 支払い 債務残高複数の受注をまとめて出荷する場合は出荷1 売上 売上 請求 入金で受注多になる 入金 分割入金 債権残高 請求 入金 請求 前払いの場合 複数の請求分を は債権残高 まとめて入金 がない (都度請求)
  7. 7. 例えば 販売管理のバリエーション顧客との関係 単価の設定 見積・受注 → 見積もり・受注先 例)単価の決まり方 出荷 → 出荷先 商品に直接単価が紐尽く 請求・入金 → 請求先 得意先によって商品の単価が異なる例)Webベースのサービス 商品 A単価 デリバリがないので出荷先が必要ない 請求先はメールだけで請求書送付がない 商品 得意先例)前払い 後払い B単価 後払いには与信が必要 前払いは債権残高がない ~ ビジネスシステムは一つ一つは簡単だが、バリエー ションと組み合わせが多岐にわたる
  8. 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)) 単純なシナリオでビジネスモデルの確認を行う
  9. 9. 型クラスとはビジネスモデルの多様性を型クラスを使って表現したい
  10. 10. Ord[T] 型クラス type class Ord[MyModel] Ord[XXModel]trait Ord[T] { def compare (x: T, y: T): Boolean}case class MyModel(val data: Int) MyModelのcompareの実装implicit object ordMyModel extends Ord[MyModel] { def compare (m1: MyModel, m2: MyModel) = m1.data <= m2.data} 構造Tを型パラメータにもつOrddef greedy[T](m1: T,m2: T)(implicit ordM: Ord[T]) = のサブクラス(Ord[MyModel]) 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
  11. 11. 振る舞いを汎化し構造を型パラメータで変える 振る舞いを汎化で拡張 構造 構造は型パラメータによ り任意のクラスを使える 振舞クラス[型] Xxxxx[T <: 構造] 構造 型パラメータを汎化 構造 振舞の拡張[型拡張] 構造 振る舞いの拡張にあわ せて型の拡張も可能 Ord[T] Ord[MyModel]implicit object ordMyModel extends Ord[MyModel] { def compare (m1: MyModel, m2: MyModel) = m1.data <= m2.data}
  12. 12. 例:グラフを処理するAからBまでの2地点の経路を求める 構造と振る舞いを変え A られるようにするにはど う考えればいいのか? B アルゴリズム 構造 総当たり戦 Node ~~ Node Link
  13. 13. グラフ構造を抽象化する trait Neighbors[Edge] { def neighbors(e:Edge):List[Edge] }<Neighbors[Edge]> <trait> <object> <routes>グラフ構造をお隣さんと Neighbors[Edge] Route neighborsで得られたEdgeを使って経いう概念で抽象化する neighbors routes 路を導き出すロジックをもつ 実際の構造にあったお隣さんを返す 構造にあったNeighborsを与えることで任意の構 造に対応するNeighborsを処理できる def routes[Edge](from:Edge,to:Edge) (implicit nghbrs:Neighbors[Edge]) :List[List[Edge]] ={ neighborsで得られたEdgeを使って経路を導き出す }
  14. 14. 経路処理を実際の構造に注入する trait Neighbors[Edge] { <trait> <object> def neighbors(e:Edge):List[Edge] Neighbors Route } neighbors routes def routes[Edge](from:Edge,to:Edge)(implicit nghbrs:Neighbors[Edge]):List[List[Edge]] ={外部からの入り口 def getRoutes(from:Base,to:Base):List[List[Base]] = from.routes(to) Service implicit object BaseNeighbors extends Neighbors[Base]{ getRoutes def neighbors(base:Base):List[Base] = { base.links.map(_.opposite(base)).toList } } 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) }今回Edgeに対応するデータ構造 Base edge1 Pathway Baseにroutes edge2 routes links を後付けする
  15. 15. ビジネスモデルを表現するビジネスモデルのバリエーションを型クラスを使って表現する ビジネスモデルの違いを振る舞いと構造の違いととらえる その違いを型クラスで表現する
  16. 16. ビジネスモデルの要素を組み替えるBtoC 前払いサービス提供 BtoB 後払い商品販売 不特定多数の顧客に対して継続的なサービス提供 特定顧客に対して商品の販売 注文 注文 顧客 会社 会社 請求 得意先 与信 会員 登録 入金 商品 人の 在庫引当 サービス 検収 デリバリ ワークフロー管理 債権管理 or 請求書 ライセンス サービス サービス提供 入金 <<消込残>> <<消込残>> <<消込残>> <<消込残>> <<消込残>> 出荷 見積 見積書 受注 注文書 ピッキング 納品書 出荷 請求書 入金 指示 リスト 見積もり 受注 出荷指示 出荷 請求書 入金
  17. 17. ビジネスモデルによってフローが変わる <<消込残>> <<消込残>> <<消込残>> <<消込残>> <<消込残>> 出荷 見積 見積書 受注 注文書 ピッキング 納品書 出荷 請求書 入金 指示 リスト 見積もり 受注 出荷指示 出荷 請求書 入金後払い商品販売 前払いサービス提供
  18. 18. importでコンテキスト変えるImport A or B ⇒ コンテキストを変える <<消込残>> <<消込残>> <<消込残>> <<消込残>> <<消込残>> 出荷見積 見積書 受注 注文書 ピッキング 納品書 出荷 請求書 入金 指示 リスト 見積もり 受注 出荷指示 出荷 請求書 入金 Business Layerの知 BtoB 後払い商品販売 識でプログラミング 特定顧客に対して商品の販売 A B 実装 implicit ビジネスモデルの 見積 受注 出荷指示 出荷 請求書 入金 違いをコンテキス トを変えて実現 Business Layer 管理単位 BtoC 前払いサービス提供 不特定多数の顧客に対して継続的な 消込 残高 少数の概念でBusiness サービス提供 Layerを実現 リソース Meta Layer
  19. 19. 実現 Import A or B ⇒ コンテキストを変える APP ドメインを利用するア プリケーションはビジ ネスレベルを利用する 一般的な振る舞い と構造を定義する ビジネスレイヤー <<消込残>> <<消込残>> <<消込残>> <<消込残>> <<消込残>> 出荷見積 見積書 受注 注文書 ピッキング 納品書 出荷 請求書 入金 指示 リスト 見積もり 受注 出荷指示 出荷 請求書 入金 メタレイヤー メタレイヤーで処理 消し込み 残高 の前後関係をつなぐ ビジネスモデルとしての具体 コンクリートレイヤー: コンクリートレイヤー: 的な構造と振る舞いを定義 後払い商品販売 前払サービス提供 具体的な永続化の機 構もここで指定する
  20. 20. Meta Levelビジネスの基本概念 ・消込と残高という2つの概念でビジネスを捉える ・消し込み 受注→在庫引き当て 消込 商品を受注したら出荷 在庫引き当て→出荷 消込 して受注を消し込む ・残高 出荷→在庫減 残高 入荷→在庫増 残高 後続機能()個々のEntityで消し込み済みのもの <<trait>> T消込操作 消込対象():Seq[Tentity] 消込済():Seq[T消込Wrapper] 消 消込 消込残():Seq[T消込Wrapper] 消込 込 消込 出 対象 クエリー(条件) 対象 受 対象 後続機能() 済 荷 注 消込残 消込残
  21. 21. ビジネスレベル・一般的な業務処理をビジネスレイヤーで記述・各処理の前後関係は記述しない・前後関係はコンクリートレイヤーで記述する <<消込残>> <<消込残>> <<消込残>> <<消込残>> <<消込残>> 出荷見積 見積書 受注 注文書 ピッキング 納品書 出荷 請求書 入金 指示 リスト 見積もり 受注 出荷指示 出荷 請求書 入金 object TE受注 受注機能 _id:TID _受日:Date 受注登録 _顧客CD: TCID 受注残一覧 _管理組織CD:TOCD 消込済(ent) trait 消込残(ent) 受注消込 copy TE受注明細 _商品:TID _数量:Date _金額: TCID
  22. 22. コンクリートレベル販売管理 後払い商品販売 型クラス モジュール 得意先 商品 組織 得意先 商品 組織 見積もり登録 注文を登録 出荷を指示する 出荷登録 <<消込残>> <<消込残>> <<消込残>> 出荷 <<消込残>> 見積 受注 ピッキング 出荷 請求書 入金 見積書 指示 納品書 リスト 出荷 消込 <<CRUD>> <<消込残>> 受注 出荷指示登録 出荷残 請求・入金見積もり 終端消込 終端消込消込 消込 CRUD R 残高 <<CRUD>> <<CRUD>> <<CRUD>> <<CRUD>> 受注登録 出荷予定 予定明細 見積登録 売上登録 <<加算>> <<減算>> 入金登録 <<消込残>> <<消込残>> 債権減 債権減CRUD 見積残 CRUD 受注残 <<消込>> R R 出荷指示消込済 CRUD 消込 CRUD 消込見積もり 見積明細 受注 受注明細 U U R <<消込>> 消込 売上 債権残高 入金 <<消込>> <<CRUD>> 見積消込済 出荷登録 CR 受注消込済 CRUD <<請求残>> 請求データ 出荷 出荷明細 作成 <<消込>> 出荷 出荷消込済 在庫引き当て 在庫 入荷
  23. 23. コンクリートレベル 販売管理 前払いサービス提供得意先 商品 組織 得意先 商品 組織 毎月繰り返される 受注 自動継続 入金 一定時間経過 受注 請求・入金 終端消込 サービス 消込 消込 <<CRUD>> 消込 <<CRUD>> 売上登録 <<消込>> <<CRUD>> サービス開始登録 受注登録 <<消込>> CRUD 請求消込 入金登録 受注消込済 CRUD CRUD R 売上 CRUD C 請求 サービス R 入金 受注 受注明細 R 請求デー 契約情報 消込残 タ作成 R <<消込>> <<消込残>> 請求残 受注残 X月X日YY メール 請求書 サービスを 開始
  24. 24. 実装
  25. 25. <<trait>> T消込操作 消込対象():Bool基本構造 消込済():Seq[Entity] 消込残():Seq[Entity] クエリー(条件) Importにより切り替え 後続機能() 前払いサービス提供 シナリオ 型クラス <<trait>> 後払い商品販売 コンクリート操作 <<trait>> <<trait>> <<消込残>> 業務操作 コンクリート操作見積 見積書 <<object>> 業務機能 見積もり implicit 後続機能() <<trait>> コンクリート操作 <<trait>> <<trait>> <<消込残>> 業務操作 コンクリート操作受注 注文書 <<object>> 業務機能 受注 implicit <<trait>> 後続機能() コンクリート操作 <<消込残>> <<trait>> <<trait>>出荷 ピッキング 業務操作 コンクリート操作指示 リスト <<object>> 業務機能 出荷指示 implicit このレイヤーでは処理の前後関係を持たない このレイヤーでは処理の前後関係を持つ
  26. 26. 基本構造 <<trait>> <<trait>> trait T受注消込[TENTITY <: TEntity] extends T消込操作 with TCRUD[TENTITY] { T消込操作 TCRUD 消込対象():Seq[Tentity] 追加 消込済():Seq[T消込Wrapper] 参照 消込残():Seq[T消込Wrapper] 変更 前払いサービス提供 シナリオ クエリー(条件) 後続機能() 削除 persistence 後払い商品販売 <<trait>>object 後払い商品販売シナリオ extends Application { コンクリート操作 import business1.後払い商品販売._ val 佐藤商事受注 = CE受注(2,Date.valueOf("2012-02-21"),2,3) 受注機能.受注登録(佐藤商事受注) <<trait>> 受注機能.受注残一覧.foreach( e => println(e.body)) T受注操作 <<trait>> val 田中商事出荷指示 = CE出荷指示(1,Date.valueOf("2012-01-22"),1) 受注 出荷指示機能.出荷指示登録(田中商事出荷指示) persistence <<object>> 消込対象():Seq[TEntity] シナリオ 受注機能 消込済():Seq[T消込Wrapper] implicit 消込残():Seq[T消込Wrapper] 受注登録 受注残一覧 後続機能():出荷指示 <<trait>> コンクリート操作 後続機能() <<trait>> T出荷指示操作 <<trait>> <<object>> 出荷指示 出荷指示機能 Persistence 消込対象():Seq[TEntity] implicit 消込済():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受注消込.消込残()
  27. 27. 基本構造 <<trait>> <<trait>> T消込操作 TCRUD 消込対象():Seq[Tentity] 追加 消込済():Seq[T消込Wrapper] 参照 消込残():Seq[T消込Wrapper] 変更シナリオ クエリー(条件) 後続機能() 削除 persistence 後払い商品販売 <<trait>> <<object>> T受注操作 <<trait>> 受注機能 implicit 受注 受注登録 persistence 受注残一覧 消込対象():Seq[TEntity] 消込済():Seq[T消込Wrapper] 消込残():Seq[T消込Wrapper] 後続機能() 後続機能():出荷指示 object 後払い商品販売 { implicit object 受注 extends T受注消込[CE受注] { type TID = Int type TMONEY = Int type 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 後続機能() = 出荷指示 }
  28. 28. 実装:Meta Layer&Business LayerMeta Layer class 消込状態 object 未消込 extends 消込状態 object 消込中 extends 消込状態 object 消込済 extends 消込状態 Entity リソース TEntity M商品 M顧客 消込 残高 <<trait>> id // // <<trait>> 残高操作 T消込操作 追加 <<trait>> 参照 <<trait>> T消込Entity 消込対象():Seq[TEntity] T消込終端操作 変更 ParentEntity 消込済():Seq[TEntity] 削除 is消込対応() M管理単位 M組織 消込残():Seq[TEntity] 対応 明細 消込済() 消込可能 合計 加算一覧() 消込残() // // クエリー(条件) 消込残 減算一覧 消込状態() 消込 前残高 //消込() 後続機能() 現残高 加算機能() 減算機能() 永続化 CRUD[T] Persistence 追加 create 参照 read 変更 update 削除 delete persistence queryBusiness Layer 見積機能 受注機能 出荷指示機能 出荷機能 売上機能 在庫機能 債権残高機能 入金機能 見積登録 受注登録 出荷指示 出荷登録 売上登録 入荷 請求書発行 入金登録 見積一覧 受注一覧 出荷予定一覧 出荷一覧 売上一覧 出荷 債権残高 入金一覧 在庫
  29. 29. 実装クラス メタレイヤー ビジネス コンクリート <<trait>> TCRUD object 受注機能 レイヤー レイヤー 後払い商品販売シナリオ 追加 参照 受注登録 import 後払い商品販売 変更 受注残一覧 削除 persistence trait 前払いサービス提供シナリオ 受注消込 <<trait>> T消込操作 import前払いサービス提供 消込対象():Bool 消込済():Seq[Entity] 消込残():Seq[Entity] クエリー(条件) 後払い商品販売 TE受注 後続機能() _id:TID 前払いサービス提供 implicit _受日:Date object 受注 _顧客CD: TCID 出荷指示機能 受注TParentEntity _管理組織CD:TOCD明細 消込対象 出荷指示登録 消込対象 消込済合計 消込済(ent) 出荷指示残一覧 消込済 消込残 消込残(ent) 消込残 persistence copy T消込Entity trait T出荷指示消込 CE受注 消込済():T消込Entity 消込残(): T消込Entity 消込済(ent) 消込状態 消込残(ent) empty消込Wrapper TE受注明細 copy _商品:TID TE出荷指示 _数量:Date _id:TID _金額: TCID implicit TEntity _受日:Date 出荷指示 _出荷指示日:Date id:TID _受注id: TID 出荷指示 出荷予定一覧 消込済(ent) T消込Wraper 消込残(ent) copy id
  30. 30. END

×