コードで理解するDDDの戦略的設計・戦術的設計のつながり勉強会メモ
だいぶ経ってしまったが8/4(土)にDDDの勉強会に参加してきたのでその時のメモまとめ 講師は現在ビズリーチに在籍されている松岡さんで、自分も本人とは気づかぬうちにDDD関連の調べ物をしている際にブログを拝見させていただいたことがある方でした。 当初の予定よりも30分延長してくださり3時間半の長丁場で内容の濃い勉強会でした
DDD
まずは原典にあたってみるのが良い https://domainlanguage.com/ddd/reference/
設計したモデルとコードを一致させる モデルと実装の変更に耐えられる設計でないといけない -> これを実現するのが戦術的設計
モデルとは
対象領域の特定の側面を表現し、関連する問題を解決するために使用する対象物 ユビキタス言語でモデルを表現する
知識
問題領域の知識(Why,What)
お客さんの業務 ユーザのニーズ 市場 ->聞く、情報収集をする、フィードバックをもらう
解決領域の知識(How)
ツール、ライブラリの使い方 コード文法 ->実際に試して得る
境界づけられたコンテキスト
特定のモデルが適用される境界
戦略的設計
コンテキストを定義、再配置するなど?
戦術的設計
構成的にやりやすい形にするための設計?
アーキテクチャ
レイヤードアーキテクチャ
3層アーキテクチャなど Infra層がAppやDomainに依存する -> DBを差し替えたりなど出来ない
ヘキサゴナルアーキテクチャ
オニオンやクリーンはこれの派生 ポートとアダプターで外部サービスとやりとり? 外側は交換可能だが、中心はそんなに変わらない
オニオンアーキテクチャ
infra層が一番上に持ってこられるアーキテクチャ -> infra層がAppやDomainに依存しない マイクロサービスなどで用いられている(サービス同士のhttp通信などはinfra層同士のやりとり) https://dzone.com/articles/onion-architecture-is-interesting
クリーンアーキテクチャ
ドメイン層
ドメインサービス
ドメインサービス
個体で扱えない、集合体で扱うものなどに利用(部屋の空き時間を知る場合は各予約単体では分からないため予約の集合体から空き時間を確認する必要がある) ただ、極力使わないようにするべき
ファクトリ
ドメインモデル
エンティティ
可変 IDを持つ IDで比較する 1テーブルに相当
値オブジェクト
不変 IDを持たない 値で比較する テーブルの値に相当
ドメインイベント
集約
整合性を保つ単位? -> トランザクションで整合性を保証する単位? 1repository1集約 1つのコンテキストの中に複数の集約がある
マイクロサービス
マイクロサービスはコンテキスト単位
ドメイン駆動設計について調べてみる - Part1
ドメイン駆動設計について自分なりに調べてまとめてみる まずはドメインや境界づけられたコンテキストなど実践ドメイン駆動設計の第2章から
ドメイン
組織が行う事業やそれを取り巻く世界のこと
ドメインモデル
ドメインの知識や振舞を抽象化したもの
業務の"データ"と業務の"機能"をコードで表現 -> データクラスと機能クラスに分けるのはアンチパターン => クラスにカプセル化 -> データと機能を行ったり来たりしながらドメインモデルを作り上げていく
ドメインモデルをみんな(データベースや各アプリケーションなど)で共有する
あちこちに分散しがちな業務ロジックをデータ中心に整理して集約する ->ドメインモデルに業務ロジックを集めて重複コードを減らす
ドメイン層のオブジェクト
業務の"関心事"を表現したオブジェクト
業務サービスの実行役
独自の型(利用者の関心事)だらけにする
ユビキタス言語
ドメインエキスパート(その業務に詳しい人)や開発者を含めたチーム全体で作り上げる共通言語
境界づけられたコンテキスト
ユビキタス言語が使われるコンテキストを明示したもの
--> ドメイン毎(サブドメインの集合体)の境界を表すものなのか、そのドメインが共有されている組織を表すものなのか、はたまたそのどっちでも無いのか、ここについてまだ理解ができていない・・
https://www.slideshare.net/masuda220/ss-26583161 https://www.slideshare.net/masuda220/ss-57352072 https://www.slideshare.net/hirokishigemura9/ruby-ddd
spring-data-jpaを使った場合の単方向と双方向について
spring-data-jpaを使った場合の単方向と双方向についてよく分からなかったので、自分なりに調べたことなどをまとめてみました
単方向
- 後から双方向にデータをたどりたいといった時に単方向で作ってしまうと改修に手間が掛かる可能性がある
one側
@Entity @Data public class Department implements Serializable { @Id @Column(name = "department_id") private String departmentId; @OneToMany(name ="member_fk", referencedColumnName="member_id", nullable = false) private List<Member> members; }
many側
@Entity @Data public class Member implements Serializable { @Id @Column(name = "member_id") private String memberId; }
双方向
双方向には下記の2パターンが存在する
- mappedByを使う方法
- @JoinTableを利用する方法
- あいだにテーブルを仲介する場合に利用
mappedByを使う方法
- @OneToManyアノテーションを付けて、mappedByで関連させる相手側エンティティのフィールドを指定する
- 相手側(多側)で外部キー用のフィールドを持つ必要がある
one側
@Entity @Data public class Department implements Serializable { @Id @Column(name = "department_id") private String departmentId; @OneToMany(mappedBy="departmentFk") private List<Member> members; }
many側
@Entity @Data public class Member implements Serializable { @Id @Column(name = "member_id") private String memberId; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "department_fk", referencedColumnName = "departmentId") private Department departmentFk; }
JoinColumnアノテーションについて
- 結合表のための外部キーカラム名を「name」で指定できる
- 外部キーカラムによって参照された結合先テーブルのカラム名を「referencedColumnName」で指定できる
- ※その場合は必ず結合先テーブルのプライマリキーとなっているカラムを指定
- 複数の外部キーカラムがある場合は@JoinColumnsを使用して、それぞれの関連に対して@JoinColumnを指定する必要がある
- @JoinColumnを明示的に指定しない場合は、リレーションが双方向でなく単方向に扱われてしまう
@JoinTableを利用する方法
※こちらは概要のみ
- @JoinTableを使ってテーブル結合させ、joinColumnsと@JoinColumnを使って結合表のための外部キーカラム名を「name」で指定する
- また、外部キーカラムによって参照された結合先テーブルのカラム名を「referencedColumnName」で指定する
- 同時にinverseJoinColumnsと@JoinColumnを使って結合表のための相手側の外部キーカラム名を「name」で指定できる
- それと合わせて、外部キーカラムによって相手に参照される結合先テーブルのカラム名を「referencedColumnName」で指定できる
単方向を使うべきか双方向を使うべきか?(※編集中)
単方向OneToManyをお薦めしない理由
子テーブルは対応する子オブジェクトにマップされないカラム(FK)を持つことになるから一般的じゃないってのが主な理由 もし単方向関連だったら、子オブジェクトは親オブジェクト無しでも存在できてしまう。もし親が必要だとしたら双方向ににするべきでは!?
ちょっと視点を変えて「関連の所有」という見方をすると・・(※ここは参考とだいぶ違うので理解が間違っているかも・・) 上記の例の場合だと、一対多の関連はどちらが所有してるのか? → 直感的に考えるとdepartmentが複数のmemberを所有しているため「department」では? → 実際は「member」、なぜならmemberは外部キーから関連するdepartmenetが辿れるが、departmentからは対応するmemberを辿れないため → こうなってくると当初考えていたのと所有者が逆に・・ => ORマッパー的には逆のように見えてしまうため単方向を使うのは避けたほうがよい??
FetchTypeについて
データをDBから取得する際に関連テーブルの方も一緒に取り出すかどうかで下記の2タイプがある
- LAZY → 取得しない(※正確には遅延ロード)
- EAGER → 取得する
LAZY
- 関連テーブルへのアクセスが発生したタイミングでロードされる
- 元テーブルのみのアクセスの場合は関連テーブルのロードは行われない
- フィールドの呼び出しを最初の呼び出しで行う
- 元テーブルのみのアクセスの場合は関連テーブルのロードは行われない
EAGER
- 元テーブルにアクセスした際に関連テーブルも合わせてロードしデータが取得・格納される
- そのフィールドにアクセスがあった時点でフィールドをデータベースから呼び出す
最後に
単方向・双方向のどちらを使うか、また使った際に各オプションをどうセットするべきかについてちゃんと理解しする必要があったため今回、まとめてみた
個人的には当初は外部キーはEntityクラスとして持たないほうが良いのでは?と思い単方向を使うつもりでいたが、関連についての記事などを見てみたりあらためて調べると双方向にシフトした方が、 本来の使い方や、今後の拡張性も考えると良さそうな気がしてきた。
ただし、この辺りはN+1問題や今回はあまり取り扱えていない「insertable,updateble,nullable」の辺りもしっかり理解した上で判断するのが良さそうなのでそのあたりについても調べてまとめる必要がありそう
参考させていただいた記事など
RESTについて
この記事について
マイクロサービスアーキテクチャを採用するにあたって各サービス間の通信方法としてRESTを使うことを想定していた 対応を進めていくにあたってそもそもRESTについて調べた際のメモ。 RESTにもいくつかの段階、レベルがあるということを知ったのでそちらについてのメモとなっています
RESTの成熟度レベル
- Level 0:SOAPやXMLでやりとりをするHTTP通信 → URI と HTTPが 1to1
- Level 1:URLでリソースを表すようにする(リソースを動詞でなく名詞で表す)
- Level 2:HTTPメソッド(GET, POST, PUT, DELETE)を正しく使い分けている
- Level 3:レスポンスの中に関連するリンクを含める → HATEOAS
[アプリケーションのRESTful度合いをどう計測するか|https://www.infoq.com/jp/news/2011/05/measuring-rest] [RESTとは何か|http://qiita.com/aosho235/items/125af74e2eab66c7a816] [Richardson Maturity Model|https://martinfowler.com/articles/richardsonMaturityModel.html] [フロントエンド開発者の僕にもやっとわかった!RESTfulの本当の意味|https://www.webprofessional.jp/what-does-restful-really-mean/] [第3回 マイクロサービス アーキテクチャ 読書会 メモ|http://nashcft.hatenablog.com/entry/2016/09/08/014818]
JJUG CCC 2017 Springに行ってきた
今更ながら参加してきたので当日のメモなどを 本当に適当なメモ書きレベルなので後で編集したい・・
レガシーアプリケーションの巻き取りとモジュール分割
ブランチ運用
テスト(CI/CD) 単体 → junit(validation etc) 画面単体 結合
@Runwith(Enclosed.class) → レビューアに優しいテストコード
selenide → 自動テストに利用
SpotBugs
tool
- Check style
- PMD → Check styleに近い。コピペ検出機能がある
- FindBugs → バイトコード解析
- Checker framework → Java8のJSR308(Annotation on Java types)を利用
- Google error-prone → コンパイル時に解析。クラスもソースも見ているためソースコードの自動修正機能がある。eclipse非対応。
コーディング規約ならCheckStyle 問題検出は、PMD、SpotBugs、CheckerFw、 error-proneから選ぶ感じ
findbugs
onlyAnalizeで対象クラスを絞る visitorsで利用detectorをけずる(何を優先してチェックするのか) → これは使いやすいと思うとのこと
Spring cloud stream
Batchをスケールアウトしたことで、ポーリングによるRDBへの負荷が高まった → spring cloud streamを使った仕組みにつくりかえ => イベントドリブンに作り変え
SCS(spring cloud stream)
- メッセージドリブンなマイクロサービスが実装しやすい(pub-subモデル)
- spring bootアプリケーション
- consumer groups → レポート作成のスケールアウトが容易になった => これによりノードごとに別IDの処理が行えるようになった(Batchをスケールアウトしたことで、ポーリングによるRDBへの負荷が高まった)
- binder application → アプリ-ミドルウェア間が疎結合になるらしい(共通のdestination設定でOK)
spring batch job管理テーブルに大量INSERTでエラー(Sink側のSpring Batchが大量に起動した時に、Job管理テーブルに大量のinsertが流れてエラーに… )
- maxAttemptの調整 → これだけだと不十分
- DeadLetterQueue → エラーリカバリ用のMQを用意 => SCSのautoBindDlqをtrueに する
→ただ根本対応にはなっていないのでJobRepository側の対応方法を調査中。。
ポーリング型からイベントドリブンに変えたことでスループットが向上
CloudFoundryへ移行してスケールアウトが容易にできるようにする → cflogin, cfpush? => この辺も含めて謎なので調べてみる
c.f) 第2世代への作り変えについて https://www.slideshare.net/techblogyahoo/jjugccc-cccf1-phpjava
c.f) pulsar https://www.infoq.com/jp/news/2016/10/pulsar
Jigsaw
・module-info.java - dependency disclosure scope → JAR内のこのファイルにモジュールの依存を記述する(module-info.javaでjarのメタ情報(依存性と公開範囲)を管理してModule化)
java –list-modules、現状73個のモジュールがリストされる
Cookpad tech kitchen#8に参加してみた
Cookpad tech kitchen #8に当選できたので初参加して来ました 色々と経験出来たのでメモ
tech kitchenについて
まず、ガッツリ料理が出てきたのにびっくり。。 野菜もふんだんに使われていて、見た目も味もステキな料理が食べられてこれだけでも来た価値が・・とちょっと思ってしまった笑 飲み物も提供されていて、セッション始まるまでは何しに来たのかちょっとわからなくなるほどのおもてなし感
セッションについて
非同期なジョブ
ワーカーがスケーラブルではない → キューをトリガーにdockerでワーカーが必要な分だけ起動する → activejobとAWS(SNS,SQSなど)を活用
Barbeque → ジョブキュー管理システム
- Hako → コンテナ管理ツール
アプリとワーカーで同じイメージから起動しているため環境差分が無くスケールしやすい
kuroko2
クックパッドのジョブ管理システム
美しいバッチの壊し方
- Bricolarge
- 1ジョブ = 1SQL → よいバッチ(運用しやすいバッチ=障害の対応がしやすい)を作るため
美しいバッチとは!?
- I/Oの対象ごと(DB、テーブル、ファイルなど)にジョブ分割
- ジョブ管理システムで結合
Others
Hakoとは
dockerで賄えないDNSやDB接続情報なども設定ファイルで管理できる(?)ツール
DWHについて
DBA的な仕事もしつつアプリ(バッチ)もガッツリ書く ブリコラージでジョブ管理をしているのでバッチはほとんどRuby製(ただし、中にはシェルなどを呼び出している部分も・・) DWH(Amazon redshift)のキャパ的にはバッチ処理自体では全然余裕があるが、DEVやビジネスサイドで呼ばれるクエリ処理がガンガン来るため大変・・(グルーバル展開もしているため、それこそ一日中来てしまう。。)
Cookpadの開発環境について
本番と開発環境のDBのレプリケーションについて
本番DBと開発DBの間にもう1個DBがかまされている(※わかりやすさのため準本番とする) 本番DBから準本番DBへのレプリケーションはステートメントベース 準本番から開発DBへのレプリケーションはレコードベース(IDが変わってしまうなどの問題があるため) 準本番から開発DBへのレプリは開発用のデータはID1から、レプリは必ず6万以上から、といったような感じでMySQLのAUTO INCREMENT(?)機能などを活用して運用している どうしてもレプリ時にエラーとなってしまうデータ(重複エラーなど)は無視する 詳しくはブログにも書いてあるとのこと
開発チーム、体制について
リリース(?)、システムははリクエストごとにdockerイメージがスケールしていくような構成になっている → スケーラブルな仕組み 開発チームはビジネスサイドのディレクターさんなども含めた2〜3人とかの小規模なチーム プロジェクトにチーム(人)が紐付いているような感じで体制は流動的
セッションはRubyもAWSも使っているわけではないため概念的な部分とかしか理解できず、持ち帰れたものが少なかったかも・・ ただ、やっぱりバッチがどうあるべき、どういう問題を抱えていてこうした、みたいな話が聞けて良かったし、個別にお話させて頂いて色々聞けたのも良い機会でした!
ダンスレッスン@20170605
ダンスレッスン
ちゃんとしたプライベートレッスンを受けるの約2年ぶり・・ 久しぶりのレッスンかつ初めて習う先生、初めて行ってみたスタジオで色々と新鮮さや学びがあったので忘れないうちにメモ
レッスン対象
チャチャチャ - バリエーション
レッスン
全体
1個1個の音をはっきりさせる → 音を一つ一つ言いながら動けるくらいにはしておく 2人で動くところはどこの音の瞬間にどのアクションになるのかはっきりさせておく
出だし
4でキック、1でアクション 次は3で右足を寄せるところまでいく
1で振り向いたところ~
1でパートナーと合わせてアクション その後は右のアームを下げていきながら、床を踏んでボディテンションを上げていく
タイムステップetc
2&3で右にタイムステプ その後は4で左足を寄せる、&で左足に踏み変えながら180°回転、1で右足を踏む
シャッセで移動
1個の音(半拍)で踏み変えて、次の足を出して踏む直前まで動く 1個1個で出て踏んでいるようでは遅い
前に移動
右→左→右で前に移動、&で左、4で右足(+1で左足?) その後は4で自分が前に出ながらパートナーを引く(この時に右手でしっかり押さえる) 1で今度は自分が下がってパートナーを出す
入れ替わり~ランジ
4で左足体重で180°回転(この時、やや自分側に体を引く感じ) 1で右足に乗る 2で左足をやや入り気味に出して3でロンデして1でランジ
パートナーのスピン
パートナーがスピンするところではムリに回そうとしない(ワクを作ってパートナーが回転する場所を作ってあげるだけくらいのイメージ) 1でラインを作るきっかけを与えるだけくらいで良い
いろいろ教わったのでちゃんと動きながら理解してモノにしたいし、他のところでも使えるようにしないとな。。