21世紀の第二四半世紀でデザインパターンを学ぶ理由について考える。
デザインパターンというのは、GoF(Gang of Four; 怒れる4人)によって、『オブジェクト指向における再利用のためのデザインパターン』にまとめられた、よく使われる23個のパターンとして、名前が与えられ、カタログとして整理されたもののことである。GoFにまとめられたものでも言語によっては使えないものがあったり、GoFにまとめられなかったものやクラウドの登場に合わせたクラウドデザインパターン1もあるが、本発表については取り扱わないものとする。
デザインパターンは、状況、問題、名前、解決をパターンとして記述するものであり2、パターンによって意図を共有することにも使えるし、OOPにおけるコードの可変性にも寄与する。
本発表での想定読者は、デザインパターンや再利用可能性や可変性に興味がある人、コード同士やソフトウェア同士が離れている環境で共通したものを用いたい人、そして、ドメインでビジネスを駆動することを望む人である。
他方、OOPやデザインパターンが生まれた理由や経緯についての歴史的な関心がある人には、あまり興味を惹かれるものではないであろう。デザインパターンがどうして生じたのか、当時どういう環境で、どういう課題が共有されており、それの解決手段としてのデザインパターンはどういう経緯だったのか、ということについては話さない。これは発表者が当時の状況を生々しく知らないから3でもあるが、21世紀の第二四半世紀での有効性について考えるにあたって現在の視点から語る方に集中したいと思ったからでもある。
発表者が考えるに、デザインパターンを学ぶことは、GoFの出版から四半世紀以上が過ぎた今でも意義がある。そして、今のmatsuri technologies株式会社における開発組織においても必要な場面が存在する。
LLMが登場し、生成AIによる開発支援ツールを使っている今、20世紀に提示された人間による分類が果たして有効なのか、と疑問を抱くかもしれないが、デザインパターンに含まれる交換可能性や設計の意図は、LLMの時代においても重要であることはここに宣言しておく。
そして、本発表ではデザインパターンを学ぶ理由として4つのカテゴリーを提示し、それぞれを実例と合わせて考えていく。実例について、パブリックにできないものは、適宜口頭で示すものとする。
Iterator は自明である。おそらくIteratorを学習過程で実装したことがある人は多いだろうが4、業務において明示的かつ意識的に実装したことは少ないかもしれない。現に、多くの言語はIterator がすでに組み込まれており、呼び出すことすらなく、ただスライスや配列を宣言するだけで求めるものは実現される。
しかし、業務において多くのものを処理や走査する際、next や hasNext とに該当するものを実装・利用していることがある。このような場合、該当のものについては Iterator を満たす実装をしておいた方が、再利用の観点からは良い5。時としては、IteratorではなくVisitorパターンであるべきこともあるかもしれないが。
そして、自明というのは誰にとっての自明かが重要である。時として、とっくに歴史のうちに議論し尽くされているものについて、改めて議論し、車輪の再発明をする、ということがある。これは歴史を追いかけている人にとっては自明であるが、そうではない人にとっては自明ではないことの証左である。他方、自明なものに対して改めて問いかけることの価値を生むこともあるが、それは誰にとって自明なのかによって意味が異なる。
以上のように、自明さの観点からも、デザインパターンを学ぶ価値はある。
matsuri technologies株式会社では予約を扱っている。予約というのは、宿泊者のために一定の空間、一定の期間を確保することである。この予約に関して、複数のプロダクト・ソフトウェアにおいて、現状ではそれぞれ独自に実装している。独自に実装している理由は、現時点から見るに、予約についてドメインごとに取り扱いたいからであろう。
そんな中、プロダクトやソフトウェアが増えていく中で、いちいち同じ型を宣言したり、似たようなメソッドを実装したりすることに対して、苦しみや悩みが生まれている。たとえば、type ReservationId stringと型をラップしたり、func(r Reservation) GetPrice() intを実装したり、というのをそこかしこで行っている。これに対して、予約についての型情報やメソッドを共通化するパッケージを作って、共有するのはどうかという提案がなされた。これはとても良いことである。さて、これについて、デザインパターンから学べることがある。
それは、過度な共通化はしないべきであり、そのためtemplate patternが有効となりうる、ということである。というのも、予約に対して、金額を得る、というのは、アクターによって異なるからである。予約に関係する金額は単純化すると次のように構成されている。
これに対して、アクターおよびシステムによって、「金額」として取りたいものは異なる。宿泊者とコミュニケーションをするときは、1、2、3全ての合計値が求められる。売り上げを考える時は1と2が必要で、建物に関する収益を計算するためには、予約以外の情報が十分に取れているとすると、予約からは1のみで十分である。つまり、価格を取得するメソッドにおいて実装まで共通化することは望ましくない。少なくともinterfaceであるべきことはわかる。同様のことはチェックインやチェックアウトについても当てはまる。運営実績においては日付が欲しいが、他方で、チェックインや清掃においては時刻が欲しいということもあるため、実装だけではなくinterfaceすらも共通化することには十分に注意を払わねばならない。
さらに、matsuri technologies株式会社が事業として扱っている、時空間を支配する概念は予約以外にもあり、同じ時空間を扱っているところでの基本となるテンプレートがあるのではないか、と考えることもできる。
先の節では、分散したコードにおけるデザインパターンからの学びであった。分散という観点でのもう1つの学びは分散したソフトウェアに対する学びである。
matsuri technologies株式会社は、事業会社でもあり、ソフトウェアやプロダクトを含むシステム6も提供している。1つのプロダクトであっても、複数のソフトウェアが、分散、非同期、疎結合な連携をしており、Observer(Pub/Sub)パターンやAdaptorパターンが使われていると解釈が可能である7。補足であるが、上述の予約の事例からも分かるように、プロダクト間連携においては、アダプターパターンが採用されがちである。
ソフトウェア間やプロダクト間の連携において、よくObserveした結果、Observeする対象(Subject)に変更を加えることがある。これはmatsuri technologies株式会社においては多くある。在庫状況の変化を検知して、在庫状況を調整する、ということを、非同期、疎結合、分散でやっている。これはかなり結果整合的である。
そして、Privateな事例であるが、開発過程において面白いこともあり、変化した結果を受け取り、Subjectを変化させ、その変化させた結果を受け取り、またSubjectを変化させ、という無限ループに陥るケースもあった。これについてどう対処するか、というのは、すでにObserverパターンにおいて語られている。Subjectから通知されている最中かどうか、というのをObserverが知っていればよい。このように、歴史を知っていれば、この問題を事前に防げただろうし、これから問題を解決する場合でも解決は容易となるであろう。
先の節までは、コードやソフトウェア連携におけるデザインパターンの有効性についての話であった。次に、事業やドメインにおけるデザインパターンの意義について考えよう。
事業をする限りにおいてお金を扱わないということはありえない。そして、単純な金額の合計で事業の状態を計測できるわけがない。例えば、最初に入ったお金であっても、その後に調整が入る。これによって、調整前、調整、調整後、とお金を扱うものが3つ生じる。さらに配賦も発生する。配賦前(調整後と等しい)、配賦、配賦後、とまた新たに2つもしくは3つが生じる。

これについて、どう捉えるか。まず全てお金であるから、調整後と調整前と調整を全て同じものとみなして、Compositeパターンを採用するということも考えられる。しかし、Compositeパターンを教科書的に考えると、上にあるものからaddしていくというものであり、配賦後をまず置くことになってしまうから、不適当な予感がする。
次に、ベースとなるものがあり、それに要素を追加していく、というところから、調整や配賦をDecoratorパターンとして考えることもできる。最初のお金に調整を追加して、さらに配賦を追加して、とやっていくのは確かにDecoratorパターンっぽい。

しかし、配賦後に調整をする、というのはモデリング上、望ましくない。となると、これは単純なDecoratorパターンではなく、順序を扱えるようにしておかねばならない。こうなるとBuilderパターンを含められるようにすることも検討の余地が出てくる。
このように、あるパターンには該当しないことを知る、ということは、取り扱う対象についての理解を深めることでもある。
さらに、matsuri technologiesが扱うデータは多種多様であり、そして、23個のデザインパターンにジャストフィットするものは少ない。では、学ぶ必要はないのかと言うとそうではない。むしろ、デザインパターンに該当しないものを探すことの方が楽しいから、デザインパターンを知っておくべきである。パターンに該当しないものは、新たなパターンになるかもしれないし、パターンに収まることはない独自のドメインであるかもしれない。
そして、このデザインパターンかもしれない、いややっぱり違う、ということを繰り返し、いずれにも該当しない、ということはすでに23のパターンのいずれにも該当しないことの判断をしたことであり、そしてそう判断した理由があることは、開発中に考えることを減らせられ、かつ、可変で可用で、そして、弾性のあるソフトウェアを継続的に開発しやすくなることにも寄与する。
以上が、デザインパターンを学ぶ理由であると発表者が考えたものであり、それに関連したmatsuri technologies株式会社における開発事例であった。
直近で生じるであろう、共通パッケージを作っていこうか、Pub/Subで開発したり修正したりしようか、という際には、ぜひ先人の知恵と議論を学び、車輪の再発明をせず、独自のドメインに対応した開発をしていこう。
本発表の理由は、matsuri technologies株式会社におけるデザインパターンの活用可能性について話すものであったが、発表者が裏のテーマとして設定していたことは、自然に分類は存在しない、人が分類するのだ、というものだった。ある問題がこのカテゴリーに属する、というのはなく、ある問題に対して人がどう反応・解釈・対応・解決をするのか、その中で人が問題をどうカテゴライズするのか、というのが問題と人間との関係である。技術ブログの趣旨からは離れるため、明確には論じなかったが、考えるには値するテーマであろう。
脚注に含まれなかったものをここに記載しておく。
CloudDesignPattern (最終閲覧日: 2025年11月12日11時29分) ↩
参考「一時期プログラミングのデザインパターンというものが大流行しましたが、現在ではどのように評価されているのでしょうか?」 (最終閲覧日: 2025年11月12日11時33分) ↩
例えば、エッグスタンドを語るには、エッグスタンドが発明されたタイミングを知る必要はない。しかし、あらゆる道具がただのお飾りやインターフェースではなく道具である理由は、課題が存在し、その課題を解決しようとする者に道具は工夫を要求し、使用者にはそれに応じるだけの熱量が存在したからである。歴史やそこにいた人やその時の状況を知っていれば、今の状況に対してもその道具が通用するかを歴史という観点からも論じられうる。 ↩
過去、二分木イテレータをRustで実装した記録がある。ref:二分木にイテレータを実装してみたら面白かった話 ↩
Queryで色々やっていることもあるだろうが、GORMのrows.Next()を使えば済むというケースもある。そして、その存在を認識するためにも、状況、問題、名前、解決をパターンとして記述されているものは有効である。 ↩
システムというのは、その語源通り、"σύστημα"(シュステーマ)、つまり、"σύν"(シュン)と"ἵστημι"(ヒステーミ)、共に、立つものである。複数の関連するコンポーネントがあり、それが相互作用し、1つかいくつかの目的や理念を持った共同体である。 ↩
なぜ「解釈」としたのかというと、このようなデザインパターンは採用していたにせよ、それ以外の観点も多分に含まれているからであり、デザインパターンという文脈から述べているからである。 ↩