ドメイン駆動設計の考え方をFXに適用する
■ドメイン(Domain)とコンテキスト(Context)
ちまたにシステム開発者のためにドメイン駆動設計(Domain Driven Design、略してDDD)という本があるということを最近友人に教えられ、勧められるがままに読んでいるのだが、これがとてもためになる。こういう概念をベースにFXのシステムを作るととてもわかりやすい。このアプローチの最大の魅力は、これによりビジネス側とシステム側の会話がスムーズになり、理解が深まり、よりきれいなシステムが実現し、またそれにより後続のリファクタリングがよりスムーズに実行できるということであるように思う。
しかしながらこれを実現するには、ビジネス側のルール、習慣、使われている金融の知識が不可欠になる。そしてそれぞれに対してシステム側の目線が絡み合ってくる。残念ながらそれら両側の考え方を一つの頭脳で理解できる人は少ない。かといって何も両方を理解する人がいなければならないというわけではない。ビジネス側を代弁する人とシステム側を代弁する人がうまくコミュニケーションをとって作り上げればいいだけのことで、そのためにこのDDDの発想は有益である(言うは易く行うは難しは言わずもがな)。そもそもそういう目的で提唱されている開発メソッドであるのだが、それを自分は最近知ったことが残念でもある(むろん2000年ごろにはこういう本は売っていなかった)。
では、基本私は素人であるという前提をお許しいただきながら、せっかくなのでFXに当てはめるとどういうデザインになるかについて私なりの理解をベースにご紹介したいと思う。
まず、最初に大事だと考えるのは、ドメインという概念とコンテキストという概念である。まず、ドメインには何があるかを考える。
■ドメインDomain
ここでいうドメイン(辞書を引けば「領域」)はFXのビジネスを遂行するうえでの業務的役割と考えてもらっていい。例えば組織図的にどういう部署があるかを考える。一般的と思えるモデルを以下のように定義してみる。
(1)口座開設部門customerOnBoard、(2)顧客管理部門customerDesk、(3)ディーリング部門dealingDesk、(4)リスク管理部門 middleOffice、(5)経理部門 accounting、(6)システム部門 からなり、以下の表ではシステム部門を(7)情報、(8)ログインセッションと(9)マスター管理の3つに分けている。
ドメインはビジネス上のドメイン(組織部門)とまったく同じである必要はない。そこはコンテキストとの絡みや、システムデザイン上の都合も影響する。そうした制約を柔軟に吸収して、仮想の組織ドメインを構築する。実際の組織に情報部などなくても、上記の表では、システム部=情報となっている。それ以外のシステム部2,3,4を束ねて一つのシステム部としてのドメインとして扱いながら帳票、情報、セッション、マスターのそれぞれをサブドメインとして考えてもいい。
次にコンテキストを考える。コンテキストとは、上記の各ドメインごと、あるいはそれら複数をまたいで実行される“仕事”といっていいかもしれない。一つ一つの仕事、サービス、ジョブ、振る舞い、言い方はいろいろあるかと思うが、具体例を挙げてみていこう。
■コンテキストcontext
コンテキストとはふたたび辞書を引けば文脈と出ているだろう。まさにその通りの意味で使っている。システム設計における文脈は、「仕事」とも言い換えることができる。仕事を細かく見ていけば、それ自身で完結するもの。そこで生まれた何かを他の仕事へ引き継ぐもの。なにがしかのインプットがあってアウトプットがあるもの。アウトプットはなく、単にある「状態」を維持し続けるもの。入ってきたものを右か左かを判断して振り分けるものなどいろいろなパターンがある。それらのパターンを意識しながら、出来る限り抽象化していくことを考える。抽象化の道具としてオブジェクト指向とよく言われるが、どういうオブジェクトを生み出してそこに据え置くかという視点を意識して考えていく。
■情報コンテキスト
例として情報コンテキストを見る。このコンテキストはどういう流れで、何をもらい、何にどう変えて、最終的に何を作るのかという目線で一つ一つ順番にその作業内容を書き出す。このコンテキストが主体的に関係するドメインはシステム部1(情報部)しかない。作業は一つのドメインで完結するが、このコンテキストが生み出すアウトプット(成果物)は他部署(ドメイン)から見ることができるか、他部署の別のコンテキストに受け渡される。
- インターバンクの複数のCPからレート(cpRate)をもらう。もらうときに必要な情報は、cpCode, curPair, settleDate, price(bid,ask), amount(bid,ask),bandNum
- もらっているレートに対してバッドティック(バグレート)を判定して排除する
- バッドティックと判断されたレートを排除した“クリーンレート”から最大ビッドと最小アスクを拾い出す。あるいは、違うロジックでソースレート(sourceRate)を作成する
。 - 作成されたソースレートに対して、念のためバッドティックではないかどうかの判定をする
。 - 上記判定を乗り越えたクリーンソースレートをベースに顧客配信レートを作成する
- 顧客配信レートは、ソースレートにたいしていくつかのロジックを持っている[retailPricingStrategy]。
- 固定レート生成ロジックと変動レート生成ロジックなどがある。
これを表にするとこうなる。
このようなロジックはシステムエンジニアでなくてもできるし、むしろ彼らよりもビジネスサイドにいる人の方が良くわかっている。わかっている人がいないと開発がそもそもできない。ただし、その時の細かい必要条件にはどういう種類のものがあるかのヒントはシステム側からサポートしてもらう必要があることが多いだろう。上の例でいればビジネスサイドの人は、「CPからレートをもらって・・・」というだけでそれ以上細かいことは言わない場合、システムサイドの人は「具体的に何をもらうのか。何を持って一意とするのか」というような質問を投げつけてくることが想像できる。
上記()で英語で書いているものは、大まかに言ってvalue Objectである。Value Objectとは(私のようなものが説明するのもおこがましいが)一つのコンテキストの中では一意であるもの。“もの”であり、物体であると思ってもらっていい。<>で書いているのは操作である。まさにお仕事につけた名前である。メソッド(method)かもしれないし、ファクトリー(factory)かもしれない。[ ]は仕事をするときに使われるルール(strategy)である。おおざっぱにしか書いていないので、上の一連のコンテキストの中にはもっとほかのvalue Objectやmethodやstrategyが存在するが、ここでは割愛する。
さらに大事な概念として、プログラムを書くときにはこうした用語を利用しながらも、それぞれのネーミングをできるだけ実際の業務で使う言葉を利用して作成することである。出来る限りソースコードを見たときに英語の文章のようになるように作成したほうがわかりやすい。こういうのユビキタス言語というそうである。
システム開発というのは長期にわたることが多い。その間、自分の作ったプログラムでも数か月見ないと、なんだったっけということになりがちだし、それを書いた人がやめてしまって違う人が引き継ぐということはよくある。そのときソースコードをみて直観的に理解できるコーディングが望ましいということである。
このコンテキストは(7)レート配信部門informationドメインに属している。それ以外のドメインにはかかわっていない。CPからレートをもらって顧客レートを作るまでが説明されている。作ったレートをどう配信するかについては触れていないが、それはまた別のコンテキストに任せる。もしくはそれはインフラレイヤーの次元の話で完結する。なるべく一つのコンテキストはシンプルに短くしたい。
コーディングをするときは英語になるので上記の一連のステップを英語にしてみる。そしてそこから“いい感じ”の英語のメソッド名やオブジェクト名を作ってく。
例)
Get cpRate with bid,ask, bidSize , askSize and bandNum from each cp by curPair and put them all into LiquidityPool where the all rates are listed and updated in real time.
Eliminate bad ticks by cpBadTickFilter and keep CleanCpRates
Aggregate cpRates in LiquidityPool by curPair
Create sourceRate that has sourceBid and SourceAsk without size every “n” msec as defined by sourceRateSlottle
Create RetailPrice from SourceRate by one of retailPricing strategies
ここでは、CPレートをrateと呼び、顧客配信レートをpriceと呼び分けている。どっちでもいいが、そうした区別も配慮のうちである。
Liquidity Poolはもらっているレートを全部並べて比較している場所(Pool)である。どのCPがどの通貨ペアで“今”どういうビッド、アスクをどれだけのアマウント(size)で送りつけてきているかがわかる。
Eliminateは、getRidOfでもいいし、ほかに似たような言葉では、Abandonやdiscardもある。どれを使うかは英語力とセンスの問題だろう。ある程度英語ネイティブ目線で違和感のない用語、単語を使えればなおいい。
sourceRateは一時点における通貨ペアごとの一意のレートでありそこには、bid, askが含まれているというかセットで持っているobjectである。これをもとに対顧レートが生成される。またこれを作る頻度については、sourceRateSottleという名のobjectを作る。どれくらいの頻度で生成するかというときの用語に私が好んで使うのはthrottleである。ほかにはIntervalを使う人もいるだろう。
そこに200 msecという値が入っているとしたら200 msecごとに作成することになる。ソースレートとしては一般には、LiquidityPoolからその時点でのベストなbid, askを引っ張ってくるのだろうが、場合によっては(通貨ペアの特性によっては)MidやAverageを取ってこいということになるかもしれない。よってここでは複数のstrategyが存在すると考える。どのstrategyを使うかは初期設定で定義し、どれを使うかをFactoryでセットする。どれを使うかを考える時にそれをCPごとで一意とするか、CPごとかつcurPairごとで一意とするかもセンスの問題である。細かい設定を最初から可能にしてデザインするか、とりあえずは大まかにしておくかは仕様を決める人の任意である。あとになってやっぱり細かくしたいという要望が来てもこのような設計図がきれいにできていれば対応が楽になる。
sourceRateに関しては、ここまでで以下の式が思い浮かぶ。
createSourceRate(curPair)= {strategy(curPair), liquidityPool,sourceRatethrottle(curPair)}
一つの通貨ペアのソースレートを作るためには、どのストラテジーで、LiquidityPoolから、どの頻度で取ってきて作成するかという式ができる。で、この式を見ながらそれで十分かどうかをビジネスサイドはよくよく検討することになる。決まればこれらの用語をそのままコーディングで使う。Strategy(curPair), sourceRatethrottle(curPair)と書くことで、それらはcurPairごとに設定されている値もしくは“ルール”であることがわかる。
今度は、上の表を見ながら再度説明をする。これはインターバンクからレートをもらってから対顧の配信レートを生成するまでの流れを左から右へと示している。
原則一つのコンテキストは他のコンテキストと深くかかわらないほうがよい。一つのタスクはそれのみで完結するようにする。コンテキストはワンセットのインプットによって一意の結果が出てくるところまでで切れるものなら切りたい。一見複数なルールや流れに見えるものは、オジェクトをうまく介在させることでよりシンプルなモデルに分割し仕上げていく。こういう考え方を抽象化(かつ単純化)というが、この抽象化ができのいいシステムを作るうえで一番重要な気がする。抽象化とはより使い勝手の良いモデリングという意味でもあり、後で他人が見てもすぐわかるという効果を目的としている。きれいに抽象化できるということはその人はそのビジネスモデルをよく理解し、頭の中で整理されているという証拠でもある。そういう人とタッグを組んだエンジニアはコードの開発がより洗練されうるし、そもそも作業が楽だろう。最悪なのはビジネス側のロジックをうまく合理的に抽象化できる人がひとりもいないプロジェクトである。そういうことは冒頭のDDDの本の中に例としてイヤというほど出てくるし、その多くは実体験上思い当たる。
ビジネス側で個々の業務に精通している人はたくさんいるが、それらを俯瞰して抽象的に説明できる人が少ない。これはかつてここでも触れたテーマであるが、上の例でドメインにあたる各部署が互いに連携をとって自分の仕事が他部署のどこに影響を与えているかということについての知見が深い人を育てないと、こうしたプロジェクトをうまく運んでいけない。そういう人は、各部署を渡り歩いていわゆるジェネラリストとして育てられた人が適任だろうが、最近はそういう人の育て方をしないのではないだろうか。もしそういうことをする余裕があるならそのジェネラリストに対しては、おまけでDDDの本も勉強してもらうと理想的だろう。何もシステム開発をするためだけにDDDが有効なわけではない。そもそも組織の在り方、その合理性、そしてビジネス・業務の流れを合理的に構築してゆくうえでとても有益なアプローチである。実際の人的作業がきれいにデザインされて(つまり無駄なく、重複なく、複雑さができる限り排除され、作業の要素が可視化(まさにオブジェクト化)されて)いれば、その業務は安全に稼働し、業務自体に変更がある場合でもミスや矛盾が発生しにくく、迅速な変更が可能になる。業務フローとか業務手順書(これは検査の時にあるかないかを問われることああるので必須の定義し備えおくべきドキュメントであるが)はユースケースでまとめうる。そしてそれをもとにクラス図を書くことができる。
以上が私が最近読んできたDDDについての考え方をベースにそれをFXに適応した場合のいろはの“い”である。折に触れ今後いろはの“ろ”、“は”を順次展開していければなと思うが、このコラムがより一層、一般の人にはわかりずらい、専門的なものになってしまう・・・・・(苦)。
最後にドメインとコンテキストの関係を簡単に以下の図で示しておく。
▼尾関高のFXダイアリーをご覧のみなさまへ
このFXダイアリーで取り上げて欲しい話題、また尾関さんに書いてもらいたいテーマなどあれば業界内外問いませんので、「件名:FXダイアリーへの要望」として info@forexpress.com までご連絡ください(コラムへの感想でも勿論結構です)。