(Meta)Modeling Module Evolution Patterns

モジュールの構造は、外部や環境の要求に応じて、進化(or 変化)する。


たとえば、クラスにはメソッドが追加される。あるクラスのサブクラスが存在するように、「メソッドの追加」という進化にもサブクラス(サブ進化)が存在する。


たとえば、「メソッドの追加」という進化のより具体的な進化として「オーバーロードメソッドの追加」という進化が考えられる。

さらにもっと具体的な継承関係を考えるなら、次のようになる:


メソッドの追加 +- public メソッドの追加 -- public オーバーロードメソッドの追加
|
+- private メソッドの追加 -- private オーバーロードメソッドの追加

When a Decision is a Design Decision

設計とは? 設計における決定とは?


マルチパラダイムデザイン」によれば、設計とは:

設計とは、ある問題に対して解決策となるような構造を与えるアクティビティのことである。

とある。「ModernC++ Design」によれば、設計とは:

ソフトウェアシステムの設計とは、各々の解決領域を組み合わせて解決策を選択することなのです。

とある。


たとえば、ある単純な(アルゴリズム的な)処理を行うことを考えてみる。以下のような、少なくとも3つの解決策が考えられる:


// 解決策1
public class Main {

public static void main(String[] args) {

new Main().run();
}

private void run() {
System.out.println("アルゴリズム");
}
}


// 解決策2
public class Main {

public static void main(String[] args) {

new Main().run();
}

private void run() {
algorithm();
}

private void algorithm() {
System.out.println("アルゴリズム");
}

}


// 解決策3
public class Context {

public void algorithmInterface() {
System.out.println("アルゴリズム");
}
}

public class Main {

public static void main(String[] args) {

new Main().run();
}

private void run() {
new Context().algorithmInterface();
}
}

解決策1では、アルゴリズム処理のコンサーンが分離されていない。解決策2では、手続き(関数 or メソッド)によって、分離されている。解決策3では、クラスを導入することで、さらにコンサーンを分離している(Mainクラスは、アルゴリズム処理のコンサーンについて何も知らない)。


はじめにあげた設計の定義からいえば、これら3つの解決策の中から特定の解決策を選択(決定)するアクティビティを設計と呼んでいいのだろうか?

クラスを導入するかどうかの決定は、設計に関わる決定に思える。

では、メソッド(関数 or 手続き)を導入するという二つ目の解決策は、設計に関わる決定だろうか? 少なくとも、コンサーンの分離に関わることであるとは言える。Kiczales らによれば:

Programming language designers have developed numerous mechanisms for separation of concerns (SOC) at the source code level, including procedures, object-oriented programming and many others. [...]

Our goal is understand what kinds of concerns each mechanism best separates, and how the mechanisms work together to separate multiple concerns in a system. [...]

また、どういった基準でソフトウェアを関数に分解(decompose)するのかといったことに関わる決定が、オブジェクト指向以前のパラダイムには存在したはずである。もし、どういった基準でソフトウェアをクラスに分解するのかいった決定のみを設計のアクティビティと呼ぶなら、オブジェクト指向以前には、そのようなアクティビティは存在しなかったことになる。


他にも、環境が異なれば、上記の3つの解決策における決定は単純(クラスで分割するのが正しい)ではなくなる。たとえば、携帯ゲームのような利用できるサイズに制限のある環境では、クラスで分割すること(解決策3)は常に適切な決定になるとは言えない。


したがって、上述の3つの解決策は、一つの設計(解)空間に含まれると考えられ、解決策の一つを選択するアクティビティは、設計における決定であると考えられる。


関連:

Gregor Kiczales and Mira Mezini
Separation of Concerns with Procedures, Annotations, Advice and Pointcuts
ECOOP'05
DL: http://www.cs.ubc.ca/~gregor/

Evolution Boundary of Design

モジュール(クラスやアスペクト)の構造の進化(あるいは発展・変化)を捉えようとしたときにどの範囲までその進化が及ぶことになることかを考える必要があると思う。なぜそもそも捉えなければいけないのか、捉えると何がうれしいのか、という疑問はとりあえず無視する。

モジュールは 単に 進化しない。設計における決断の結果として進化する。それは、その時における文脈を考慮した上での意図的な進化であり、単に進化するわけではない。


ソフトウェアは、モジュール(or オブジェクト)同士のやりとりで構成される。オブジェクト同士はお互いに協調し合って、何らかの機能を果たす。

デザインパターンは、クラス(オブジェクト)の構造的な協調を明示的に書き示す。たとえば、Strategy パターンは、Context, Strategy, ConcreteStrategy などの役割を持ったオブジェクトが協調してある設計上の問題を解決する。


したがって、構造の進化を考えた場合、単に単体のモジュールの構造の変化を捉えるだけでは不十分であり、協調するモジュールの構造として変化を捉える必要がある(と思う)。

たとえば、Strategy interface へのメソッドの追加は、単にその interface の構造が変化するのではなく、その interface を実装するクラスの構造も変化させることになる。


したがって、モジュールの構造がどういう 意味や機能単位 で協調しているのかという設計の境界を把握することが重要となる。あるモジュールへの構造的な進化の要求は、そのモジュールと協調するどの範囲までを考えればいいのか。

個々のデザインパターンの構造の単位(Strategy でいえば上述した3つの役割を持つクラス)で考えればいいのか。

デザインパターンは、合成される場合がある。ConcreteStrategy の役割を持つあるクラスは、同時に Context の役割も持っているかもしれない。この場合、二つの Strategy パターンが構成する構造の単位を、その構造を構成する個々のモジュールの進化に対する強調的な構造の変化だと見なすのか。


そもそも、モジュールの構造の進化の視点から見た場合、その分析対象は、必ずしもデザインパターンである必要はない。デザインパターンは、出発点として役には立つ。しかし、デザインパターンの本来の目的は、設計におけるモジュール構造を明示的に文章化することではない。


設計を考慮しつつモジュール構造の進化を理解しようとしたとき、そもそも分析のためのツールが足りないことに気付く。語彙が足りないことに気付く。Maman と Gil の Micro Pattern の研究 は、デザインパターンでは足りない語彙の不足を補ってくれる。Micro Pattern は、繰り返し起こる単一のモジュールの構造を特徴を捉え、名前を与える。ただし、複数のモジュールとして繰り返し発生する構造は取り扱っていない。

Analyzing and Understanding Designs

設計自体を分析したり理解するためには、どうすればいいのか?


ここで議論したいのは、ある問題領域に取り組んでいるときに、その問題に対してどのような設計がいいのかということでなく、ソフトウェアにおける設計という活動・行為やその設計から導かれるソフトウェアの構造そのものを分析したり理解したりするにはどうすればいいのかということ。


問題領域を無視して設計を分析・理解することは無理と思われるかもしれないけど、(GoF の)デザインパターンなんかは、問題領域そのものには(それほど)依存せずに一般的な設計の問題とそれに対する解を文章化している。

同じように、リファクタリングカタログなんかも、プログラムの設計を改善するという視点から、設計における問題点とその改善方法を文章化している。

恐らく、これらデザインパターンリファクタリングは、設計を分析して体系的に文章化するという意味では、代表的なアプローチだと思う。


リファクタリングはともかくデザインパターンをわざわざ書いて設計を分析しようという人はそれほど多くない。「パターンハッチング」なんかに書いているように、デザインパターンを書くという行為はなかなか大変だと思う。


では他にアプローチはないのか。

UML のクラス図なんかは、クラス間の構造的な関係などを視覚的に表現することで、現在行っている設計がどのようなものかを理解する助けにはなくかもしれない。

JavaDoc などの API ドキュメントなんかも、助けになるかもしれない。

設計を教える本(たとえば「アジャイルソフトウェア開発の奥義」)なんかは、自身の設計スキルを向上させるのに役立つかもしれない。


すごくナイーブなアプローチとしては、設計上の問題にぶちあたったときに、その設計上の問題を 考えるの ではなく、体系的に分析して文章化する方法がある。ある設計Aの時の利点と欠点、設計Bの時の利点と欠点、などなど。

ただしこのアプローチは、まともに取り組もうと思うとすごく大変でめんどくさいと思う。なぜなら「Modern C++ Design」にも書いているように、設計という行為は、一手先を読むような行為ではなく、数手先を読むような行為だと思うから。

一手先を読む(つまり現在の要求だけを考慮する)場合は、設計Aが設計Bよりよいかもしれない。しかし、数手先を読む場合(つまり、将来の要求を想像する)には、設計Bから出発する パス を選択するほうがよいかもしれない。

もちろん、将来起こらないかもしれない要求を考慮してのアップフロントな設計は、無意味に複雑な構造に至る可能性がある。


ソフトウェア設計の複雑性にどうやって取り組んでいけばいいのか。

もちろん、色々な取り組みがある。デザインパターンであったり、言語設計者が考える新しいパラダイムやモジュール化の方法であったりがある。

しかし、それらの取り組みは体系的なのだろうか。

設計自体を理解したり分析したりすること自体のためのツールやアプローチ、あるいは方法論はそれほどないのかはないか。

先ほど例であげたように、デザインパターンリファクタリング的に設計を文章化する方法や、ナイーブにその時々の設計を分析していく方法などしかないように見える。

Design Patterns: Recurring Problem vs. Recurring Solution

デザインパターンの標準的な見方は「ある文脈において繰り返し発生する設計上の問題に対しての標準的な解法を明示的に記述したもの」という感じ。

ある意味では、問題が繰り返し発生するだけでなく、解法も繰り返し発生する。この記事での焦点は、繰り返し発生する問題と解法のどちらが重要なのか、ということ。

注意:上述したデザインパターンの定義は、正確に文献を参照して書いているわけではないので、前提としている定義が誤っていれば、以下の話の信頼性は失われる

そもそも、なぜ、問題と解法のどちらかが重要なのかを考える必要があるのかを。まず書く。

恐らく、根本的な問題は、安定性の違いにあるのではないかと思う。問題よりも解法の方が変化しやすい。

たとえば、デザインパターンが提供する解法は完璧ではなく、単なる回避策であると言われたりもする(正確に文献を参照するのは面倒なので省略)。

たとえば、AspectJ を使って デザインパターンの実装を改善しようという試みなどがある。他にも、提案しようとしている言語を評価するための例題やケーススタディとして、従来(Java など)のデザインパターンの実装の欠点を挙げ、その欠点を解決するような研究報告が多い(僕のクソ論文を参照)。


ここから分かるのは、取り扱おうとしている問題(つまり、各デザインパターンが解決しようとしている問題)と比べて、その解法は、不安定だということ。つまり、実装する言語が変われば、解法も変化する(このことは、昔から指摘されているし、GoF でも言及されている)。


ただ、現状の研究上の課題としてあると思うのは、異なる言語が提供する解法間の関係。

ここでは、簡単のために、大きく異なる言語(たとえば Java と CLOS などのダイナミックな言語)がそれぞれ提供する解法は無視して、似ている言語(JavaJavaを拡張した言語)or 言語ファミリ が提供する解法だけを考えたい。

言語が異なれば、解法は異なる。とはいえ、実際に何が異なるのか

  • それとも、AspectJ の実装と Java の実装は 共存するのか。その場合、割合はどうなるのか。従来のJavaでは、ある問題に対しては 9 割の可能性で Javaデザインパターンの実装が適切だったとすると、AspectJ の存在にとってその割合はどう変わるのか。5割が Java の解法で 4 割が AspectJ の解法なのか。その場合、この状況を パターン と呼べるのか。

このような疑問に取り組んでいる研究者は少ない。言語設計者は、少なくとも論文上では、デザインパターンを例題やケーススタディの一例として見なすことが多い(僕のヘッポコ論文を参照)。逆に、パターン研究者がこの問題に取り組んでいるケースを僕は知らない。


ここでは、デザインパターンということに焦点を当てて議論を進めたけれど、設計における問題と解法という視点からは、ここでの議論はデザインパターンに限定されない。デザインパターンは、設計における比較的重要な問題を取り扱う。一般の設計においては、それほど重要でない設計上の問題も繰り返し発生する。そして、恐らく、解法も繰り返し適用される。そして、その解法も、もちろん、その言語を用いるかによって影響を受ける。


まとめ:
デザインパターンは、解法だけでなく、問題も記述する。デザインパターンかどうかにかかわらず、つまり、解法が繰り返し発生するかどうかにかかわらず、設計における問題は繰り返し発生する。そして、問題は解決されなければならない。適用される解法は、最適でないかもしれないし、適切でないかもしれない。誤っているかもしれない。不十分かもしれない。しかし、解法の頻度は(定量的でなくても)観測できるかもしれない。分析できるかもしれない(言語設計者がやってるのはまさにこれだと思う:問題の分析とそれに対する解法)。

言語の拡張に伴う解空間の拡張は、設計における選択肢を増やす。デザインパターンにおける実装上の解法は、選択肢の増加のため、安定でなくなる可能性がある。解きたい問題は同じかもしれない。ただし、解法は、もはや、一方通行な、暗黙的に選択してよいパスを形成していないかもしれない。

参考:

評価対象としてのデザインパターンの使用に関する考察
http://www.ncfreak.com/asato/papers/bench-dp-final.pdf

Modularity and Modularity Properties, or Design Choice

モジュラリティの向上と設計上の選択との関係は?


そもそも モジュラリティ とは? については「デザイン・ルール」をぱっと調べても載っていなかったので省略。


質問を変えて モジュラリティが向上した という視点から考えてみる。


Hannemann と Kiczales は、AspectJ によって GoFデザインパターンを実装することでモジュラリティが向上したと報告している。向上は、locality, reusability, composability, and (un)pluggability といった、モジュラリティに関連する4つのプロパティの視点から述べている。

AspectJ implementations of the GoF design patterns show modularity improvements in 17 of 23 cases. These improvements are manifested in terms of better code locality, reusability, composability, and (un)pluggability.

疑問は、設計上の選択肢における決定にこれらのプロパティがどう影響を与えるのか、ということ。


まず、「モジュラリティが向上した」というのをどう解釈すればよいのだろう? 

Hannemann らの例でいえば、Java バージョンの実装と AspectJ バージョンの実装が選択肢としてあることになる。そして、AspectJ バージョンの実装(設計)の方が、モジュラリティが高い。

これは、AspectJ バージョンが Java バージョンを置き換えることになるのだろうか? Hannemann らはそうは主張していない(と思う)。また、自分の経験上、完全に置き換えることにはならない。例外が存在する。

また、従来の OO バージョンのパターンを適用するかどうかを決定する場合には、いわゆるフォース(トレードオフ)が影響する。


次に、平鍋さんは『「テストしやすい」ことが、良い設計』or『Ease of Testing(EoT:テスト容易性)の高い設計が、よいオブジェクト指向設計である』と主張している。

AOP のコミュニティでは、アスペクトをどうテストするのかについては、まだまだ良く理解されていないテーマである。従来の JUnit では、アスペクトを適切にテストできないかもしれない。そのため aUnit などのテスティングフレームワークが提案されている。

したがって、AspectJ バージョンのデザインパターンの実装は、Java のバージョンよりもモジュラリティを向上させるかもしれないけれど、AspectJ バージョンにおける EoT は Java バージョンの実装よりも(少なくとも一時的に)低いかもしれない。

この場合、平鍋さんの意見にしたがうならば、Java バージョンの実装(設計)を選択することになる(もちろん、選択にはその他の色々な要因が関係する)。このことは、モジュラリティの向上という議論やそれらのプロパティの役割についても疑問を生む。


ただし、平鍋さんの記事ではモジュラリティという用語を使っておらず、また EoT がモジュラリティ向上に影響するプロパティかどうかは不明である。


疑問のまとめ:

  • モジュラリティの向上は、設計に関係するいくつかのプロパティで表現できる? もしそうなら、上記の4つ以外にどんなプロパティがある?
  • モジュラリティ向上に関連するプロパティと、設計における選択との関係は? 設計におけるある選択肢をその他の選択肢よりも優先して選択する、ということは、モジュラリティのプロパティの視点から説明できる? また、プロパティ間には、優越がある?

たとえば、ある設計 A は B よりも localityと composability が優れているけれど、 reusability については B が優れているので B を選択する、ということはありえる?

  • モジュラリティの向上には影響を与えないけれど、設計上の選択肢には影響を与えるプロパティ(or 要因)は存在する? もし存在するなら、モジュラリティのプロパティと設計に影響を与える要因との関係は?

たとえば、ある設計 A は B よりも localityと composability が優れているけれど、 EoT については B が優れているので B を選択する、ということはありえる?


参考:

キム・クラーク (著), カーリス・ボールドウィン (著), 安藤 晴彦 (翻訳)

デザイン・ルール―モジュール化パワー

http://www.amazon.co.jp/exec/obidos/ASIN/4492521453/

Jan Hannemann and Gregor Kiczales.

Design Pattern Implementation in Java and AspectJ

Proceedings of the 17th Annual ACM conference on Object-Oriented Programming, Systems, Languages, and Applications (OOPSLA), pages 161-173, November 2002.

DL:http://www.cs.ubc.ca/~jan/papers/oopsla/oopsla2002.html

「テストしやすい」ことが、良い設計(EoT=Ease of Testing)
http://blogs.itmedia.co.jp/hiranabe/2005/08/post_e66c.html

Cristina Videira Lopes and Sushil K. Bajracharya

An Analysis Of Modularity In Aspect Oriented Design

AOSD'05

DL: http://www.isr.uci.edu/~lopes/documents/aosd%2005/index.html

Kevin Sullivan, William Griswold, Yuanyuan Song, Yuanfang Cai, Macneil Shonle, Nishit Tewari, Hridesh Rajan

Information Hiding Interfaces for Aspect-Oriented Design

In the proceedings of the Joint 10th European Software Engineering Conference and 13th ACM SIGSOFT Symposium on the Foundations of Software Engineering (ESEC/FSE 2005), 5-9 Sept 2005, Lisbon, Portugal.

DL: http://www.cs.virginia.edu/~yc7a/Publications.htm

Cristina Videira Lopes and Trung Ngo

Unit Testing Aspectual Behavior

Workshop on Testing Aspect-Oriented Programs

DL:http://www.isr.uci.edu/~lopes/documents/wtaop%2005/index.html