OOC2024まとめ(オブジェクトモデリングとコアコンセプト・OOP DDDと関数型プログラミングなどなど)
話を聞きながらとか後で思い出してとかなのでスピーカーの皆さんと思ってることが違うとかあるかもですが一応自分のメモ&まとめ&所感です。
オブジェクトでつながるUXとシステム設計 by yumemi
デザイナーもやってる自分としては新しい何かを得ようと思ってないですが、この手のエンジニア領域のカンファレンスにしてはめずらしいデザイナー領域とも言えるものなのと、そういう発信をした人たちに関心があったので参加してみました。
内容
サービスコンセプトを考える際に共通言語を関係者で定義してコンセプトワークへ収束していくというワークショップでした。
ワークショップ
- ユーザストーリが各テーブルにあってお隣の方とペアに
- ユーザストーリから主語や目的語など単語を抽出し概念モデルの楚を定義
- 動詞を抽出し概念の関連を定義
- そこからコアコンセプトを考案しサービス名をつける
手順としてはこんな感じ。
自分たちは市民が町をお勧めしたいみたいなユーザストーリが振られていたのでそこからやっていき、
ユーザストーリにはウォンツしかなく、能動的にユーザがサービスを利用するところが想像できなかったのでサービス提供側を自治体と定義し、その自治体のニーズ(町おこし=[移住促進・関係人口促進などなど])を踏まえて、市民にインセンティブを渡すという方に持っていきました。で、町おこしからサービス名がOCOCYと。おや?グノシーみたいだなーと思ったけど遥か昔にグノシー社員だったってことは言う必要のないことなので伏せておきました…。
所感
ここで言うモデリングは設計や実装フェーズまで完全に関連するものではなく、コンセプトワークの際の共通言語という風合いでドメインモデリングとかって感じではなくもっと自由な発想をするための発散と収束過程における概念モデリングという感じでした。
この辺はサービスのジャストアイデアはあるがもう少しブレイクスルーしていきたいファウンダーとかとやると良いかと。大体のファウンダーはふんわりサービスアイデアしかないのでこの活動を基にPoCなどを経て具体的なサービスコンセプト・コアドメインなどを明確にするのには良い。というかこれ、デザインスプリントに近い感じです。
ちなみに、自分はサービスデザイナーとしてもやっているので簡単に言うとこんな感じでやる方がいいかなと思います。
サービスデザインと設計フロー
- 雑なビジネスアイデアからステイクホルダーを定義する
- ステイクホルダー(サービス提供者・サービス運営者・想定または現状のドメインの顧客)の相対的な活動をサービスブループリントで表現
- サービスブループリントでシステムが入る余地を見極める
- できる範囲でPoCを行う
- PoCの結果を踏まえて可能ならユーザ分析や業務フローの分析を行う(特にウィークポイントやペイン)
- それを元にシステムを入れたと仮定したサービスブループリントを作る
- 作りながらビジネスのコアコンセプトやコアドメインを明確にしていきつつ概念モデルを抽出してまとめていく
とまぁあんま書くと長くなるのでこんな感じ。まだここから要求分析・要件定義を経て設計と進めながらコアコンセプトやコアドメインの蒸留をはかる感じです。
ビジネスロジックを「型」で表現するOOPのための関数型DDD by Yuito Sato
個人開発でサーバサイドをDMMF(Domain Model Made Functional)で実装しているところだったので参加しました。て、参加して気づいたけど「OOPのため」なのでDMMFではないです。
内容
- OOPに関数型の要素を適度に取り入れ、とのこと型によるコンパイルエラーを検知できるようすることで堅牢化を図るとのこと。
- OOPでは似たようなことを継承でできるが、継承は継承の継承など影響範囲を限定したりなどが難しい
- 継承ではなく関数型プログラミングの全域関数 と 代数的データ型を使うことで実現する。
- TypeScriptで言うとUnion型
UnCompleted | Completed | CancelCompleted
- UnCompletedには
type = { status: 'uncompleted'; id: number; isEditable: boolean; }
でCompletedにはtype = { status: 'completed'; id: number; }
みたいに状態の範囲を定め、状態ごとのモデルを定義し、その状態ごとの型で実装時にエラーを検知できるようになる
- TypeScriptで言うとUnion型
- 継承ではなく関数型プログラミングの全域関数 と 代数的データ型を使うことで実現する。
- アーキテクチャとしては純粋関数のインスタンスをDIする。関数自体をDIするとインターフェースが崩れてしまう可能性がある。
- 尚、ドメイン層に対して隠蔽したいもの(ドメインの責務外の関心)を注入する。
- ドメインロジックに相当するものを隠蔽してしまうと、ドメインの責務が漏れていたり、漏れ隠れているのでその場合はドメイン層でやるべき。
全域関数とは
全域関数とは、定義域のすべての要素に対して値を持つ関数のことです。つまり、全域関数では、関数が定義されている範囲内の任意の入力に対して、出力が存在します。数学やプログラミングにおいて、関数が全域であるとは、その関数がすべての可能な入力に対して定義されていることを意味します。
代数的データ型
代数的データ型(Algebraic Data Types, ADT)は、複数の型の値を一つの型で表現できるデータ構造です。主に積の型(タプルやレコード)と和の型(バリアントやユニオン)の組み合わせで構成されます。これにより、コードの安全性と表現力が高まり、関数型言語を中心に多くのプログラミング言語で利用されています。
所感
テストや実行ではなく型でを究極にしていくような話。テストを書く前に問題を特定したり、そもそものドメインモデルのイレギュラーを型とその方に対する例外、状態に対して例外を限定するなどで明らかにし不正でいくのは確かにあると良さそう。特に開発規模やメンバーが増えるとメリットが比例して良くなりそう。
設計の知識と技能で駆動するソフトウェア開発 by 増田 亨
増田さんとは色々と勉強会で声かけていただいてご一緒させてもらっているので改めて増田さんの習熟・共創を経た知見のまとめを聞きたく参加しました。
内容
広い講義室が満席・立ち見状態で若干息苦しかったのもあってメモる余裕もなかったので詳しくはスライドを見てくださいと…。
所感
スライドを見ることで増田さんの設計や実装への取り組みが技術やシステムエンジニアリングを取り巻く環境などを経て変わったところ、変わらず重要なところを経験則として後に続くエンジニア達に共有しているという内容と自分は受け取りました。まさにスライドの最後にある習熟・共創を経ての経験則の共有をこの場でしていたという感じです。
あと、この枠ではなく懇親会の時に増田さんと話してたことですが、モジュライリティを高めていくことで関心の整理・分離を進めるわけですが、ポート&アダプタの外側にあるところに実はシステムとして提供することでステイクホルダーの事業活動や生産性を向上するきっかけになる情報が隠れていたりするのでそこをうまく捉える必要があると。
昨今のDXは実はこの視点がなく、単にアナログと言われるものをデジタルというかシステム化するかひどい場合はツールの導入をコンサルするかみたいになっているがそうではないと。
例えば何かシステムで集計するが実際の業務ではそのシステムが吐き出したCSVをエクセルにインポートして手でまとめて印刷してステイクホルダーに伝達するみたいなものがあった場合なんかがそれ。こういう要求にはないが実はビジネスプロセスで改善すると大きく事業に貢献できるものを提案してシステムにすることこそ真にDXな気がします。
ちなみに、こういう見えないビジネスプロセスを可視化して改善施策を発散するにはサービスブループリントがちょうど良いと思います。
サービスブループリントとは
関数型DDDの理論と実践: 「決定を遅らせる」を先につくり、ビジネスの機動力と価値をあげる by Kenichi SUZUKI
こちらも関数型プログラミングをOOPに部分的に採用する実践の話。2番目「ビジネスロジックを「型」で表現するOOPのための関数型DDD」の枠と同じ様な話でした。
内容
- 決定を遅らせるためにモジュラリティを高めたい、そのために関数型プログラミングのアプローチを採用する。
- ここで言う関数型とはで純粋関数や関数合成、全域関数であって部分関数にならないように注意する
- 品質上げていくには全域関数であるべき(部分関数だと破綻する可能性がある)
- この辺の話は2番目「ビジネスロジックを「型」で表現するOOPのための関数型DDD」でも出ていた話。
- 継続的アーキテクチャ
- 機能要件でなく品質属性にフォーカス
- 必要になるまで設計の決定を遅らせる
- 変化のために設計する(小さく作る・小さくまとめる・小さく検証するできるようにする)
- 副作用を減らす→純粋関数・全域関数であることでバグの温床を無くす
- 関数型では副作用(外部の状態を変更したり、外部の状態に依存したりする操作)を避け、純粋な関数を使用することを目指しても、UIやデータベースへのアクセスなど、副作用を伴う操作がある。その副作用を扱うための手法に「Effect Tracking」と「Effect Wrapper」がある。
Effect Trackingとは
Effect Trackingは、副作用のある関数を許容するが型シグネチャでそれを表現することで純粋な関数かどうか区別できるようにすること。HaskellのIO型やRustのResult型などは、この種のEffect Trackingを実現するために使われる。
Effect Wrapperとは
Effect Wrapperは、副作用を持つ値や操作を特定の型でラップし、値を操作するための純粋な関数を提供すること。Effect Wrapperは、副作用を持つ操作を遅延させるなどコントロールを可能にする。
- 副作用のコントロールの手法
- Tagkess-final: コンビネーターアプローチと高階多相を利用して型安全にDSLを表現する手法
- Free Monad: 計算の実行を遅延させることで副作用を持つ操作を純粋な値(ツリー構造)で表現
- ZIO(Scala)
- 例外
- 関数型のメリットとリスク
- メリット
- 副作用が分離できる
- 型安全にできる
- 業務システムなどエンタープライズ基幹システムなど課題・要求など明確になりそうなものと関数型と相性がいい
- 設計から実装までのシームレスにできるのでラグが少なく済む
- リスク
- 学習コストがあるし、チームオンボーディングなどコストが気になる
- 副作用のコントロールでテクニックを突き詰めていくと沼に入ることがある
- 純粋関数で実装していくとNullが気になるようになる
- メリット
- 型の堅牢性はドメインレイヤーには求めるがそれ以外は求めないでもいい
所感
話を聞いていて思ったのは、課題・要求が明確になりそうなものは関数型と相性が良い(副作用を分離したり、型安全が明確に定義しやすいなど)が、その逆に変異しやすいものは関数型の採用はちょっと様子みた方がいいかも。例えば事業ドメインではなくユーザメンタルモデルに寄り添うようなUIの部分など。
Discussion