sait0sのブログ

技術で広く浅く遊んでいる、エンジニアの真似事をしている学生です

複雑なトランザクションにおける排他制御

ここでは、トランザクションの中でも、複雑なトランザクションの実装技法について取り上げたいと思います。そのため、通常のマニュアルトランザクションや分離性の解説は省略してあります。

 

トランザクションの種類

 

対話型トランザクション

業務アプリケーションでは、何らかの対話型処理が含まれており、対話処理の前後に排他制御を要求するものがある。例えば、チケット発券システムである。

  1. 空きの座席一覧を表示
  2. 予約したい座席(座席sとする)を指定する
  3. お金を支払う
  4. チケットを 発券する

このようなシステムの場合、トランザクション制御を行わないと、2~4までの座席を確定してチケット発券までの間に座席sを他のトランザクションによる「後勝ち」が発生してしまう。

対話型トランザクションの対処法

  • 排他制御を行わず、運用でカバーする
  • 業務排他制御機能を作りこむ
  • 楽観同時実行制御を行う

排他制御を行わず、運用でカバーする

後勝ちが発生する要因としては、同時に複数のトランザクションが発生しうる状況だからである。そのため、チケット発券が一つの窓口でしか行えないようなサービスであればトランザクション制御の必要はない。ただし、これは現実的ではない。

業務排他制御機能を作りこむ

業務排他制御は、対話型トランザクションの最中にAP側が上手く排他制御を行って後勝ちを回避させる方法である。

座席ID 編集状態
s ユーザA
t なし

ユーザAが2~4のチケット発券の手続きの最中に他のユーザが座席sを予約しようとすると、AP側で検知して座席を保護することができる。実際には、この他にも編集中や予約済み、排他有効期間などの状態データを記録しなければならない。ただし、これにはデメリットもある。

  1. 障害が発生したときに原子性や一貫性が失われる可能性がある
  2. クライアントの操作やタイムアウトの取り扱い
  3. トランザクションの衝突確率が低い場合、コストが高くなる

①はチケットの発券途中で何かしらの障害が発生したときに、チケットの発券が正常に行われずに終了したときに状態フラグは編集中のままで復旧されてしまう。この場合、チケットが発券されていないにもかかわらず編集中になっているため、原子性や一貫性に違反している。そうならないためには、障害発生時に状態フラグを修正するようなリカバリ手続きを業務側で作りこまなければならない。これは、業務排他機能が複雑になるほどリカバリも複雑になる。

②はブラウザを誤って終了させたときやチケット発券までのタイムアウトになった時に状態フラグを元に戻さなければならない。座席予約システムのような即売を必要とするタイプの商品の場合、すぐに再度販売をかけることが望ましい。そのための制御を業務側で作る必要が出てくる。また、むやみに制御を行うとクライアントにとって使い勝手の悪いアプリケーションになってしまう可能性もあるため注意しなければならない。

最後、③はトランザクション量が少なく、衝突はめったに起こらないようなシステムの場合にはコストに見合わなくなってしまう。

楽観同時実行制御を行う

トランザクション量が少なく、衝突確率も低いようなシステムかつ「後勝ち」だけは避けたいというような場合に用いられる。楽観同時実行制御は、実際にデータが更新されるタイミングで、他のユーザによる更新が行われたか確認される。

座席ID 予約フラグ 最終更新
s FALSE 20240101T10:00:00.000
t TRUE 20231231T09:30:00.000
UPDATE sheet
SET reserve_flag = TRUE
WHERE id = s AND reserve_flag = FALSE AND last_update_at = 20240101T10:00:00.000;

 更新時に更新前の値と照合するようなバージョン管理をすることで、後勝ちを検出して回避することができる。ただし、後勝ちの検出精度を高めるには、更新クエリのWHERE句に一意なIDとtimestampのようなバージョンを指定する必要がある。ただし、楽観同時実行制御は、JDBCや.NETなどのフレームワークやライブラリによっては自動でサポートするものもあるため、複雑になりにくく、実装が容易である。一方でデメリットもある。

  1. トランザクション量が多い場合、衝突が頻発してスループットやユーザ体験が悪くなる

業務排他トランザクションと比べて、レコードを更新するまでバージョンが正しいかわからず、トランザクション量が多いと全てブロックされてしまう。また、レコードの編集中でも該当レコードを取得できてしまう問題もある。

 

バッチ型トランザクション

まず初めに、今までのトランザクション指向処理とバッチ処理の違いについてまとめる。

  トランザクション指向処理 バッチ処理
実施タイミング ユーザ要求から即時 日次、月次など
時間帯 日中のオンラインの時間帯 夜間などのオフラインの時間帯
一度に取り扱うデータ 少量 大量
同時に並行実行される処理の数 多数 小数
一貫性の保証 トランザクション制御によりACID性を保証 特に行わず、リランなどにより対処

 

オフラインバッチ

オフラインバッチでは、バッチ処理がデータベースを占有するため物理的な排他制御が不要になる。そして、バッチ開始時点からトランザクションをかければエラー発生時でもロールバックするだけでよい。ただし、注意点がある。

  1. 膨大なデータを扱うバッチ処理ではアボートは使えない
  2. オンライン時間までにバッチ処理が終了するように見積もらなければならない

①は処理の開始時点でバックアップをとっておき、エラー発生時にはリストアすることで対応する。また、チェックポイントやミニバッチ、頻繁なコミットなどの方法もある。

②はオンライン時間帯に間に合うように十分なリラン時間を確保しておく必要がある。バッチ処理では対象データを1件ずつ順番に処理していくため、データ量によって要する時間が大きく異なる。処理時間を十分に確保できない場合は、バッチ処理を何かしらの条件で分類して並列実行させる。

オンラインバッチ

そもそもオフライン時間帯がないシステムも多く、オフラインバッチと同じ考え方で実装できないこともある。そこで、業務の重要性や求められる即時性などからいくつかのサブシステムやDWHを作り、日時や週次単位でデータを複製する。分析業務や印刷業務であれば複製で問題ないが、オリジナルのデータを用いて行わなければならないときもある。その場合、バッチ処理が長時間データをブロックしないように設計しなければならない。

  1. 一括処理への修正
  2. ミニバッチ
  3. サーガ

一括処理への修正

具体的には、一括した更新を行うことでラウンドトリップ回数を少なくすることができる。

/* レコード指向処理 */
SELECT price FROM item WHERE id = '1';
UPDATE item SET price = 2000 WHERE id = '1';
        :

/* 一括処理 */
UPDATE item SET price = price + 1;

ただし、業務ロジックが比較的単純であり、他のトランザクションによるデータの矛盾とブロッキングが起こらない場合に限る。特に、一括更新する場合は、SQLクエリやデータベースによってはロック粒度が大きくなる可能性がある。

ミニバッチ

データ件数が多い場合には、バッチ処理を細分化して逐次実行していく必要がある。仮にデータ更新中にシステムがクラッシュしても、進捗管理テーブルを基にリスタートできる。

/* ミニバッチで10件ずつ更新 */
SELECT price FROM item WHERE id BETWEEN '1' AND '10';
        (更新処理)
SELECT price FROM item WHERE id BETWEEN '11' AND '20';
        (更新処理)
           :

しかし、以下のような注意点もある。

  • バッチ処理の対象データの隔離性が保証されないため、バッチ処理時に他のトランザクションによってデータが更新されている可能性がある
  • パフォーマンスやスケジュールの観点からミニバッチサイズのチューニングや設計を考慮しなければならない
  • システム障害時にバッチ処理が必ず完了する保証はなく、既にコミットしたものはロールバックできない

サーガ

ミニバッチによって一方的に進められた処理は、何かしらのエラーが発生したときのロールバックを想定していない。ロールバックの際には、補償トランザクションによって解決する。ただし、補償トランザクションは自力で実装しなければならず、ミニバッチ処理の設計に大きく依存する。加えて、補償トランザクション中に起きたトラブルや進捗管理に関する設計も考慮しなければならない。

 

キュー型トランザクション

キュー型トランザクションモデルでは、クライアントとサーバ間に永続性を持つリクエストキューやレスポンスキューを挟み込んで一連の処理を行う。そのため、キューを永続化させるために永続ストレージ上に構築し、アプリケーションプロセスに障害が起きても処理データを生き残らせる。以下の手順で行われる。

  1. クライアントのリクエストキューの処理内容を一旦書き込み、コミットさせる
  2. サーバ側で定期的にリクエストキューを取り出して処理し、レスポンスキューへ書き込む
  3. クライアントは定期的にレスポンスキューを確認し、該当のキューがあれば結果を表示させるなどの処理を行う

これにより、各種システム障害に対する耐性やトランザクション内の一部処理の切り離しによって処理効率の向上が期待できる。また、キューからのメッセージの取り出しを工夫することで、優先制御や流量制御などのスケジューリングも可能になる。一方で、以下のようなデメリットもある。

  • キュー型トランザクションモデルを取れる業務は少ない
  • 平常時の処理速度や処理結果の受け取り遅延に配慮する必要がある
  • 明示的なキュー操作が必要になるため、設計が複雑になりやすい

キュー型トランザクションはリアルタイムで結果を受け取ることができず、対話的な性格の強い業務アプリケーションでは頻繁に直接型トランザクションによるサーバ呼び出しが発生することになる。そして、単純な読み書き処理ではほとんどメリットがない。

キュー型トランザクションでの設計課題

キュー型トランザクションモデルの課題としては以下のものがある。

  1. 効率的に動作するリスナーアプリケーションの設計
  2. バックエンドサービス障害時のリトライ制御
  3. 処理順序逆転に対するアプリケーション設計の工夫
  4. ポイズンメッセージ対策
  5. サーバ側の非同期処理の確認・受け取り方法
  6. メッセージキューの障害時のリカバリやセキュリティ

① リスナーアプリケーション*1は、マルチプロセスまたはマルチスレッドで動作させなければならないことが多く、キューのポーリング間隔や負荷、リスナーアプリケーションそのものの多重制御や監視も考慮しなければならない

② 外部のバックエンドサービスが停止していた場合、リスナーアプリケーションの処理は必ず失敗するため、キューを書き戻して処理を再試行しなければならない。しかし、失敗直後にリトライしても再び失敗する可能性が高いため、ある程度時間間隔を置きながらリトライを行う必要がある。

③ 一般的にキューはFIFOで動作する。しかし、リスナーアプリケーションはマルチスレッドやマルチプロセスで動作するためキュー型トランザクションは必ずしも完全なFIFOにならないことが多い。そのため、キューの格納順序や実行順序が変わっても不具合が起こらないようにしなければならない。

④ 仮にクライアントが投入したキューそのものに誤りがあったとする。リスナーアプリケーションでエラーが発生して何度もリトライされるが、決して成功しない。このようなポイズンメッセージを検知することは難しいため、ある一定回数リトライしても成功しないときはそれ以上再試行しないなどの工夫が必要である。

⑤ クライアントがレスポンスキューを適宜確認すれば簡単ではあるが、リスナーアプリケーションの処理が終了したことをクライアントに通知しなければならないときが問題になる。

⑥ 障害発生時のリカバリやセキュリティが手薄になることが多いが、無視してはならないポイントでもある。リカバリに関しては、クラッシュしたことて処理するべきデータが不明となってしまったときはデータベースに記録された内容から復元することで対応できる。セキュリティに関しても、インフラ設計の工夫で改善できることも多い。

 

トランザクションの冪等性と再試行

複雑な短時間トランザクションを上手く設計するうえで重要なことが「冪等性」と「再試行」である。例えば、注文受付完了のメール配信処理を考えてみる。メール配信時に何かしらのエラーが発生したときは念のため再試行されるが、再試行によって重複してメールが届いてしまう可能性がある。それは冪等性ではない。ある処理をn回繰り返しても実質的に同じ1回行ったことになければならない。そのため、まず先方で処理が正しく行われたか確認してから再試行する必要がある。

*1:リクエストキューのデータを取り出して処理を行うアプリケーション

2023年の振り返る

 12月の初旬の暖冬は一気に過ぎ去り、寒さと感想がより強くなりました。今年も残すところわずかということで、2023年を振り返ろうかなと思う。

 

やったこと

この1年は本当に大変な時期だった。大きくこんな感じである。

 

就活

 これね、一番大変だったし、つらかった。ただ、やりたいこととか、やっていかないといけないことが明確になった気がする。今振り返ると、打ちのめされる経験をしたのはよかったのかもしれない。

 

 これと言って語ることはないが、あえて言うならエンジニアに面接を担当させるならトレーニングするべきだと思う。面接で技術の話しかしない、意図の見えない質問をするなど酷いなと思う面接は多かった。何よりも一番許せなかったことは、質問に対して自分が答えているときに面接官がクスクス笑っていたことがある。こういうことは、体験者側はずっと覚えているものだと思う。このようでは、優秀な人材なんて見極められないし、何より会社のイメージダウンにつながるため、絶対にやめた方が良いと思う。

 

インターン

 夏に2週間ほどインターン行ってきた。一年前と比べると、大きく成長したなと実感できた。技術面でも、非技術面でも、、、 就活やインターンを通して、自分に足りないこと、これからやりたいことが明確になった。

単位を必死でとる

 B3は就活とインターンが忙しくなるということはわかっていたので、単位を抑えめにしたた。そしたら、B4の春が単位に追われるという事態が発生した。(なんとか頑張って単位を取った)

 

卒業研究

 本当に研究が忙しかった。しかし、文章を書くという経験はすごく良かった。自分の文章に磨きがかかった気がする。技術書籍とかいつか書いてみたいと思った。

 

近況

 結局、研究が終わらなかった。クリスマスだけでなく、年末年始も研究やってます。あとは、DB入門しました。「トランザクション処理  概念と技法」を読んでいる。DBMSに詳しい人が少ないということ、今まで以上にDBはインフラよりもアプリケーション側の方が親和性が高くなっている(気がする)ことから、インフラよりもDBスキルの方を強化していきたい。

 

来年の抱負

  • アーキテクトになるためのスキルを磨く
  • 技術アウトプットを強化する
  • 何かしらの技術カンファレンスで登壇する
  • 自分にできること全部やる

 

 こんな感じですかね。具体的なプランは決まってない部分が多いが、やりたいことや自分にできることはわかっているので、あとはいかにアクションとバリューを出せるかだと思う。

 来年から社会人になる。今まで以上に頑張らないといけない。だからこそ、楽しみでもあるし、やれること全部やっていきたい。(全て達成していくつもり)

 

 来年は、もう少し充実した振り返りで終わりたい。

 

「エリック・エヴァンスのドメイン駆動設計」を読んだ

 最近、物騒な時代になったなぁと感じます。何か暗いニュースばかりで気分も落ち込みますね。そんなわけで、何かと定期的に炎上するドメイン駆動設計(以下DDD)を読んだので感想とか書いていこうと思います。

対象読者

 UMLとかオブジェクト指向設計は読める、ある程度理解していることが前提になっているので、わからなかったら以下の書籍を読むと良いと思う。UMLオブジェクト指向設計デザインパターンがわかりやすく解説されている。あとは、クリーンアーキテクチャアジャイルプロセスに近いところがあるので、それらを理解しているとより理解しやすいかもしれない。

 

あらすじというか概要

第1部 (1~2章) ドメインモデルを機能させる

1章 知識をかみ砕く

 ドメインの理解者であるビジネスエキスパートとシステムを設計するアーキテクトは、会話を途絶えさせないことが書いてある。綿密にコミュニケーションをして、知識や概念の齟齬がないように努める必要があるとされる。これらの付帯的な方法は、2章へ続いている。

 

2章 コミュニケーションと言語の使い方

 設計、モデリングをする際には、ビジネスエキスパートとアーキテクト間で共通言語を用いることとされる。それが、統一モデリング言語(UML)である。ビジネスエキスパートチームと開発チームで概念が異なる危険性について述べている。例えば、ビジネスエキスパートチームのXXという概念は、開発チームでは△△となっているようなシステムがある場合、翻訳コストだけでなく、ビジネスエキスパートやプログラマーを混乱させる。そうならないために、UMLを用いる。これを貨物輸送システムを例に挙げて説明している。アーキテクトは、ビジネスエキスパートと共にUMLを用いてシステムの設計をしていく。ビジネスエキスパートは理解しているがアーキテクトにわからないこと、アーキテクトは理解しているがビジネスエキスパートにわからないことをお互いに明確にし合う。そこで、システムの隠れた本質を見出していこうとすることが大事である。

 

3章 モデリングと実装を結びつける

 ドメインを基に設計したモノを明示化するのは難しい。そこで、ドメインとモデルを必ず一致させることが重要である。モデリングの際に、UMLを用いてドメインとモデルを一致させるように落とし込む。そうすることで、オブジェクトの責務を明確にし、SOLID原則を順守させる。

 

第2部 (3~7章) モデル駆動設計の構成要素

4章 ドメインを隔離する

 システム開発とはいえ、ユーザからのリクエストを受け取る、DBにアクセスする、レスポンスをユーザへ返すといった単なるデータ処理以外の複雑な処理も実装しなければならない。その解決策として、オブジェクトの責務レイヤー化アーキテクチャを例に挙げている。MVCのようなアーキテクチャフレームワークを用いることで複雑な実装を分割し、開発者はドメインの実装に集中できるという考え方である。凝集度を高めることで、システムとそれ以外を疎結合する。ただし、インフラ層やUI層に悪影響を与える問題もあるが、この後の章に続く。

 

5章 ソフトウェアで表現されたモデル

 モデルをオブジェクトに表現するには、エンティティ(Entity)値オブジェクト(Value Object)サービス(Service)に分けられる。

 Entityの重要なコアは、同一性にある。とあるサービスに登録したBob(男)がいたとすると、Bob(男)という同姓同名はニューヨークにもいるかもしれないし、カルフォルニアにもいるかもしれない。そこで、確実に区別するために顧客IDを用いて識別する。このような、識別IDは外部のモデルと一意になるように識別することもできるし、内部のモデルを区別することもできる。ただし、Entityはimmutableで一意性を担保していく必要がある。

 Value Objectの重要な点は、バリエーションにある。顧客は、ニューヨークに住んでいるかもしれないし、カルフォルニアにも住んでいるかもしれない。しかし、ニューヨークに住んでいる人は1人だけではない。そこで、Entityと一意になるようにモデリングすることでバリエーションを表現できる。Value ObjectはEntityと同様にimmutableである必要がある。

 Serviceは、EntityやValue Objectで表現できないドメインを引き継ぐ。全てのドメインをモデルに押し付けると膨大な責務を持った不自然なオブジェクトが生まれる。ただし、Serviceは独立したインターフェースになるようにUMLの一部となること、状態(Field)を持たせないことが重要である。

 また、パッケージングとモジュールにも注意する。J2EEでは、ビジネスロジックはSession Bean、データアクセスはEntity Beanに集約される。別々のパッケージで構成させるため、コンポーネントが一緒になり実装と関連性を理解することが難しくなる。そこで、フレームワークに依存しない、独立したビジネスモデルを定義することが重要である。ただし、ユビキタスは指針にすること。

 

6章 ドメインオブジェクトのライフサイクル

 複雑なモデルでは、オブジェクトの一貫性を保つことは難しい。ただし、過度なロックを強制すると、相互に干渉し合い、別の問題が発生する。その一例として、DBMSにおけるデッドロックなどがある。そうならないようにするためには、ファクトリ(Factory)リポジトリ(Repository)を用いて集約させる。

 Factoryは、オブジェクトのライフサイクルの過程には複雑な責務が発生するため、クライアントの要求するオブジェクトの生成責務を担うオブジェクトとして用いる。そのため、Factoryはインターフェースを提供することで、クライアントには生成過程のルールや責務を隠蔽できる。ただし、インターフェースの実装については引数や操作は柔軟性が必要である。カタログ商品システムを例に、購入注文と商品のモデルは依存関係がある(購入注文は商品を集約している)。具象クラスではなく、抽象クラスを利用することで依存関係と結合を解消することができる。また、一般的にFactoryは、Entityの条件に一致するものはEntityを、Value Objectに一致するものはValue Objectを生成するが、その使い分けは次のRepositoryへ続く。

 Repositoryは、あらゆるオブジェクトへのアクセスを制限し、オブジェクトが保存されているDBへのアクセスに用いる。Repositoryは、永続化されたオブジェクトを追加・削除するメソッド、属性値の条件に一致するオブジェクトを戻り値として提供することが求められる。ただし、集約ルートから辿れるオブジェクト(Entity)に限定するべきだが、サブセットに複雑なValue Objectoが含まれることもある。その場合は、特定の型として集約させることで対応するまた、Factoryと同様に抽象化させることでアクティブにする。

 

7章 言語を使用する:応用例

 今まで述べてきたことを考慮して、貨物輸送サービスを例にモデリング例を提示している。ここで、重要になるのがルートEntityの抽出である。リレーションされたサブセットを含むモデルを抽出することで、集約されたモデルの境界を引くことができる。

 その一例が荷役イベントである。今までは、予約アプリケーション*1は貨物の予約状況を確認する貨物リポジトリと貨物の予約ができる販売管理システムが両立していたが、同じような責務が混在していた。貨物リポジトリにはquantityBooked(予約状況)、販売管理システムを隠蔽させた配分チェックサービスにderiveEnterpriseSegment(予約したい貨物タイプが適合)とmayAccept(予約済みか判定)で分割することでモデルを維持しつつ、責務を明確に分けたアプリケーションが完成する。

 

第3部 (8~13章) より深い洞察へ向かうリファクタリング

8章 ブレイクスルー

 継続的なリファクタリングは、ときに責務が不明瞭となるブレイクスルーを引き起こす。その例を貸金システムで説明する。

 出資額の上限を規定するファシリティと実際の出資を規定するローンという概念がある。ファシリティの割合によって手数料が決定され、ローンの割合で配当金の受け取り額が変わる。このファシリティとローンはそれぞれ割合が独立して変わる可能性があるときのモデルを考えなければならない。

 

9章 暗黙的な概念を明示的にする

 ドメインの重要な概念を見落としていないか、アーキテクト*2は注意深く議論に耳を傾けなければならない。商業融資アプリケーションを例に利息と手数料に注目する。アーキテクトは利息と手数料の認識を誤解しており、設計していた。そのため、重複した概念や設計になっていたことに気づく。そこで、利息計算における発生主義会計の概念を基に、利息と手数料を完全に分離したリファクタリングができた。ここで重要なことは、概念が明確になるまで何度もモデリングし直すことである。

 一方で、それほど明示的でない概念も存在する。それが制約である。貨物輸送システムを例にすると、貨物予約の際には「貨物の種類ごとに可能な利用しなければならないコンテナの選択」や「優先予約可能貨物の存在」などの制約、いわゆるブッキングポリシーが存在する。ここで、Specificationという概念を用いることで解決していく。このようなビジネスルールは明らかにEntityやValue Objectの責務とは一致しない。そこで、制約の仕様を満たしているか判定するValue Objectを定義する。

class AAASpecification {

boolean isSatisfied(Entity entity) {
return true;
}
}

class BBBSpecification {

boolean isSatisfied(Entity entity) {
return true;
}
}

 こうすることで、ドメイン層から分離させず、EntityやValue Objectの責務から独立したビジネスルールを定義できる。

 

10章 しなやかな設計

 開発者があるコンポーネントを利用するためには、その実装を注視して利用しなければならないときはカプセル化の意義が失われる。そうならないようにするために、クラス操作には効果と目的が明確になる命名して、開発者がすぐに意味を推測できるようにしなければならない。インターフェースの実装を見なければならないようでは、抽象化の効用は限定されてしまう。

 また、どんなに上手く抽象化してもインターフェースが機能別で重複することもある。その場合には、闇雲にクラスやメソッドで分割するのではなく、ドメインや設計に一貫性を持たせて、意図の明確なインターフェースを保つようにすることが重要である。その際に、一つのクラスに対する責務が大きすぎるときは独立したクラスを定義することも検討しなければならない。そして、それらはたいていはプリミティブなものにならないことが多いため、戻り値と引数が同じ型にできる場合はそうするなど依存関係を最小限に留めるようなインターフェースを提供させる。

 一方で、今までの例に挙げた貨物などの用語が関連した他の概念に含まれているかもしれない。その場合は、型レベルで抽象化して宣言的な設計にさせる。

interface Specification {

boolean isSatisfied(Entity entity);
}

class AAASpecification implements Specification {

boolean isSatisfied(Entity entity) {
return true;
}
}

 この他にも、ANDやORといった複雑な仕様や複数の仕様を縫合するような新たな仕様・ビジネスルールを定義することができる。

 

11章 アナリシスパターンを適用する

 ある一定の概念を追跡して重要だと思っていたが、実は本質ではないことがある。その例が、会計アプリケーションにおける勘定科目である。会計において、複式簿記という概念を用いて貸方と借方が一致するようにシステムを設計する。そのため、勘定科目に仕訳記帳を包括することで仕訳記録のすべてを保持し、貸方と借方で対応させようとしていた。しかし、手数料における発生主義という概念を用いることで、勘定科目、仕訳基調、会計取引の重複した概念が取り除かれて洗礼されたモデルになる。

 

12章 デザインパターンをモデルに関係づける

 今まではモデル駆動設計を用いてモデルの問題を解決していたが、デザインパターンを用いることでも解決することができる。StrategyパターンとComposite パターンを用いて説明する*3

 

13章 より深い洞察へ向かうリファクタリング

 問題点を発見することは最も困難であり不確実性も多い。同僚やドメインエキスパートとブレインストーミングすることやアナリシスパターンデザインパターンなどの知識を活用することもできる。モデルを煮詰めることに注力せず、自由な意思決定、スコープと休憩、ユビキタス言語を駆使することで解決策が見いだせることもある。

 また、開発者にドメインの理解が足りていない、設計がよりしなやかになる方法があるなど変更が妥当でない場合は、完全に正当化できるまで待つということも考える。さらに、モデルが突然違うモデルへと代わることもあり得る。このようなブレイクスルーは毎日起こるようなものではないが、そこから新たな好機が生まれることもある。

 

第4部 (14~17章) 戦略的設計

14章 モデルの整合性を維持する

 とあるモデルを用いようとしたら、別のチームで既に使用されていた。2つのチームで異なるモデルを持ちながら、それを認識していないことがあると思いがけない事態を招くかもしれない。

 そこで、境界づけられたコンテキストを用いる。このコンテキストの境界は、チーム編成やアプリケーションの用途、データベーススキーマなどの物理的な観点からモデルの適用範囲を明示的に定義することで、外部からの問題に注意をそらされたり、混乱させることを避ける。ただし、チームが大きく、コンテキストが細かくなるほどモデルが分裂して一貫性を保持することが難しくなる。そこで、モデル同士をユビキタス言語に付け加えることで、コンテキストの境界、議論を明示化することができる。

 その他にも、上流と下流、システム間のモデルに順応させやすくする必要がある。上流と下流で密なコミュニケーションとユビキタス言語を用いた共有によって協力関係を築くこと、2つのシステム間でモデルの関連付けが難しい場合は片方のシステムに寄せるのではなく、腐敗防止層というモデル変換の責務を持たせたインターフェースを用いることも検討するべきである。

 

15章 蒸留

 複雑に混ざり合ったドメインを分離し、知識をモデルに一致させるために蒸留を行う。

 まずは、ドメインモデルの本質であるコアドメインを明確にする必要がある。複雑なシステムや変更が難しいシステムは認識していない重複や誤解が発生する可能性が高く、ビジネスの本質が不明瞭となり道に迷う。そうならないために、大量のモデルからコアドメインを見つけて最も価値のあるものにしなければならない。その際に、コアはできる限り小さくし、コア以外のモデルがコアドメインに与える影響を最小限に抑える。この作業は、長期にわたって参加しているドメインに詳しい開発者とドメインエキスパートに任せる。コアドメインをコントロールするには安定したチームが必要である。

 次に、コアドメインとは直接関係ない要素をサブドメインとして定義する。その際に、高凝集なサブドメインになるようにしなければならない。ドメインの知識とは全く関係ないようなサブドメインに関しては、汎用サブドメインとして外部ライブラリやフレームワーク等に責務を委譲する。

 さらには、モデルの中にはコアとしてだけでなく、サブドメインとしても役割を果たす要素もある。それを隔離されたコアとして分離することでコアの凝集度を高めつつ他のドメインとの結合度を低くする。

 また、コアドメインでさえ多くの詳細を扱っており、サブドメイン間で相互作用があるとモジュール間で多数の参照が発生して分割した意味がなくなる危険性がある。そこで、モデルにおける根本的な概念を抽象クラスやインターフェースに括りだした抽象ドメインを定義する。

 

16章 大規模な構造

 モデルを適切な大きさにモジュール分解しても、巨大なシステムに包括的な原則がないせいで設計全体にどのような役割を果たすか見分けられなくなる。そこで、役割や関係性でパターンを考え出す必要がある。

  • 厳格なルールが支配する設計はモデルに不自然な制約を強いることになるため、大規模なシステムはアプリケーションと共に進化させる
  • 抽象化し過ぎた設計は把握しにくくなるため、そのメタファの中にユビキタス言語を用いてコミュニケーションを行う
  • モデルの依存関係を常に把握し、各モデルとその責務が1つのレイヤに納める
  • 抽象化されたコアを蒸留して、そのインターフェースに様々な実装を置換できるようなフレームワークを作る

このように状況に応じてふさわしいリファクタリングを行う。

 

17章 戦略をまとめ上げる

 今までのプロセスを実行するためには戦略的な設計が必要不可欠となる。

 最初に、戦略的設計の前に、現在の状況を評価する必要がある。

  • コンテキストマップを書く
  • 言語の使われ方、ユビキタス言語でのコミュニケーション
  • コアドメインは識別されているか
  • 使用技術はモデル駆動設計に向いているか
  • チームの開発者は必要な技術スキルを保持しているか
  • 開発者はドメインに関心を持っているか

 アーキテクチャはプロジェクトを通して有機的に成長する。大規模な構造を監督する責任を小さなチームにグループに持たせると構造を維持しやすくなる。そのため、戦略的設計における意思決定を行う才能のある人が少なくともチームに数人はいなければならない。一方で、綿密に強調しているチームが非公式で議論を進め始めることにも注意しなければならない。一方で、意思決定がチームで共有されている場合、何らかの意思決定を中央集権化することが合理的だと判断することがある。ただし、それによってアプリケーションチームの意思決定を妨げないようにする必要がある。

 最後に、評価後の意思決定で以下のことに注意する。

  • 意思決定はチーム全体に伝えなければならない
  • 意思決定プロセスはフィードバックを吸収しなければならない
  • 計画は進化を許容しなければならない
  • アーキテクチャチームが、最も優秀な人材を吸い上げてはならない
  • 戦略的設計にはミニマリズムと謙虚さが必要である
  • オブジェクトはスペシャリストだが、開発者はジェネラリストである
  • 素人にもわかるフレームワークを使用してはならない
  • スタプランに注意すること

 

感想

 読んでみて雑に感想でも書き連ねてみる。

 

ここは同意できる

・エキスパートと開発者で概念を一致させる

 これは、当たり前な気がする。というか、要件定義でこれをやらない人っているんですかね。ビジネスドメインに寄せていくことで設計や実装の本質だと思うし、新たなビジネスを行う際に考慮しなければならない事項が減る。円滑なコミュニケーションを行うためにも、アーキテクトは常にコミュニケーションを図って齟齬をなくす、ドメインをうまくシステムに落とし込むことが重要である。これができない組織は崩壊一直線だと思う。

 

ここは難しい

ドメインモデリングを中心とする設計

 おそらく、ここがDDD vs 非DDDにおける最大の議論の火種だと思う。自分は、どちらかというと非DDD寄りであり、設計はUIやデータに依存すると思っている。まず、ビジネスドメインから設計を考えるということは、顧客が求めるUI(データ)よりもビジネスで必要となるであろうモデル(データ)を定義することを意味している。顧客にとっては、法律だろうが、システム上の制約だろうが関係ない。そんなめんどくさいことを考えずに利用できることの方が重要である。そもそも、UIやデータに依存しない設計なんてできるのだろうか。結局、顧客からのFBでUIやデータを修正しないといけなくなる気もするが、、、 ただ、優先順位の話をどうこうって言いたいわけではなく、顧客(クライアント)の欲しいUI、データが大きくモジュール戦略や設計に関わってくるよねということが言いたい。

 6章や7章においても、集約クラス(Factory, Repository)のパラメータは依存関係にあるため、具象クラスとして結合させる必要はなく、抽象クラスを利用するという考えも不可解に思える。オブジェクトの責務を分割するとは言っても、単にRepositoryなりFactory内でのモデル変換用のモデルを作成しただけな気もする。これが責務の分割と言われても納得できない。

 

 それ以前に許せないのが、矛盾した内容が多いことである。今まで散々、「モデルを定義してオブジェクトと一致させることが重要」、「ユビキタス言語を用いてモデリングと相互理解を深めること」などと散々述べていたのにもかかわらず、「UMLにはこだわらないこと*4としれっと付け加えられている。

早々と落ちが見えてきてしまった感がある、、、

 

・集約の軸としてEntityを定義し、Value Objectはサブセットとして利用する

 DBのテーブル設計で集約したEntity(広義の意味)に他のEntity(広義の意味)がリレーションしていることがよくある。その際に、集約ルートをEntity、その集約に内包された値をValue Objectに定義することが疑問である。コードに表すとこうである。

class OrderEntity {
int id;
ItemVo itemVo;
}

class ItemVo {
int id;
String name;
}

 著書にも書いてあるが、パフォーマンスとのトレードオフである。ここまでしなくても、ベースとなるEntityと判別できるような形で新しいEntityを作成すれば良いかなと思う。

 最近、JavaのORMであるJPAに@OneToManyと@ManyToOneというものが追加されたが、はたして使っている人はいるのだろうか、、、

 

・Frameworkに関して懐疑的な視点を持っている

 2000年代に考察されたものだからか、J2EEなどのWebフレームワークに懐疑的な視点を持っている。確かに、当時のJava界隈は不安定でフレームワークやライブラリ戦略に苦しめられたかもしれない。しかし、今となっては、フレームワークは互換性やレガシー化、エコシステム化を意識して開発されている(はず)。現代において、この考えはもう古い。フレームワークが使い方や実装を強制して、モデル分割やオブジェクトの責務を考慮しなくても良いようになっている。ただし、著者はフレームワークを直接的に否定しているわけではない。あくまで「フレームワークによってモデル分割が不可解なものになっては意味がない」程度にとどめている。そこを敢えてフレームワークに依存しないと誤認してしまう人もいるのではないかとも思って付け加えた。

 

・ビジネスルールをビジネスロジックから分離させる

 自分は、ビジネスロジックの中にビジネスルールを定義するべきだと感じている。DDDにおけるドメイン層がどの範囲までなのかはわからないが、ビジネスルールを独立させること自体は危険に感じる。再利用可能性は高まるかもしれないが、権限や機能ごとにビジネスルールが異なると意味がないものになってしまうし、ビジネスルールなValue Objectが量産されかねない気がする。

 例えば、ルールA, B, C, D, E... とあり、△△の条件ならAとBとCを、XXの条件ならAとDとEを... みたいな条件によって適用されるルールが異なるのであれば有効だとは思うし、それなら自分もそうする。ただ、弊社のシニアアーキテクトにも聞いたが、「そんな複雑なビジネスルールが存在するシステムはないし、UX視点からも良くないでしょ」と一蹴されてしまった、、、

 

・コアドメインへの定義

 コアドメインを明確に定義は理想的ではあるが、実際にはかなり難しいと思う。抽象ドメインという選択肢が残されているようにどうやっても多くのドメイン知識を持つ汎用コアドメインになりかねない気がする。それほどドメインを定義することは難しい。また、コアドメインを蒸留したとしても、ビジネスの変化が激しければコアドメインに変更が絶対的に起こらないとは限らないはずである。どちらにしても、解決策がリファクタリングモデリングし直すしかなく、リファクタリングのためのリファクタリングと現実的な解決策ではない。また、コアドメインへの蒸留に関しても、長期にわたって参加しているドメインに詳しい開発者を中心にすることも良くない気がする。DDDの文化を培ってきたのであれば可能かもしれないが、基本的にモデリングや設計に携わったことがない人に任せるのはかなりの勇気のいる選択だと思う。さらに、安定したチームであることが前提であり、その人が転職せずに残っているとは限らない、、、(属人的でもある)

 

それ以外で

・DDDは逆コンウェイドメインに理解がないのはコンウェイだから

 このような意見ってどこから来たんでしょう。開発者にもドメインに関心を持たせる、採用でスクリーニングするとは書かれていたけど、コンウェイや逆コンウェイは全く書かれていない。14章の最初だけを読むと、逆コンウェイ戦略をとっているようにみえるが、14~15章を通して読んでみると、あくまでモデルを維持するためであって、アーキテクチャや設計のための組織を作ると伝えているわけではないと感じた。その結果の副作用が、逆コンウェイ戦略ということだと思う。

 あとは、コンウェイだろうが、逆コンウェイだろうがドメインに理解がないと設計すらできないと思うが、、、

 それ以上に、まさに外部因子を排除して、その組織(コンテキスト)内で完結するようなコンテキストの境界を定義する*5と書かれている時点で、かなりの違和感を感じた。「外部とのコミュニケーションを諦めて、Closedな組織にしましょう!」と言っているようなものである。自分は同意できない。

 言わずと知れた名著である「イノベーションのジレンマ」にて、コンピュータ業界におけるイノベーションの失敗について以下のように書かれている。

たいてい製品開発組織は部品ごとにサブグループごとに分かれているため、企業の組織構造は、部品レベルのイノベーションを促すことが多いとされている。製品の基本的なアーキテクチャーを変更する必要がなければ、このようなシステムは効果的である。しかし、アーキテクチャーの技術革新が必要な場合には、人々とグループが新たな方法でコミュニケーションをとり、連携して働く必要のあるイノベーションにとって、このような組織構造が妨げになるという。

(中略)

組織の構造と、組織を構成するグループは、その組織の主要製品を設計しやすいように作られているかもしれず、因果関係の方向が逆転することもありえる。その場合、組織の構造と、更生されるグループの関係は、新製品の設計能力に影響を与えかねない。

 

(注)ここでのアーキテクチャーは、コンピューターアーキテクチャの意である

イノベーションのジレンマ」2章 p60

 まずは、コンウェイだの逆コンウェイだの言う前に、サブグループで境界のない、連携しやすい組織構造への改革が今まさに必要だと感じている。ただし、各サブグループが独立していることが悪いと言いたいわけではない。デプロイ頻度とか生産性の向上は一定程度見込むことができる。ただ、コンポーネントレベルの変更だけ対応できれば良い状況(もしくは、その適用範囲を超えたことはやらない状況)を許容していること、開発者のためだけの設計・組織構造に陥る可能性が非常に高いことを危惧している。それでは、本末転倒だよねということが言いたい。そういう意味では、イーロンマスクのコミュニケーション施策は的を射ていますね。

 あとは、この記事にもある通り、コンウェイや逆コンウェイってもう古い気がします。変に組織論とかイノベーションとか言っている人ほど組織構造に名付けたがったり、境界を引きたがるのかもしれない、、、 (すごく、自分の言いたいことがまとまっている)

future-architect.github.io

 

・DDDはコミュニケーション手法

 はたしてそうだろうか、、、 まず、本書のドメインエキスパートとアーキテクトの会話を見るとわかるが、アーキテクトがドメインエキスパートにユビキタス言語を用いてモデリングの議論をしている。ドメインエキスパートが設計やモデリングに詳しいとは限らないし、こういうモデルにしたら機能的にどうなるというのは全く興味ないと思う。確かに、経営者にもITやソフトウェアエンジニアリングに理解を持たせることは必要だが、これらに理解がない時点でIT企業の経営者に向いていないのでそれ以前な問題な気もする。

 経営者以外でいうと、開発者同士でシステムのモデリングすることについても考える。ER図だのユースケース図だのは書くことがあっても、ユビキタス言語やUML図でのシステムモデルを表現することはあるのだろうか。(ここは、自分自身が経験していないのでわからないので何とも言えない、、、)

 どちらにせよ、概念に齟齬のないように常にコミュニケーションをとるというのは当たり前であって、システムモデリングをコミュニケーション手法とは言わないと思う、、、

 

オブジェクト指向論争

 ここまで、DDDを含めたオブジェクト指向の議論がめんどくさいと脱オブジェクト指向の流れも頷ける。ただ、実際には難しい。JavaC#C++で作られた膨大なエコシステムと資産はオブジェクト指向があったからこそであり、エコシステムや資産の少ない他の言語を採用するのはかなりのチャレンジだと思う。あと、その言語らしい設計をするべき意見もあるが、その言語らしいって何をもって言うのだろう、、、

最後に

 完全に、DDDを否定する人みたいになってしまったが、自分は実現できれば理想だと思う。ただ、もう少し議論の余地があるし、多くの人を納得させるまでには至ってないとも感じる。やはりどうしても「組織規模が小さければ」とか「ドメインが単純なものであったら」と思ってしまう。単なるアーキテクトが、「じゃ、DDDやりましょう!」と言ってできるものでもないし、組織レベルから抜本的に変えていかなくてはならない。

 つまり、取り入れられることもあるし、難しいこともあるというのが自分の意見である。それはどの議論においても同じことなのでトレードオフ。どこを取捨選択するかで使い分ければ良いのかなと思った。

*1:本書では、アプリケーションと書かれているが、機能と同義である

*2:本書では、開発者と書かれているが今までの表記に則りアーキテクトと表現する

*3:本書では、デザインパターンの詳細は触れられていないため別途参照を推奨する

*4:5章 p119

*5:14章 p344

「オブジェクト指向のこころ」を読んだ

今年の夏インターンで、アーキテクトやモデラーとして活躍するつよつよエンジニアを見て、何となくアーキテクトに憧れを抱くことがありました。そんな中で、「アーキテクチャやソフトウェア設計を理解するなら、オブジェクト指向デザインパターンは理解しておいたほうが良いよね!」とふと思ったわけです。

 

実は、デザインパターンJavaを始めて1年目くらいの大学1年のときに、かの有名な「Java言語で学ぶデザインパターン入門」を買ったものの、難しすぎて本棚に隠していました。(あと、カツオのたたきは食べたことない)

 

そんな中で、本屋をぶらついていたら、面白そうな本があったので衝動買いしました。

あと、今まで Javaばっかり触っていたので、「いくつか知ってるやつもあるし、余裕だろ」という甘い覚悟で臨みましたね。

対象読者

本書のサンプルコードは Javaで書かれていますが、専用サイトに C++C#での実装が記載されています。基本的に、オブジェクト指向の三大要素がわかっていれば、問題ないです。

 

読む際の注意点として、Java言語の interfaceとソフトウェアにおけるインターフェースを混同すると、何を言っているのかわからなくなります。本書に記載されている "インターフェース" は後者です。あと、ほとんど abstractクラスで実装されていますが、interfaceで実装できるのであれば、interfaceを使うのが一般的だと思います。

あらすじというか概要

第1部 (1~2章)

1章では、オブジェクト指向の三大要素や凝集度、結合度の概念について説明しています。エンジニアなら知っていて当然みたいな雰囲気はありますが、本質をしっかりと理解している人は少ないのではないでしょうか。自分はそうでした。

読んでいるときは「当たり前だよね!」と思っても、本書を読み終わった後でもう一度見ると、違った観点で理解が深まると思います。オブジェクト指向設計では、流動的要素を概念レベル、仕様レベル、実装レベルで抽出し、コードを実装していきます。これらをいかにオブジェクト指向を用いて影響範囲を抑えるかが重要です。この辺の概念は、次章以降でも何度も提唱されています。

 

2章は、UML(統一モデリング言語)の説明になります。次章以降からUMLを用いて解説されているので、UMLの読み方を学びます。すごく簡単なので覚えることは少ないですが、モデリングした設計が可視化されるので理解しやすくなります。

昔は、UMLが新たな言語として流行するみたいな雰囲気もあったようですが、今は全く使われていないですよね。

第2部 (3~4章)

3~4章では、この本でサンプルとして用いる CAD/CAMシステムの概要とそれを用いた実装例について説明しています。設計に携わった経験がある方なら、設計時の問題点をイメージしやすいのかなと思います。それをオブジェクト指向で解決するにはどうすれば良いか?ということを考えるパートです。

 

CAD/CAMシステムなんて、今は知らない人も多いのではないでしょうか。自分はコナンで初めて知りました。

第3部 (5~11章)

この章から、GoFデザインパターンに入っていきます。

最初に、"Facadeパターン" と "Adapterパターン" を見ていきます。クライアント側からシステムの実装や内部設計を意識させないために、カプセル化のみを用いた比較的簡単な解決方法です。この2つのパターンは、他のデザインパターンと同時に利用されることもあるので、かなり重要なパターンだと思います。

 

次に、"Strategyパターン" と "Bridgeパターン" になります。ここから interfaceや抽象クラスを用いるため、複雑になります。クライアント側から見た Aシステム、 Aシステムから見た Bシステムといった2つの観点からそれぞれ見ていく必要があります。どのようにオブジェクトに責任を持たせていくかといった考え方を持つ必要があるため、本当に難しいです。

 

最後が、"Abstract Factoryパターン" です。ファクトリの概念自体は DDDにも出てきますが、ほとんど同義なのかなと思います。各ファミリに対して、ファクトリが実装を提供するというイメージですね。まずファクトリを用意し、クライアントはファクトリを利用するが実装は関知しない、ファクトリ(もしくはConfig)が実装を決定するといった考え方が根底にあります。あと、Abstract Factory単体で何かを解決するということはないのかなと思います。後述にもある通り、生成に関するデザインパターンと一緒に用いることが多いと思います。

第4部 (12~13章)

ここでは、パターンの適用方法を見ていきます。概念レベルから問題点を抽出し、複雑にしていく必要があるということを述べています。その後に、CAD/CAMシステムからデザインパターンを組み合わせた解決方法について考えます。一番重要なことは、デザインパターンはシステムの問題点を解決するために提案された手段であるということです。そのため、デザインパターンの組み合わせは、各デザインパターンの問題点へのアプローチであるということを理解して、システムに適用する必要があると書かれています。

第5部 (14~16章)

モデリング手法や設計アプローチについての説明です。どのように分析し、モデリングをして、デザインパターンを適用して設計するかということが述べられています。SOLID原則を意識することやパターンへの過度な信頼は禁物であるということも書かれています。オブジェクト指向設計の際のアンチパターンについても語られているので、重要です。

第6部 (17~19章)

"Decoraterパターン" 、"Observerパターン" 、"Template Methodパターン" を見ていきます。ここでは、流動的要素をどのように保持していくかということに焦点を当てたものです。簡単に言うと、オブジェクト指向によるイベント管理方法になります。Java をやっている方なら、○○IventListenerとか○○Templateとか馴染みがあるのかなと思います。多くのJava ライブラリにも利用されているデザインパターンです。

第7部 (20~24章)

"Singleton / Double-Checked Lookingパターン" 、"Object Poolパターン" 、"Factory Methodパターン" を見ていきます。今までとは少し観点が違って、生成に関するデザインパターンになります。ファクトリからどのように実装を提供するかの違いになります。ここら辺は、馴染みのある人も多いのかなと思います。

第8部 (25~26章)

今までのまとめ!!

 

読んでみて

すごくわかりやすかったです。「Java言語で学ぶデザインパターン入門」がコードで理解するなら、こちらは理論で理解するという感じですね。

それでも、他の記事や実装例も参考にしましたし、実際にデザインパターンでの設計を見たことがないので、理解度7割って感じですが、、、(それと、内容が濃いため、全体は360ページ程度ですが読み終わるまでに300hはかかりました)

 

何となく気づいた人もいると思うのですが、23個全てのデザインパターンは取り扱ってないです。主要かつ重要なパターンに絞ったのかなと思います。

 

何度も書かれていますが、"オブジェクトへの責務" 、"オブジェクトの集約" 、"カプセル化" の重要性を説いています。

  • 継承よりも集約を用いること
  • カプセル化の本質は、(メンバーやメソッドだけでなく)型やオブジェクトの隠蔽
  • オブジェクトへの責務を明確にすること

これらを理解するのに、かなり時間がかかりました。現代のソフトウェア開発も同じですが、開発における不確実性要素に対して、いかに柔軟に対応することができるかということが根底にあります。これらを上手く使って、不確実性要素に対して最小限の変更に抑え、新規機能の追加では変更を加えないという SOLID原則に則った設計にすることが求められます。(注意点あり -後述- )

 

あとは、凝集度や結合度についても少し間違った理解をしていたのだと痛感しました。

単に、高凝集は関連するメソッド群でまとめたもので、疎結合は機能や役割ごとに分割させるという認識でした。流動性要素の集約やオブジェクトへの責務という観点からみると、持つべきでないモジュールやクラスに責務が与えられていたり、 if文や switch文で無理やり書いていたなと反省しました。(switch はパターンを適用するフラグと書かれているところが良かった)

 

そうは言うものの、責務を明確化することや集約することには限界はあると思う。設計時に分析して不確実性要素を洗い出すわけですが、あらゆることを想定したら分析地獄に陥るし、下手をすればクラス爆発を起こして逆に保守しにくくなってしまう。ここら辺は、システム要件やアーキテクトの腕次第なのかなと思います。ただ、何よりも難しいのは、複雑なシステムに対応するためにデザインパターンを複数用いて対処するということかもしれないです。単一のデザインパターンで解決できることの方が少なく、何かしらのパターンを組み合わせて対応することがほとんどであるということ。間違った組み合わせを選択すると、その先も地獄になってしまう。ここが本当に難しい、、、

 

最後に、DDD やアーキテクチャアジャイル開発にもつながる部分はたくさんあるのかなと思いました。ここら辺の知識が浅いので、今のところ何とも言えないが、こちらの知識もつけていきたいです。(単純に理解不足)

 

学生にオブジェクト指向は早すぎたかもしれないとは思いつつも、アーキテクトって何か響きがかっこいいですよね。それは別として、以前からこの分野には興味あったので、さらに追及してみたいですね。

 

(注意)

SOLID原則には触れているものの、ジレンマというか、トリレンマ(?)のように、これら全てのソフトウェア原則をカバーすることは絶対にできないと思っている。どれかを諦めなければならなず、絶対的なものではないというのは注意しなければならない。ここら辺は、メリット・デメリットと一緒に触れてほしかったです。