デザインパターンとは何か?

私のキャリアはわずか数年ではありますが、最近になってデザインパターンについて考えがまとまってきたので「そもそもデザインパターンとは何か」を簡潔に説明したいと思います。人によって捉え方は様々ですので、こういう考えの人もいるんだと軽く捉えて頂ければ幸いです。

初めに

Java等のオブジェクト指向プログラミング言語を学習していると、「デザインパターン」という単語を良く耳にします。しかし、一方で「デザインパターンは使えない」「実際の開発で役に立たない」という話も聞きます。というか、SIの世界では、開発プロセスの中で出てこないし、ふつう使わないですよね? この「デザインパターン」とは何者なのでしょうか?

結論を言うと、オブジェクト指向開発のコンテキストにおけるデザインパターンは、オブジェクトの設計の根幹を担うものです。ただし、オブジェクト指向開発プロセスにおいてのみ重要です。本記事では、デザインパターンが必要な理由、使われ方について説明します。

オブジェクト指向開発は難しい!

次にデザインパターンの前提となる、オブジェクト指向開発について解説します。

オブジェクト指向開発プロセスとセット

オブジェクト指向開発プロセスとセットでないと意味がありません。オブジェクト指向は「1実装技術」ではなく、日本で主流のDOAと同じく、開発プロセスパラダイムそのものです。例えば有名な「Unified Process」はオブジェクトの、オブジェクトによる、オブジェクトのための開発プロセスです。開発プロセスそのものがオブジェクトであり、成果物もオブジェクトです。オブジェクト指向開発プロセスの歴史と具体的な手法については、下記の書籍が詳しいです。

The Unified Software Development Process

Object-Oriented Analysis and Design With Application

Object Oriented Modeling and Design

プログラミングありきの世界もあるのかもしれませんが、少なくともエンタープライズにおけるオブジェクト指向開発は、「顧客の要件と動くソフトウェアの世界のギャップを埋める」「コンポーネントの再利用により生産性を高める」等を目的として、開発プロセスの一環として進化してきたことがわかります。特にBoochの書籍ではドキュメント・ドリブン、構造化設計手法を採用した大規模プロジェクトで起こりがちな問題点と、それを乗り越える方法としてのオブジェクト指向開発手法が提示されており、衝撃を受けました。オブジェクトの役割を「stable intermadiate form」と表現しているもわかりやすくて良いです。
(極東の某国では未だに前者のパラダイムで頑張っていることが多いようです。「(当時の)多くの企業が20年以上前の古い開発プロセスで〜」等との記述がありますが、そこから数えて日本は40年遅れといったところでしょうか。)

また、Rambughの書籍ではモデルの本質が簡潔に説明されており、オブジェクト指向開発手法は元来、上流重視であることがわかります。コンピュータの世界から切り離されたシステム化対象(real world object)を抽出し、少しずつコンピュータの要素を肉付けするスタイルです。実装はできるだけ後工程に遅延させます(そして単純作業化する)

どの書籍も「開発手法としてのオブジェクト指向」がメインであり、オブジェクト指向を一実装技術と思いこんでいるエンジニアは一読することをお勧めします。多分、ソフトウェア開発の世界観が変わります。単純なCRUD + αなWebシステムならともかく、ある程度以上の規模と複雑さで、再利用性が高い領域でオブジェクト指向は極めて有効です。

オブジェクト指向開発の問題点

オブジェクト指向開発は優れた手法ですが、重大な問題があります。それは「オブジェクトの抽出」が極めて難しいという点です。Boochの書籍では「ソフトウェア開発をlabor intensiveでつらいものからcreativeなものに転換したい!」という熱い思いが語られていますが、その代償がこの難しさです。

そもそもオブジェクトはどこから来るのでしょうか? 一般的には、システム化する領域(Domain Model)でしょう。これらの領域からオブジェクトを抽出するMethodlogyは様々です。例えば、名詞がオブジェクトの候補、動詞がメソッドの候補になったりします(詳細は前述の書籍等を参照。他にもいっぱりあります。)

しかし、真面目に考えればわかりますが、動くシステムを作るにはDomain Objectを抽出するだけでは不完全です。それらのDomain Objectを生成、管理し、「つなぎ合わせる存在」が必要です。例えばAccountというオブジェクトがあったとして、それをどうやって生成、維持管理するのでしょう? また、Domain Object自身の粒度、関連、振る舞いの設計は自由度が高すぎるので、参考にできるテンプレートが欲しいと思うのが普通でしょう(詳細はRambughの書籍を参照。頭が痛くなります...)

そこでデザインパターンの出番です。デザインパターンは上記のオブジェクト指向設計の問題に対する処方箋となります。

デザインパターンの役割とは?

デザインパターンとは、一言で言ってしまえば、「オブジェクトの設計テンプレート」であり、オブジェクト指向開発プロセスで利用すべきものです。オブジェクトを設計、抽出するときに参考にします。

前述の通り、オブジェクトの抽出は極めて難しいため、経験者のオブジェクト設計の知見を再利用できる形でカタログ化し、開発者のレベルの底上げすることが重要です。その道何十年とやっていて、自分なりの方法論を確立しているならともかく、大多数の開発者には基礎知識として必須でしょう。
(もちろん、開発プロセスDOAの時に実装ありきで気まぐれで使うべきではないでしょう)

もっとも有名なのはGOF本のパターンであり、デザインパターンといったら大抵これのことを指します。



次は、具体的なパターンの説明に入らず、誤解されやすいポイントであるデザインパターンの抽象度を見ていきたいと思います。

デザインパターンの抽象度は高い

デザインパターンはどこにでも存在します。GOF本の例が具体的すぎて、誤解されがちですが、ブロックのようにくっつけるというよりも、オブジェクトの関連、ライフサイクル等の設計に自然になじませる感じです。具体例としてJavaAPIである「Servlet」を見ていきます。

ServletはHTTPのサーバサイドのReceive/Replyの処理を抽象化したものです。ServletAPI一つとっても、GOFデザインパターンの要素が複数含まれています(少なくとも、私はこう解釈しました)

  • オブジェクトのライフサイクル管理 => Singlton Pattern
  • リクエスト毎にインスタンスを生成せず、HTTP処理の外部的な特性をメソッドの引数とする => Flyweight Pattern
  • init, destroy等のコールバック => Template Method Pattern
  • Serviceオブジェクトや、フレームワークへの入り口 => Facade Pattern(見方によっては)
  • また、別のパターン本にあるIPCの抽象化パターン「Fowarder-Receiver Pattern」の実装そのものでもあります。入力がInputStream、出力がOutputStreamであり、プロトコルの実装を隠ぺいしたIPCメカニズムの抽象を提供します(現実には、実装であるHttpServletを相当意識しますが・・・)

    また、上記のデザインから、Servletの目的はあくまで「HTTP処理の抽象化」であり、開発効率を上げるための複雑な機能をゴテゴテ盛り込むべきではないということもわかるでしょう。他のJavaフレームワークServletを土台としていますが、それは「Servletが使えないから」ではなく、初めから意図された設計です。

    上記の例を見ていて、なんとなく察しがつく人もいると思いますが、パターンには以下のような特性があり、一筋縄にはいきません。非常にトリッキーで難しいです。

    • パターンは複雑に絡み合い、特定の目的のためにオブジェクトの振る舞い、ライフサイクル、関連、拡張、再利用性などを決定します。
    • パターンは抽象度が高く、設計の基本的な考え方のテンプレートなので、「パターンを適用する」というよりも、「目的に合わせてパターンを選択し、すり合わせる」作業が必要となります。目的ありきであることが重要です。

    Servletの開発者も、問題領域、制限等を良く理解したうえで、パターンカタログや他のAPIなどを参考にしながら、他のメンバとのディスカッションやプロトタイピング、コミュニティからのフィードバックを得ながら、現在のデザインにたどり着いたはずです。パターンを上手く使うコツは、「自分で問題領域を良く理解し、自分の頭で考えて、自分で手を動かしてみる」以外にないと思います。

    色々小難しいことを書きましたが、もちろん、パラダイムDOAの場合はオブジェクト指向設計をスルーするのもありだと思います。

    パターンの効果

    パターンには様々な効果があります。

    • 語彙の共有 => 開発者間のコミュニケーションを円滑化します。「あんな感じ」とか言わないで済みます。
    • ソフトウェアのデザインの分析 => 何百、何千とオブジェクトの山があっても、設計的に重要なところや、設計の意図を理解できます。
    • オブジェクトの変更性、再利用性を高める => フレームワークミドルウェアなどの再利用性の高い分野で特に威力を発揮します。

    しかし、デザインパターンには、複雑化という暗黒面もあります。基本的にデザインパターンありきで考えずに、オブジェクトの設計目標、目的ありきで必要に迫られたときに利用すべきです。

    様々なパターン

    デザインパターンやその亜種は様々です。もっとも有名なもののうちの一つは、POSA(Pattern Oriented Software Architecture)等で詳細に説明されている、Architecture Patternです。有名なLayer, MVC等が分類されます。また、今流行りのMicroservices Architectureも、Microkernel Patternの亜種として見ることができます。 極めて重要な考え方ですので、エンジニアならMUST BUYでしょう。

    コンポーネントの設計に影響を与えるデザインパターンに対して、アーキテクチャパターンはソフトウェアの根幹の設計なので、日本では方式設計、基本設計などと呼ばれます。アーキテクト的な観点では、デザインパタ-ンよりも重要です。

    また、デザインパターンにも、様々な亜種が存在します。

    POSAのデザインパターン

    GOFよりも特定の領域に特化したパターンたちや、GOFのパターンをオーバーライドしたパターン(嫌がらせっぽい...)が説明されています。VOL.2のパターンはAPサーバ, 非同期処理マニア向けです。

    Patterns of Enterprise Application Architecture

    エンタープライズ開発者には必須のパターンです。知ってるのは常識扱いでしょう。

    ほかにも、PLOPDのバラエティー豊かなパターンたち等、パターンの種類は豊富だし、日々増えています。また、自分たちで特定のドメインに特化したパターンカタログを作るのもありだと思います。

    まとめ

    以下、まとめになります。

    私の理解はまだまだ浅いですが、参考になれば幸いです。