エンジニア的なネタを毎週書くブログ

東京でWebサービスの開発をしています 【英語版やってみました】http://taichiw-e.hatenablog.com/

増田亨さん ドメイン駆動設計の正しい歩き方 を聞いてきました #bpstudy

BPStudy#141〜DDD(Domain Driven Design)実践の現場 - connpass に行ってきました!

特に心に残ったことまとめ

  • DDDは、「ソフトウェアの変更を楽で安全にする」ことに振り切っている。
    • 逆に言えば、変化がないソフトウェアには最適ではない設計かもしれない。
  • コアドメインに集中する。真のコアのみを切り出して、そこに集中する。
    • 例えば、すべてをバリューオブジェクトとエンティティでやろうとするような試みは失敗パターン。
  • モデリングとコーディングは行ったり来たり。いかに行ったり来たりするかが大事。
    • 仮設を立ててコードを書いてみる。「軸」の候補が3つあるなら3つ書いてみる。「こんなの数時間書けばわかる」!!

以降、ノート

言葉の使い分け:ビジネスロジック vs ドメインロジック

  • ビジネスロジック」は、そもそものビジネスのルール。ソフトウェアかどうかは関係ない。(ITを使っていないビジネスはいくらでもある)

それに対して

コアドメインに集中する

DDDは「『核心にある』複雑さ」に立ち向かうためのもの。ソフトウェアすべてを設計の対象とするのではなく、コアに集中する。
コアを切り出して集中することで、不思議と周りも綺麗になっていく。

例えばホテルの予約サイトなら…

全体の中でも、特にコアとなるビジネスロジックは料金計算。*1*2


コアドメインを独立させる。独立とは、 ここだけで開発できて、ここだけでテストできる状態にすること。画面の要素やデータベースのテーブル定義は一切入り込まない。
独立させたら、特徴を掴むためにモデリングする。自然言語も使って良い。

この段階でのモデルはあくまで「仮説」。仮説を確かめるために、コードを書いてみる。

すると…
コーディングしづらいなどの問題が見つかることがある。

その場合、「モデルにフィードバックする」。
コーディングしづらいのは、モデルが適切でないのかも。モデルを更新し、再度、コーディングを試してみる。

…というように、モデルとコードを行ったり来たりすることが重要!!

そして、このモデルは実装のために作っているので、必ずしもきれいにならないことも多い。*3


コアドメインが複雑なのであれば、その中でもさらにコアを探す。
何が中核なのか。
「幼児の寝具」ではないだろう。

シーズンか、一室何名か、特別室/一般室か。
どれがコアなのかわからなかったら、3つそれぞれを軸にしたコードを書いてみる。
数時間書けばわかるはず!!*4

ビジネスを継続的に学ぶ

よくある失敗の一つが、「ビジネスを表面的に捉えて理解した気になる」。
もし深く理解できていれば、例えばサンプルの計算結果のタイポに気づけるはず。
あるいは、書かれていない部分の計算結果がわかるはず。

更に、周辺のビジネスの理解は重要。
どんな背景があるのか。
周りが分かってくると、コア部分で何を作らなければならないかがまた見えてくる。*5

エヴァンス本の読み方

読み方のコツ*6が有る。

*1:まさに「ホテルの予約サイト」の「料金計算」を主の生業として数年やってきた人間なので、このお題の登場にはビックリ

*2:検索や予約はコアではない… は私が言ったんじゃなくて増田さんの言葉ですからね!

*3:実装のためでない、ビジネスの理解のためのモデルにも価値がある。ただし実装には貢献できないかもしれない。これらは切り分けて考える

*4:これが今回一番心に刺さったフレーズなのです

*5:これ、よく私言ってるのですが… エンジニアはビジネスの背景をきちんと理解し無くてはならない。今の私達の現場は人数が増えてきたので、ポジションが別れている。高度なサッカーで11人がボールに群がっていくことはないはず。一方で、11人それぞれが、自分のポジションのことだけでなく、他の10人がどんな意図でどんな動きをしているのか理解できなければ、チームプレーはできないはず!

*6:・冒頭、「突然わけのわからないストーリーが始まる」ので、はじめは読み飛ばすべし ・結構な前提知識が必要 ・文章の構造を捉えつつ、重要なところだけ読む ・文章に癖があって読み方のコツが必要 という説明を聞いて、「それ普段、お仕事で読んでいる某文章と全く特徴が同じなんですけど…」 と思った次第。大事なことが書いてあるけど読みにくい文章の読み方って共通点があるのかな。

VOYAGEさんの「技術力評価会」がすぐにでも取り入れたいくらい面白かった! #EM集会

今日はこちらに参加しました!
エンジニアのマネージメントで悩んでいる人が集まる会 #3 - connpass
f:id:taichiw:20190524222454p:plain

今までそれなりにいろんな勉強会/ミートアップに参加してきたのですが、
「マネジメント」「マネージャー」を冠した会は初めてでした。
主催者の方や、一部の参加者の方はアジャイル系と重なっている印象でした。

なんと、寿司と酒が出てきましたよ。
f:id:taichiw:20190524222548p:plain
後半の懇親会用のものだったようですが、発表が始まる前からカンパーイ!

VOYAGE さんのめっちゃ攻めてる「技術力評価会」

今回のテーマは「評価」。
一件目の発表、@katzchangさんの「技術力評価会の話」の発表が大変印象に残ったので、こちらを書き留めておきたいと思います。

VOYAGE さんでは、評価制度の一環として、「技術力評価会」という制度が行われているそうです。
こちらの資料が詳しいのですが、

要点をまとめると、

・半年に一回行われる
・一回90分のセッション
・被評価者は、自身の成果を発表する
・評価者は発表を聞き、被評価者と議論する
・セッション終了後、評価者は評価レポートをまとめ、口頭で被評価者にフィードバックする
・被評価者の発表内容と、評価者の評価レポートはすべて社内に公開される

・評価者は、原則、被評価者と別のチームから選ばれた、「ミドルエンジニア」「シニアエンジニア」「シニアより上のグレードのエンジニア」
・社外評価者(他社のCTOだったり、デブサミで発表しているような人だったり…)が参加することもある
・評価者と被評価者のマッチングは、評価委員会(各チームのリーダーで構成)が決める

・後日(評価レポートが出揃ったあと)、被評価者はチーム内で、技術評価会の振り返りを行う。
・振り返りでは、評価会で得たFBの共有(例えば、「そこはmysqlを使ったほうがいいんじゃ?」のような意見)がチームに共有される
・また、評価会制度そのものが振り返りの議題に上がることもある

というものでした。


この評価会制度、とても良さそうだなと思ったのが二点あります。

1. 被評価者が、コンテキストが違う人に対して説明するスキルを磨ける
f:id:taichiw:20190524223141p:plain:w200
個人的には、発表スキルは、エンジニアにとって、とても大事なスキルだと思います。
しかも、別のチームの人(=被評価者のやっていることをよく知らない人)に対して説明するということで、一段更に上のプレゼン力が求められるわけです。
プレゼンに限らず「ちょっと説明が下手な人」って、聞き手が何を知っていて何を知らないのかが分かっていないケースがままあるので…。

発表してくださったkatzchangさんは、自分のメンバーに対して、「転職するとき、採用面接で、コンテキストが違う人に自分がやってきたことを説明する力必要だよ」と言ってモチベートしているそうです。

2. 評価者が、「他社を評価する」という経験を得られる
f:id:taichiw:20190524225557p:plain:w200

ミドルクラスのエンジニアって、普通にしているとあまり「他社を評価する」機会がないんですよね。
(360度評価をしていなければ)人の給料を決める機会がないですし、
採用面接の面接官をしているケースも少ないんじゃないかと。

そういったメンバーに、「他人を評価する」機会を与えられるということ、とても素晴らしいと思います。
なぜなら、「評価する」ことを考え、知ることによって、「自分が評価されるとはなにか」を考えることができるようになるからです。

以上の二点(だけではないですが)から、「技術力評価会」、とても興味深い制度であると感じました。

一方で、給料が関わってくるからこそ、何かしら批判的な意見も出てくるようで*1
katzchangさんのように高い目線を持ったシニアな方が、意味を伝え、啓蒙し続けて行くことが、仕組みを維持するための鍵の一つのようです。

いきなりこれを評価制度に取り込む、というのは難しそうですが、
「コンテキストが違う人に自分の成果を伝える」「他社を評価する」
という仕組みを上手く自身のチームに取り入れたいと感じました。
*)とはいえ、評価だからこそみんな真剣にやるわけで、お金がかかってないとモチベーションがわかない人はいそう…。

懇親会で話したこと 走り書き

評価が難しいタイプ

  • アベレージヒッター
  • 三振かホームランかタイプ

※アベレージヒッターは挑戦がないところが辛い
※インフラのプラットフォームを提供している会社で、明確に「三振タイプは評価しない」を打ち出した会社がある

挑戦は認めてあげたいけど…

  • それでやらかしていいのはジュニアレベルくらいまでなのでは。ある程度のレベルの人が、「リスクも考えずにやってみました」は「挑戦」ではない。

ドバーッと人を採用した

  • 「様々な」人が増え、価値観もバラバラに

スペシャリスト系の評価

覚えた単語

  • ノーレイティング
  • OKR

*1:プレゼン力があるやつの勝ちじゃんとか、評価者ガチャじゃんとか

増田亨さん「マイクロサービス 4つの分割アプローチ」を聞きに行けなかったんだけど教えてもらったのでまとめてみる #jjug_ccc

背景

私の増田さん追っかけは2017年11月に遡るのですが、
https://taichiw.hatenablog.com/entry/2017/11/05/175105
当時、APIの設計や、そこからつながるマイクロサービスの設計については、まだ試行錯誤されている段階… というお話を聞いていました。

当時の私も絶賛、「どう切るのが良い切り方なのだろう」と悩んでいたところだったのですが…

あれから一年半あまり経って、今年のJJUG CCCで増田さんがマイクロサービスについて話される ということで、これはぜひ聞きたい! と思っていたのです。
マイクロサービス:4つの分割アプローチの比較

思っていたのですが、都合が合わず、参加できず………

ということで、せめて公開された資料でも後で読もうと思って備忘録代わりにFacebookに投げておいたところ…
f:id:taichiw:20190520183702p:plain
「聞きに行きましたよ!」と優しい同僚が話しかけてくれたのです。

こういうのはダメ元でSNSに上げてみるもんだなぁ!

と、いうことで、聞いた話と公開されている資料などなどから勝手に感じ取った感想を書き残しておきたいと思います。*1

分割には4つのアプローチがある

タイトルにもある通り、サービスの切り方には以下の4通りのアプローチがあり、これが組み合わせて使われているのが現状 というお話だったようです。

…ということで、一年半前の私の疑問、
「計算ロジックはデータと同じサービス内に置くべきか否か」は
ケース・バイ・ケース ということになってしまうようです。

ただ、今回、4パターンに名前をつけてもらったことで、名前を使った議論ができそうな予感です。これについて少し見ていきたいと思います。

…………と思ったんですが、直接聞かないとやっぱりよくわかんないなこれ。
モノリスを分解していく過程で、
ざっくり縦(時系列)に切る → ビジネスファンクション
 ↓
「そこから」更に縦に切る → 動詞/ユースケース
 ↓
「そこから」横に切る → 名詞/リソース

…というようにも読めたんだけど、そんな絵がどこにもないということはそういう意味じゃないのかな。


そしてこの、「ビジネスルール中心の構造」って

ビジネスファンクションやユースケースで切った中から共通のビジネスルールを抜き出して一箇所に集めた…… ように見えるんだけど、
これまたそういう流れの設計は語られてないから違うのかなぁ…。


んー 結論 やっぱり資料だけじゃよくわからないから直接聞きたかった!

とりあえず明日、もう一回同僚の彼に聞いてみよう。

*1:ということで、本ブログは、直接発表を聞いた者の感想ではございません

ISO25000を読んでみる - ISO25010 The quality model 前半

「『品質がいい』ってなんだよ!?」を定義したISO25000 の中に含まれる、ISO25010を読んでいます。
こちらのポータルサイトを中心に読み進めているのですが、
iso25000.com
抽象的な説明が中心(&英語)で理解しづらいところがあるため、「こういう意味かな? 例でいうとこういうことかな?」と考えたことをメモとして残します。

The quality model

「ソフトウェアの品質」を8つの項目に分類し、更に各項目が複数のsubcharacteristicsを持つ構成になっています。
f:id:taichiw:20190506235312p:plain
上記図はhttps://iso25000.com/index.php/en/iso-25000-standards/iso-25010より。

Functional Suitability

所謂「機能要件」。品質とかテストとか言うとこれが注目されがちですが、"Software Product Quality"として定義されている8項目の中の1つに過ぎません。

Functional Suitabilityを構成する3つのsubcharacteristicsのうち、
Functional completenessは、機能が網羅されたチェックリストにどのくらい『実装されていますチェック』を付けられるか
f:id:taichiw:20190504232011p:plain:w100
Functional correctnessは、そのリストになっている各機能がどれくらい正しい結果を返しているのか
f:id:taichiw:20190504232151p:plain:w100f:id:taichiw:20190504232216p:plain:w100
と解釈しました。

Functional appropriatenessは、

Degree to which the functions facilitate the accomplishment of specified tasks and objectives.

とあったのですが、この定義がよく理解できませんでした。

こちらのCase Studyを見ると、
http://www.aqclab.es/images/AQCLab/Noticias/SQP/software-quality-management-evaluation-of-software-product-functional-suitability-a-case-study.pdf

understood as the ability of the system to carry out the requirements that are needed for the different usage objects that have been specified.

とありました。ということは、先程の「チェックリストで定義された機能一覧」が、そもそもどの程度ユーザの要求を満たしているか、
要件定義そのものの品質チェック… ということでしょうか?

ISO25000を元にした、JISでは、

明示された作業及び目的の達成を,機能が促進する度合い。

と訳され、

例 不要な段階を除いて,作業を完成するために必要な段階だけを利用者に提示する。

という例がついていました。*1

Performance efficiency

「パフォーマンス」と言ってもいろいろあるようでして。

Time behaviourは速度とスループットが要求を満たしている度合い
f:id:taichiw:20190505000025p:plain:w100f:id:taichiw:20190505000151p:plain:w100

Resource utilizationはコンピュータのリソース消費に関する要求を満たしている度合い*2
f:id:taichiw:20190505000449p:plain:w100

で、最後のCapacityがまた分かりそうでわからない。

Degree to which the maximum limits of a product or system parameter meet requirements.

これだけ読むとナンノコッチャ って感じなのですが… またJISの怪しげな*3に頼りますと

製品又はシステムのパラメータの最大限度が要求事項を満足させる度合い。
注記 変数には,保存することができる項目の数,同時に利用する利用者の数,通信帯域,トランザクションスループット,及びデータベースの大きさを含む。

ということで、要は「いろんな値の最大値」がちゃんと満たされているかどうか ということのようです。

Compatibility

Co-existence

Degree to which a product can perform its required functions efficiently while sharing a common environment and resources with other products, without detrimental impact on any other product.

サーバの相乗りとか、あるいは一台のPCやスマートフォン上で複数のアプリが動く際に、他のソフトウェアに悪影響を与え(自分ばかりCPUやメモリを食うとか)ずに動作できる度合い…ということでしょうか。
f:id:taichiw:20190506230912p:plain:w100

Interoperability

Degree to which two or more systems, products or components can exchange information and use the information that has been exchanged.

と、定義されています。
ここまではすべて単体のシステムに対する指標だったのですが、"Degree to which two or more systems, products or components" なので、評価の対象が複数システムの指標のようです。複数システム間でどれだけ情報の共有がなされているのかを表す指標です。
f:id:taichiw:20190506231426p:plain:w100

同じ区役所のビルの1階と3階と5階に、同じような内容をそれぞれ別のフォーマットで書いて提出しなくてはならない*4お役所のシステムはInteroperabilityが最悪なわけですね。何のためのマイナンバーですか。

Usability

なんとなく使ってしまう言葉ですね。

Degree to which a product or system can be used by specified users to achieve specified goals with effectiveness, efficiency and satisfaction in a specified context of use.

と、定義されていて、specifiedが何度も出てきます。
「『特定の』ユーザが、『特定の』状況において、『特定の』目的を達成する ことに対してどれだけ役に立つか」を表す指標なんですね。

逆に言えば、そもそもユーザとして想定されていない層の人達が「使いにくい!」と感じることは、この指標の観点に於いては問題ない ということになります。

subcharacteristicsは6つです。

Appropriateness recognizability : なにか達成したいことがあるユーザに、このプロダクト(システム)が使える! とそもそも認識してもらえる度合い。
f:id:taichiw:20190506232650p:plain:w100

Learnability : いざ使う気になってくれたユーザの、操作方法の学びやすさ。
f:id:taichiw:20190506232821p:plain:w100

Operability : 操作性。んー どういうのを指してるのかな…
スマートフォンのUIなのにやたらボタンが小さい上に並んでいて誤操作しやすい(PCでマウスだったら特に押すのが難しくない)」のは、Operatabilityが悪い例でしょうか。
f:id:taichiw:20190506233204p:plain:w100

User error protection : ユーザが誤った操作をしずらい度合い。
「数値しか受け付けないフォームは数字しか入力できないようにする」はここに入るでしょうか。

User interface aesthetics : "aesthetics"は「美学」という意味だそうです。狭義の「UIが良い/悪い」はここに入りそうです。

Accessibility :

Degree to which a product or system can be used by people with the widest range of characteristics and capabilities to achieve a specified goal in a specified context of use.

ということで、ここでは"people with the widest range of characteristics and capabilities"の広さが指標になっています。
Usabilityのはじめに、特定のユーザが、特定の状況で、特定の目的 と書きました。この『特定のユーザ』の範囲が広く、多くの人から使ってもらえる製品 = Accessibilityが高い製品 と言えるようです。
f:id:taichiw:20190506234501p:plain:w100

*1:英語でこれっぽい記述は見当たらないので、翻訳時に足されたのでしょうか

*2:例えばスマートフォンのアプリだと、過剰にCPUやメモリを使うアプリは困りますもんね。Webの、サーバサイドの開発が主な自分としてはハードウェアまで含めてまるっとシステムなのでちょっと感覚が違うのですが…。

*3:もしかして原文のPDFを見たら書いてあるのかな?

*4:詳細は忘れましたが、保育園関係の何かでした

リアルタイムにそこそこ重い処理を実行するためには、前処理が重要… なのかな? #jsug

JSUG勉強会 2019その3 LINEにおけるSpringの活用 に参加してきました。
ここがとっても気になったのです。

Personalized content recommender systemであるSmart Channelは、ユーザーの属性や趣味趣向を推定し、各個人に最適なコンテンツを推薦するServiceです。
LINEの膨大なトラフィックを受けながら、可能な限りリアルタイムにRecommendをするために、Architectureや実装にいくつかの工夫をしています。

「個人個人に違う結果を出すために、毎回リアルタイムで計算」ってどこかで(私が)(業務上)聞いたことある!
すごい気になる!

ということで行ってまいりました。初LINEさんオフィスです。
f:id:taichiw:20190325234503j:plain
f:id:taichiw:20190325234523j:plain
会場のカフェ。おしゃれだった。


さて、@hackmylife さんの Personalized content recommender system on Springです。

自分が気になっていた、以下にリアルタイムに処理をするか、という点。

以下の二点が特にミソなのではないか と感じました。

・Redisとの通信がWebflax形式のNon-Blocking. フィルタリングなどの処理はSubscribeしたときに動く。
・前もってTrainer側で、Rankerが「扱いやすいように」処理する。例えば、逆行列を求める処理がアルゴリズム上必要なのだが、これは事前に処理しておく。
この「事前処理」はスライドのこちらのページで触れられています。

"User traffic" を起点に動作する、CRS Engineが見に行く"CRS Model Redis Parameter"。
こちらに格納されているデータが、「CRS Engineが扱いやすいように処理された」ものなんだそうです。

IntelliJ IDEAのSequenceDiagramプラグインが便利

この、SequenceDiagramプラグインで、
vanco.github.io

こんな感じのシーケンス図が描けます。
f:id:taichiw:20190301195001p:plain

素敵なのが、

  • 好きなメソッドから始められる
  • 深さが選べる

f:id:taichiw:20190301195116p:plain
点です。

コードレビュー時などに、深さ2でServiceクラスから始めると、私の好きな感じのコードになっているかどうかがよくわかります。
参考:持論:Application Layerがシンプルなコードは読みやすい - エンジニア的なネタを毎週書くブログ


以前は、こういったコードから自動生成された図は、ノイズが多くて使い物にならない…と思っていました。
けれども最近は、
「自動生成された図が汚い、ということはそもそもコードが悪いのでは?」
と思うようになってきました。

f:id:taichiw:20190301195934p:plain
例えばこれ。
右から左に呼び出しが伸びてるのが気持ち悪いです。
以前の私であれば、「この呼ばれているクラスを右に持っていければいいのに… ツールがイケていない!」と思っていたところでしたが、
そもそもこんな向きに呼び出しがかかる、元のコードが悪いのではないでしょうか。

こういう考え方になってきたのは、12月のJJUG CCでirofさんの「JIGを使った設計」を聞いたからなのかなぁ… と思います。

【極論ですけど】JavaでforEachを使ったら負けだと思う

正直使い所がわからないんですよね、forEach.
ログとかprintfとかする以外は…

コレクションを更新するな

未だに時々見るのがこういうコード。

List<X> list = new ArrayList<>();
適当なコレクション.forEach()
  .map(t -> list.add(t.getXXXX()));

これとっても良くない。

スレッドセーフでない

上記をあまり深く考えずにパラレルストリームにしちゃいますと

List<X> list = new ArrayList<>();
適当なコレクション.forEach().parallelStream()
  .map(x -> list.add(x.getXXXX()));

ArrayListに対する追加処理がスレッドセーフでないため、確率的に不具合が起きてしまいます。*1

パラレルにしなければいい…のですが、Project Lambdaの目的の一つがマルチコアへの対応なわけで、「parallelStreamを使って並列化できないものはラムダ式で書くな」くらいに私は思っています。(私の勝手ルールではありますが)

Lambdaで更新するの「関数」でない

Lambda式内では外で定義した変数に代入ができません。
これは、「状態」を極力排除することによって、バグの入り込む余地を減らすため… と私は認識しています。
ですが、上記のようにコレクションに対する操作や、Setterでの代入はJavaの言語仕様上できてしまいます。

…とはいえ、できるからやっていい、というものでもないと思います。

「リストを作る」と明確に書く方法がある

List<X> list = 適当なコレクション.stream() //parallelも可
  .map(X::getXXXX)
  .collect(Collector.toList());

そもそもこのように、リストを作るための書き方が用意されているのに、これを使わずに汎用的なforEachでなんとかする… というのは美しさに欠けます。

更新しないとなると、forEachは出力くらいしか使いみちがないのでは

上で書いたとおり、コンパイルエラーにはならない… とはいえ、Lambda式内で何かを「更新」するのは不適切と考えます。
そうなると、冒頭に書いたとおり、何かの出力くらいしか使いみちがないなぁ… ということになり、
よっぽどのことがない限り、「forEachを使ったら負け」だと思うのです。

*1:私が経験したことのある事象だと、「適当なコレクション」よりも多い要素がlistに追加されるという謎現象が発生し、その要素をgetするとnullが入ってる → ヌルポで落ちる というものを何度かみました。