始めよう! ドメイン駆動設計&マイクロサービス開発 ~c# と azure service...

Post on 12-Jan-2017

8.331 Views

Category:

Software

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

2016/05/24株式会社ネクストスケープ

エバンジェリスト 上坂貴志

de:code 2016SNR-003

www.nextscape.net 1

~C# と Azure Service Fabric で最高の DDD 開発を~

始めよう! ドメイン駆動設計&マイクロサービス開発

アジェンダ

なぜ今Microservicesなのか

MicroservicesとDDD

Domain-Driven Design

DDD導入のハードル

Azure Service Fabric

最後に

www.nextscape.net 2

自己紹介• 会社

株式会社ネクストスケープ

• 名前上坂貴志(うえさかたかし)Twitter:@takashiuesaka

• 年齢44歳

• 好き・興味ありAzure(Microsoft MVP for Microsoft Azure)、Scrum(認定スクラムマスター)DDD、ソフトウェアアーキテクチャ、機械学習

• 講演活動• 2016年

NS Study No.6 Azure IoTHub紹介アプレッソ 最新IT事例セミナー Azure Machine Learning セミナー登壇SANSAN DDD勉強会発表

• 2015年FEST2015 (Channel9で動画公開)MSxNextscape合同 Azure Machine Learningセミナー開催Developers Summit 2015QCon 2015CloudDays2015東京・大阪 3

• 執筆活動• 人工知能アプリケーション総覧 寄稿(日経BP社、2015年9月30日発売)• ITPro:クラウドで機械学習を手近に、Azure Machine Learningの概要

www.nextscape.net 3

会社紹介

www.nextscape.net 4

設立年月日 2002年4月10日資本金 1億5001万円主要株主 株式会社豆蔵ホールディングス

(東証一部上場)

〒163-0722東京都新宿区西新宿2-7-1小田急第一生命ビル22F03-5325-1301(代表)

会社紹介

www.nextscape.net 5

クラウド、デジタルマーケティング、システム構築に強み

(※2012年~2014年マイクロソフト パートナーズ オブ ザ イヤー)

2013 Microsoft Worldwide Partner Award において

Sitecore Of The Year Asia 2013において

Cloud Partner of the Year ファイナリスト選出

Best Japanese Siteを受賞

3年連続 Microsoft Azureパートナー アワード受賞

会社紹介

www.nextscape.net 6

タワーレコード様

「NO MUSIC, NO LIFE.」のキャッチフレーズでおなじみの、音楽エンタメ・小売り事業の大手。250万点もの商品を取り扱うオンラインショップ「TOWER RECORDS ONLINE」のCMSをSitecoreで構築。2010年当時に1日当たり100万強だったPVは、2014年4月時点で205万強まで倍増。https://www.sitecore.net/ja-jp/customers/e-commerce/towerrecords.aspx

エイベックス通信放送様( dTV powerd by BeeTV )

「dビデオ powered by BeeTV」は、スマートフォン利用者向けに映画、ドラマなどを視聴可能な国内最大規模の動画配信サイトとして注目を集めている。Microsoft Azureにて、高負荷・ハイパフォーマンスに耐えうるスケーラブルな配信インフラを構築。http://special.nikkeibp.co.jp/as/201207/mpncompetency/cs01.html

400万会員を超える動画サイトの配信インフラを構築

EC売上を3年間で2倍以上にしたタワーレコードの成長を支えたCMS基盤を導入

なぜ今Microservicesなのか

なぜ今Microservicesなのか

www.nextscape.net 8

サービス切り出し指針がなかった

サービス間の連携が扱いにくかった

サービスの可用性を担保が難しかった

分散リソース実装が辛すぎた

初期SOAの思想は素晴らしかった

だが思想を実現する前にSOAの概念が拡大しすぎた

設計

設計・実装

インフラ

実装

初期SOAの思想の実現ですら難しかった

MicroservicesとDDD

MicroservicesとDDD

www.nextscape.net 10

よく見かけるのが

というやり取り。

サービスをどうやって分割すればいい?

DDDの「境界付けられたコンテキスト」が参考になり

ます

折角DDDに触れるのにそこだけ?勿体無い!

Domain-Driven Design

DDDの考える課題

www.nextscape.net 12

戦略 要件 基本設計 詳細設計 実装

変換 変換 変換 変換

この戦略はどの実装?

この実装はどの戦略?

DDDの考える課題

www.nextscape.net 13

顧客にとっては理不尽だらけのIT業界

機能追加して

機能の改善して

バグだ!すぐ修正して

工数とスケジュールの提示するけど・・・

でも工数の根拠は提示されない。提示できない。

DDDの考える課題

小さな機能追加依頼

•以前と同じぐらいのボリュームだろう、

と顧客は思っている

見積もり提示

•以前に比べて高額

•でも根拠は提示されない(できない)

不信感

•高い!遅い!前と違う!

•もっと早く、もっと安くできるでしょ?

スケジュール優先の対応

•顧客の要望は品質よりスケジュール、予

算よりスケジュール、と理解

•ソースが肥大化(品質悪化)

www.nextscape.net 14

不信感の負の連鎖

DDDの目指す世界

業務をモデルで

表す

モデルをそのま

ま実装する

モデルから業務

を改善する

www.nextscape.net 15

業務と実装のギャップを埋める

余談:業務=ドメインってこと?詳しくは後ほど

DDDのよくある誤解

そういう箇所も一部もありますが、それはDDDのメインではありません。

ビジネスモデリングなどの要求開発工程から業務フローなどの要件定義工程などを含んでいます。

www.nextscape.net 16

DDDとはデザインパターンのような設計技法

である

モデリングから実装へのプロセス

ドメインをコン

テキストで分割

コンテキストごと

にドメインをモデ

ルとして表現する

モデルをそのま

ま実装する

www.nextscape.net 17

最初はものすごくざっくりとした理解から

そもそもドメインとは何か

もっとざっくりと具体的には、ドメインとは

www.nextscape.net 18

システムを使う人にとっての関心事のことです。

DDDではドメインエキスパート、という言葉出てきます。これは業務(ビジネス)に精通している人のことを指します。

業務 業務の成果

という感じで最初はいいんじゃないでしょうか

達成したいことエンドユーザー

運用者

※異論は認めます!他にもステークホルダーはいっぱいいますよね

ではコンテキストとは何か

誤解を恐れず

に言えば、

「環境」

特定のモデル

達だけが意味

を持つ「環

境」

モデルが特定

の意味を持つ

ための「前提

条件」

www.nextscape.net 19

そのモデルは、そのコンテキストだけでしか成立しない

もうちょっと言えば もっと正確に言うと

ではコンテキストとは何か

www.nextscape.net20

メンバー同士の会話 特定の作業 あるコードの範囲

そのモデルは、そのコンテキストだけでしか成立しない

コンテキストの例

例:料金というモデル。あ

る時は送料を、ある時は発

注代金を表す

例:アカウントというモデ

ル。ある時は顧客を、ある

時は口座を表す

違うものを同じ言葉で表す 同じものを違う言葉で表す

よくある混乱

境界付けられたコンテキストとは

業務別

•在庫管理業務

•商品発送業務

顧客の組織別

•パッケージング・発送

•経理

•経営

•広告

他システム

• DDD本の例だとレガ

シーシステムが良く出

てくる

www.nextscape.net 21

つまりある程度粗い条件別にアプリを分割すること

よくある分割指針

コンテキスト(前提条件)が違うことが明確になった結果のこと

分割したコンテキストを明示化

www.nextscape.net 22

順応者

図の参考:コンテキストマッピングによる戦略的ドメイン駆動設計

https://www.infoq.com/jp/articles/ddd-contextmapping_jp

コンテキストマップ 目的1.コンテキスト間の関係を明示化

コンテキスト間の情報の伝達に

は注意が必要

他コンテキストのモデルで自分のモ

デルを侵食されないようにする腐敗

防止層(Anti Corruption Layer)の検討を

情報変更のトリガーとしてドメイン

イベントの検討を

Webユーザープロファイル

個人財務管理銀行システム

支払い追跡

オンライン銀行サービス

(レガシーシステム)

パートナー

U

D D

U

分割したコンテキストを明示化

www.nextscape.net 23

目的2.コンテキスト間のモデルのマッピング

図の参考:Modularity and Domain Driven Design; a killer combination?

http://www.slideshare.net/aca_it/modularity-ddd

コンテキストマップ

オプション オーナー

保証

モデル

製造

車コンテキスト

輸送

場所

輸送対象

輸送先顧客輸送依頼元

輸送コンテキスト

ビジネスパートナー

担当窓口 住所

ビジネスパートナーコンテキスト

from

to

不信感の負の連鎖を断ち切る

www.nextscape.net 24

モデルを顧客と作る

モデルを顧客と作る=要件定義+設計です

www.nextscape.net 25

•モデルで使用されている名詞や動詞に、顧客が知らない言葉があってはなら

ない。

•モデルがそのままコードになる=言葉がコードで使用される

顧客と同じ言葉でモデリングする。

業務の中身をモデリング

•顧客と一緒にモデリン

グすることが重要

開発者もモデリングに参

加する意義

•業務を正確に把握でき

顧客もモデリングに参加

する意義

•複雑な業務がそのまま

コードになることから

コスト感覚を持てる

重要なプラクティス、ユビキタス言語

おまけの話DDDのソフトウェアアーキテクチャ達成すべきこと

•ドメインレイヤー内でドメインモデル以外の余計なものを絶対に入れない

•DDD本ではレイヤーアーキテクチャが掲載されているが、特にこの構成を採用せよと規定されていない

www.nextscape.net 26

図の参考:DDD and Hexagonal architecture

http://tindaloscode.blogspot.jp/2013/11/ddd-and-hexagonal-architecture.html

「実践ドメイン駆動設計」ではPortAndAdapter(別名ヘキサゴナルアーキテクチャ)をお勧めしている

余計なものって?例えば

データ永続化

ロジック

トランザク

ション

権限チェック

ロジック

ドメインLayer

Port

内部Client Port

外部Client Port

内部永続化Port

外部サービスPort

HTMLWeb Gadget

RIAViewer

Web API

ESBinbound

RDBMS

In-memoryObject store

他システム

ESBoutbound

プレゼン

Layer

インフラ

Layer

DDD導入のハードル

DDDがなかなか採用されない理由

DDD本が難解すぎる

•とにかく分厚い

•前提とするスキルレベルがかなり

高い(PoEAA知ってるとか)

•章立てとプロセスが紐づいていな

いので混乱しやすい

設計・実装のイメー

ジが沸かない

•結局どうすればいいのかわからな

•どこから手を付ければいいのかわ

からない

モデリングできる人

がいない

•大抵の場合、ER図になる

•もしくは、ただ構造を表しただけ

の静的なモデルとなる

www.nextscape.net 28

小さななシステ

ムには向かない

手法

小さく実験して

も効果がわから

ない

むしろ煩雑なだ

けにしか感じな

何がいいのかわ

からない

最大のハードル:試しにくい

ハードルを越えよう

「実践ドメイン駆動設計」は読みやすいです

•本で登場するサンプルの著者による実装がGithubにあります

• https://github.com/VaughnVernon/IDDD_Samples

まずは社内システムから

•そこそこ複雑なものを選ぶ

•システム開発にあまり詳しくなく、モデリングに付き合って

くれる業務担当者に協力を依頼

www.nextscape.net 29

ハードルを越えよう

www.nextscape.net 30

要件定義中からモデルを書きましょう

•モデリングをする、ということは業務フロー=モデル、となるはずです

•逆にいうと、基本設計以降のフェーズだけでDDD採用は見送った方が良いです(負担ばかりが多くて価値が出にくい)

コンテキストマップを書きましょう

•これを軽視すると1つのコンテキストでモデリングしがちです。巨大なモデル群を作り上げてしまいます

最初からテーブル設計を絶対にしないこと

• DDDを採用すると開発プロセスが変わります。

•モデリングという作業が強要され、要件定義=モデリングしつつ実装も進めます

• ER図を作る=モデリングが完了を意味します。が、モデリングは要件定義なのでなかなか固まりません

•だからER図の作成は後回しにするしかないはずなのです

• RDBMSで保存するなら最終的にテーブル設計は必要ですが、最初からやろうとしてはいけません。無駄になるだけなら

いいですが、最悪モデリングしないで工程が進んでいきます。(もはやDDDではない)

私が感じた、実践したほうが良いプラクティス

大事!

Azure Service Fabric

Service Fabricでホスト可能なアプリ

単体で動くものであればなんでもOK

Exeファイル、javaア

プリ、node.jsなどな

ど。ゲスト実行可能

ファイルと呼ぶ

ノード内部では

Service Fabricとは別プ

ロセスとして稼働

VisualStudio使って

ServiceFabricのテンプ

レートから作ったア

プリもコンソールア

プリにビルドされる

www.nextscape.net 32

Service Fabric SDKを使った実装

www.nextscape.net 33

ServiceFabricのSDKを使って実装すると• 外部との通信が実現

• 中止、開始、停止時のイベントをハンドルできる

プログラミングモデルの種類

Reliable Service Reliable Actor

ステートレス Service ステートフル Service

Exe等の実行ファイル単位のホスティング

Service Fabricの基本

オブジェクト単位のホスティング

データを保持しない StatelessServiceクラスを継承したクラスに実装していく

データを保持する StatefullServiceクラスを継承したクラスに実装していく

Stateless Serviceの仮想メソッド達

www.nextscape.net 34

StatelessService

※StatefullServiceも同名の仮想メソッドを持っていて使い方も同じですが、クラス階層を辿っても、StatelessServiceとStatefullServiceは関連がありません

自作クラス

Task RunAsync(CancellationToken cancellationToken)

Task OnOpenAsync(CancellationToken cancellationToken)

Task OnCloseAsync(CancellationToken cancellationToken)

void OnAbort()

IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()

サービス起動のイベントハンドラバッチ処理用

サービス起動準備の最後にレイズするイベントのハンドラ。初期化

処理用

サービス停止イベントハンドラ

外部からの着信を待ち受けるリスナーを返却

する

サービス中止イベントハンドラ

※全部仮想メソッドなので必要なメソッドだけOverrideする

上の4つのメソッドはイベントハンドラ

Service Fabricの外部と通信する

www.nextscape.net 35

StatelessService

RunASync, OnOpenASync, OnCloseASync, OnAbort

自作クラス

ICommunicationListener

自作のリスナークラス

OpenASyncメソッドの戻り値で返す文字列が重要。外部からの着信をリッスンする場所を返却する例:http://ホスト名:port/ほげほげ

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners(){

return new ServiceInstanceListener[]{

new ServiceInstanceListener(serviceContext =>new 自作のリスナークラス())

};}

Task<string> OpenAsync(CancellationToken cancellationToken)

Task CloseAsync(CancellationToken cancellationToken)

void Abort()

見ての通り、リスナーは複数返せるのでエンドポイントを複数用意できます。1つはhttpで、もう1つもhttpでPort違い、3つ目はtcpでクラスタ内通信とかできます

あれ?こっちもOpen,Close,Abo

rtじゃないか

Webで通信 IISが動かないので、OWINで自己ホストします

Visual Studioに用意されるテンプレートのService Fabric WebAPIはMSDNで解説している内容の完全実装です

www.nextscape.net 36

StatelessService

自作クラス

Startup

void ConfigureApp(IAppBuilder appBuilder)

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners(){

return new ServiceInstanceListener[]{

new ServiceInstanceListener(serviceContext => new OwinCommunicationListener(

Startup.ConfigureApp,serviceContext,ServiceEventSource.Current,"ServiceEndpoint"))

};}

ICommunicationListener

OwinCommunicationListener

Task<string> OpenAsync(CancellationToken cancellationToken)

OpenASyncでリッスンするURIを組み立てて、サーバースタートしているだけ

https://azure.microsoft.com/ja-jp/documentation/articles/service-fabric-reliable-services-communication-webapi/

MSDN解説のURL

WCFで通信

www.nextscape.net 37

なんと。ICommunicationListenerを実装済みのクラスが提供されています。Nugetで入れます

完全なサンプルが見当たらないので、実装のポイントをいくつか

https://azure.microsoft.com/ja-jp/documentation/articles/service-fabric-reliable-services-communication-wcf/

MSDN解説のURL

プロジェクト構成

※サンプルではクライアントも同じクラスタ内で稼働させる必要があるため、クライアントをStatelessServiceでプロジェクト追加します

プロジェクト参照します

WCFで通信

www.nextscape.net 38

WCFホスト側の実装

Calculatorの実装がサンプルに見当たりません。適当に作ってくださいclass Calculator : ICalculator{

public Task<int> Add(int value1, int value2){

return Task.FromResult(value1 + value2);}

}

<Resources><Endpoints><Endpoint Name="WcfServiceEndpoint" Protocol="tcp" Port="8515"/>

</Endpoints></Resources>

リッスンする場所とプロトコルを定義して名前つけます

internal sealed class WcfHostStateless : StatelessService{

private ICalculator _calculator;public WcfHostStateless(StatelessServiceContext context)

: base(context){

this._calculator = new Calculator();}

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners(){

return new ServiceInstanceListener[]{

new ServiceInstanceListener(serviceContext =>new WcfCommunicationListener<ICalculator>(

wcfServiceObject:this._calculator,serviceContext:base.Context,endpointResourceName: "WcfServiceEndpoint",listenerBinding: WcfUtility.CreateTcpListenerBinding()))

};}

WCFで通信

www.nextscape.net 39

サンプルでServiceUriというオブジェクトが説明なく出てきます。これはWCFを実装したホストの場所を保持したUriオブジェクトです。例:”fabric:/アプリ名/サービス名/”

WCFクライアント側の実装クライアント側にもライブラリをいれてください

private void CallWcf(StatelessServiceContext context, string endpointName){

var binding = WcfUtility.CreateTcpClientBinding();

IServicePartitionResolver partitionResolver = ServicePartitionResolver.GetDefault();

var wcfClientFactory = new WcfCommunicationClientFactory<ICalculator>(clientBinding: binding, servicePartitionResolver: partitionResolver);

var calculatorServiceCommunicationClient = new WcfCommunicationClient(wcfClientFactory,new Uri("fabric:/ServiceFabricWcf/WcfHostStateless"),ServicePartitionKey.Singleton);

var result = calculatorServiceCommunicationClient.InvokeWithRetryAsync(client => client.Channel.Add(2, 3)).Result;

}

サンプルそのままです

this.CallWcf(this.Context, "WcfServiceEndpoint");

RunAsyncの中でCallWcfメソッドを呼びます

Wcfホストと同じEndpoint設定を記載します

最後に

で一緒に働きませんか!

一次請け案件100%

SESやっていません。すべて自社開発(西新宿)

www.nextscape.net 41

DDDプロジェク

ト2つ進行中

Scrumプロジェ

クト3つ進行中

裁量労働制

コーヒー、ミネラ

ルウォーター、お

茶飲み放題

デュアルディスプ

レイ支給

技術書籍は全額会

社負担

各種社外研修も全

額会社負担

海外カンファレン

スも積極的に行け

ます

募集中!

•PM

•PL

• SE

•スマホエンジニア

イラストはこちらを利用させていただきました

いらすとや:http://www.irasutoya.com/

www.nextscape.net 42

ブースにも

来てね!

NS Studyで待ってます!

top related