asatoの技術的な日常日記

「成長に最大の責任をもつ者は、本人であって組織ではない。自らと組織を成長させるためには何に集中すべきかを、自らに問わなければならない」  非営利組織の経営 - ピーター・ドラッカー

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ソフトウェア進化:進化の単位と進化のパターン化

一つ前の記事 では「Javaでのコードの進化のパターン」ということで「列挙型への定数の追加」というのを紹介した。

このパターンは、コードの変化だけを書くならこんな感じで難しくはない。

before:

public enum EnumType {
TypeA,
TypeB
}



after:

public enum EnumType {
TypeA,
TypeB,
TypeC
}




この進化パターンに限らず、三年以上こんな進化パターンを収集し続けてきた僕が悩んでいる問題の一つに 進化の単位 の扱いというのがある。

先ほどの「列挙型への定数の追加」の進化パターン例を考えてみても、これだけで進化が終わるのではない。途中経過に過ぎない。つまり、何らかの要求変化(機能追加や変更など)があったとして、この進化パターンだけでこの要求変化に対応できることはほとんど考えられない。考えられない理由は以下の点のため。
(1)定数の追加の処理の追加ではない
(2)追加した定数を参照するコードを追加していない。

ほとんど したのは、もしかするとリフレクションを用いて列挙型の情報を読み取ってなんとかする場合があるかもしれないため。

とりあえず、言いたいことを図で表すとこうなる。

evo_enum.png

実際には、次の図の場合がほとんどだと思う。

evo_enum2.png



さて、以上のことを踏まえて、今回の記事の本題に戻りたい。ここで、進化単位をどう取り扱えばいいだろう?

いくつかの候補が考えられる。
(1)ある要求の変化を満たすコードの変化

(2)僕の提案している進化パターンのように、要求の変化に関わらない粒度のコード変化

(3)依存するコードの変化。たとえば、クラス名を変更すれば、そのクラスを参照しているコードすべてを変更する必要がある。


そもそも、進化の単位を考えるのがなぜ重要なのかも問わないといけない。進化パターンの文脈で言えば、「列挙型への定数の追加」のレベルで進化のパターンの粒度を扱ってもたいして面白くないということがある。

僕が作っているゲームでの具体例を紹介すると、「列挙型への定数の追加」は次の一連の進化の流れの一ステップにすぎなかった。要求の変化は、新しいゲームモード(正確にはゲームの状態)を追加するというもの。

このゲームでは、ゲームモードという列挙型を定義している(ゲームプログラミングとしてこれが適切な設計なのかは不明)。

(1)列挙定数の追加

public enum GameMode {
TITLE,
OPENING,
MAP_VIEW,
// 省略
LOOK_VIEW // 新規追加
}



(2)ゲームモードに対応するキーハンドラの追加


public class LookViewModeKeyHandler implements GameModeKeyHandler {
//省略
}




(3)キー管理クラスの変更(変更の一部としてメソッドの追加)


public class KeyManager {
//省略
public boolean isLookKeyPressed() {
return isLookKeyPressed;
}


//省略
}



(4)ゲーム状態遷移の変更


public class NormalModeKeyHandler implements GameModeKeyHandler {

public void handleKey(KeyManager keyManager, final GameManager gameManager) {

if (...) {

// 省略

} else if (keyManager.isLookKeyPressed()) {
gameManager.setGameMode(GameMode.LOOK_VIEW);
}

}
}



(5)ゲームモードとキーハンドラの対応付けの追加


public class MainPanel extends JPanel implements Runnable {

// 省略

private Map<GameMode, GameModeKeyHandler> keyHandlers = // ...

private void initKeyHandlers() {

keyHandlers.put(GameMode.TITLE, new TitleModeKeyHandler(titleMenu));
keyHandlers.put(GameMode.OPENING, new OpeningModeKeyHandler(openingMenu));
// 省略
keyHandlers.put(GameMode.LOOK_VIEW, new LookViewModeKeyHandler());
}
// 省略
}




このようなコード進化の流れは大きなパターンとして存在するかもしれない。しかし、以下の点が数ステップからなる進化単位のレベルでパターン化することを困難にする気がする。


(1)パターンとしての信頼性:進化の粒度が多きすぎ、パターンとして信頼できるほど遭遇できるコード進化ではないかもしれない。
evo_pattern.png


(2)抽象化:進化のパターンとして役立つ形で文書化するには、進化のキーとなる側面から抽象化して表現する必要がある。しかし、数ステップからなる進化単位で抽象化することは難しい。
evo_pattern2.png



一方、複数のステップではなく、より粒度の小さい一つのステップ(たとえば「列挙定数の追加」のステップ)だけを進化のパターン化の対象にすれば、

(1)その進化がパターンだと認識できるぐらい実際に遭遇できるかもしれないし、

(2)抽象化もそれほど困難でなくなる。

と考えられる。

evo_pattern3.png


スポンサーサイト

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバックURLはこちら
http://asatohan.blog77.fc2.com/tb.php/77-34ce204c
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。