asatoの技術的な日常日記

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

スポンサーサイト

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

メモ:進化できるとできないの区別

書きなぐり。後でちゃんと議論したい。思いつつままに書いてる。


カウフマンの「自己組織化と進化の論理」を読んでいて感じたこと。

ソフトウェアが進化できるとできないの区別は何か?


新たな要求に対応することが難しくなったとき、いくつかの対処が考えられると思う。一つは、スクラッチで書き直す。もう一つは、再構造化などをする。もう一つは、そのまま難しいけど、要求に対処する。

スクラッチで書き直す場合、ソフトウェア進化だといえるだろうか?

他の二つは違和感はない。


で、感じたのは、すでにある要求を保ちながら進化する必要があるという前提がありそうなこと。

この前提を破ればどうなるだろう? 

追加しながら進化することはできそうなのに、削除して追加というプロセスがあまり聞かないのはなぜだろう?

モジュラリティはこれにどう影響してるんだろう?

モジュラリティが高ければ、容易に追加できるというのはよくきく。容易に削除できるというのもありそうな話。プロダクトラインとかフィーチャー指向プログラミングとかではそういう観点だと思う。


構造の再構築は、少なくとも、機能要求を保ったまま行われる気がする。構造が変われば、構造の性質(保守性や、性能、モジュラリティ)なども影響が受ける気もする。

要求を満たしたまま、進化させようとするのは何故だ?

もし、あるシステムが10の機能要求からなるとしよう。

そのうちの半分の5個の機能要求を分離できたとして、別々に進化はできるだろうか?

いったん全体として進化(成長)してきたら、もう個別に進化はできないのか?

モジュラリティが高ければ、ここのモジュールは、他に影響することなく進化でやすといわれる。もちろん、インタフェースは保つ必要があると思うけど。


機能5個を実現する構造と、その機能5個+5個を実現する構造は異なる?


機能・非機能要求を保ったまま進化しなければならないのは何故だろう?


10つの要求を満たすためにデザインされた構造があるとする。後に、そのうちから一つの要求を削除する必要が出たとする。で、実際に削除する。このとき、構造は、9つの要求に対して最適なデザインといえるだろうか?

もちろん、何が最適なのかを議論する必要があるとは思う。

でも、たとえば、デザインパターンは、初めから適用しまくるべきではなく、状況にあわせて適切に使っていくべき(Refactoring to Patterns)という議論もある。

アルゴリズムが一つの機能要求を表すとしよう。二つのアルゴリズムをサポートするだけなら、Strategyパターンは必要ないかもしれない。10個のアルゴリズムになったら、必要になる。

その後に、8つのアルゴリズムが不要になったとする。Staretegyパターンをアンリファクタリングするだろうか?

さらに、一つのアルゴリズムだけになったら?

よほどドメインを絞っていない限り、ソフトウェアに要求される機能は増えていくと思う(リーマンの法則に書いてたっけ?)。


でも、フルスクラッチで書き直すこともないかもしれない。コアの部分(フレームワークを想像)はコピペできるかもしれないし、末端のユーティリティクラスなんかは、再利用できる可能性がある。

ユーティリティクラスが、独立して進化していけるのは、直接要求を満たしていないからか?


結局モジュラリティの話?

スポンサーサイト

デザイン:design is an attempt at global optimization with finite resources

単なるメモ程度のもの。

Vinod Goel さんの「Sketches of Thought」という本の256ページには、デザインの一つの側面を次のように書いてる。


This is compatible with a widely held view among designers that design is an attempt at global optimization with finite resources.




本:LNCS Transactions on Pattern Languages of Programming

SEWORLD の 投稿 より。パターン言語の本(ジャーナルかな?)が 出るらしい


Software patterns are a highly effective means of improving the quality of software engineering, system design, and development, and communication among the people building them. Patterns capture the best practices of software design, making them available to all software engineers.

This new LNCS Transactions subline aims to publish papers on patterns and pattern languages as applied to software design, development, and use, throughout all phases of the software life cycle, from requirements and design to implementation, maintenance and evolution. The primary topics of this journal are patterns, pattern collections, and pattern languages themselves, however the LNCS Transactions on Pattern Languages of Programming will also include reviews, survey articles, criticism of patterns and pattern languages, as well as other research on patterns and pattern languages.

In addition to presenting and discussing patterns, this LNCS Transactions aims to present material that is validated -- crucial to the application and advancement of both industry and research. In this spirit, the LNCS Transactions on Pattern Languages of Programming focuses on publications that present patterns, research results and industrial studies that are verifiable. Every paper included here has been reviewed by both patterns experts and domain experts, including researchers and practitioners.



本・デザイン:Sketches of Thought

以前の記事 にちょっとだけメモったけど、工学における設計者が取り組む問題というのは、ill-defined とか ill-structured とかに見なされるらしい。ill-defined とか ill-structured とかの反対の問題は、チェスとかクロスワードとかで、well-defined とか well-structured とかの問題。

そして、ソフトウェア開発における活動というのがほとんどが設計行為であると考えられるとしたら[1]、ill-structured な問題とはどんなものかを理解しておく必要があると思う。

ソフトウェア設計に関わる本では、あまり説明されることが少ない気がするので(気のせいかもしれないけど)、参考になる本としてどんなのがあるのかを知っておく必要があると思う。

Code Complete」では、やっかいな問題(wicked problem)として設計という行為を解説してくれている(90ページ)。

もっと一般的に、工学での設計で説明してくれているのがNigel Cross
さんの「Engineering Design Methods: Strategies for Product Design」の本だと思う。

で、今日は届いた Vinod Goel さんの「Sketches of Thought」という本でも、 ill-structured とか well-structured とかの議論があったので参考になると思ったのであった。


参考:
[1] P. Kruchten, Casting Software Design in the Function-Behavior-Structure Framework, IEEE Software, Vol. 22, No. 2, Mar./Apr., 2005, pp.52-58. ここ からDLできるようです。

プログラミング:プログラマの基礎体力

吉岡さんの「プログラマの基礎体力」というブログ記事の一部に軽く反応。

まず、吉岡さんが次のように疑問を投げかけている(太字と省略は僕による)。

そもそも、プログラマの基礎体力ってなんだろう。学校でアルゴリズムの基礎を習うとか、プログラミング言語を習うとか、あるいはコンピュータの基礎を習うとかそういうことなのだろうか。

断片的な情報を獲得するのなら確かにインターネットや書籍でどうにかなる。しかし、職業プログラマとして一目置かれる存在になるための基礎体力ってなんだろう。

~省略~


そして、最後の結論にはこうある。


プログラマにとっての基礎体力はコードの読解力でそれを強化するのが重要であるというのが、本日のわたしの結論である。


これをもとに、僕の疑問。

(1)職業プログラマかどうかは重要? 

(2)「一目置かれる存在になるための基礎体力」と単なる他の「基礎体力」とは区別している? つまり、「一目置かれる存在になる」ことが目的で、そのための「基礎体力」なるものを議論しようとしているのか? 

(3)そもそも「一目置かれる存在」の定義は?

(4)「職業プログラマとして一目置かれる存在になるための基礎体力」とは何か? に対する結論が「コードの読解力」だとすると、「コードの読解力」があれば、「一目置かれる存在」になれるという話になる。だけど「コードの読解力」がないと「一目置かれる存在」にはなれないのか?

(5)そもそも「基礎体力」の定義がない気がする。その次にじゃあ「基礎体力は具体的に何か」という議論になる気がする。



たとえば、「基礎」という言葉には、次の意味がある。

(1)物事が成立する際に基本となるもの。
「―を固める」
(2)建築物の重量を支え、安定させるために設ける建物の最下部の構造。地形(じぎよう)・礎石・土台など。

Goo辞書より。


一つ目の定義に従うならば、プログラマ(プログラミング)の文脈で「物事が成立」とは何を意味するのか?


などなど疑問に思うのであった。

デザイン:問題の構造化

過去の記事で何度か、デザインとは何かについて考えてみた。デザインの一つの側面は、意思決定ということだった。

「デザインとは何か?」対するGrady Boochの回答
デザイン:Design is a decision-making procedure/process


デザインと意思決定について書かれた論文を少し前に見つけて読んで勉強中なので軽く紹介してみる。この論文は、ソフトウェア設計者に対して彼らが行った意思決定についてインタビューした、という内容。

以下は論文の結論(強調と改行は僕による)。

Conclusion #1 is that software design is primarily about problem structuring.

Conclusion #2 is that the more structured the design problem was, the more the interview subject primarily discussed rational approaches to solve the problem, and the more that naturalistic approaches were facilitators to this discussion.

Conclusion #3 is that the less structured the design problem was, the more the interview subject primarily discussed naturalistic approaches to solving the design problem, and the more that rational approaches were facilitators to this discussion.

Conclusion#4 is that decision makers use either NDM or RDM as the dominant decision making approach but use aspects of the other decision making approach to implement their decision, depending upon the structure of the decision.





C. Zannier, M. Chiasson, F. Maurer

A Model of Design Decision Making based on Empirical Results of Interviews with Software Designers,

A Special Issue of the Journal of Information and Software Technology, p. 637–653, Feb 2007.

DL: http://ebe.cpsc.ucalgary.ca/ebe/index.php/Publications/Home



まだこの論文については勉強中なので、変な疑問しかいえないけど、問題の構造化といった場合、どこまでいうんだろうか? 問題と解が対になっているとすると、直感的には、問題の構造化と解の構造化が存在するように思える。

問題の構造化といえば、マイケル・ジャクソン の「プロブレムフレーム」の本が思い浮かぶ(買ったけどちゃんと読んでないので、今軽く読んでる最中)。論文で言われている構造化とプロブレムフレームの構造化が同じかどうかはわからないけど。

でこの本では、プロブレムフレームとデザインパターンが似ているとしている。似ているというのは「繰り返し発生する状況を特定し記述する」という意味らしい。

たとえば、あるデザインパターンを洗練するとしよう。もっと具体的に言うと、新たな実装方法が見つかったのでそれをパターン記述に加える、という感じ。この場合、解の構造に対する洗練を行ってるんじゃないだろうか? と感じる。

いずれにせよ、論文が言う意味での問題の構造化をきちんと理解しないといけないのかもしれないけど。

デザイン:設計手法

設計手法って何だろう? 手法とかにあまりこだわらない or 気にしない僕なので、今までちゃんと考えたことが無い。

Nikos Salingaros さんの「A Theory of Architecture」という本を読んでいたら、こんなことが書かれていた(強調は僕)。


[...], a design method depends upon the number of solutions it can generate. We are arguing for including all possible design solutions to choose from. [...]



誤読してたらあれだけど、さらに当たり前かもしれないけど、ある設計手法とその他の設計手法の違いの一つは、その手法が生成する解の種類と数だと言えるんじゃないかと思う。

ここでは、簡単のため、あるプログラミング言語を使うとし、設計手法はその言語に依存するとする。

design_method.png


異なる二つの設計手法をもとに、簡単な例で考えたい。

一つ目の手法は、クラスのフィールド(データ)をきちんとカプセル化するという手法。

二つ目の手法は、クラスのフィールドを定義しても、カプセル化するかどうかについては何も言わない手法。


一つ目の手法が生成する解は、例えば次のもの。

public class MyClass {

private int n;

}



一方、二つ目の手法が生成する解は、次の二つ。


public class MyClass {

private int n;

}





public class MyClass {

int n;

}




だから何? という内容かもしれない。では、リファクタリングの役割とはここでは何だといえるだろうか? リファクタリングは設計手法だろうか? 

先ほどの例を使うなら、「フィールドのカプセル化」のリファクタリングをどう解釈できるだろう?


design_method2.png


上の図を見て分かるように、リファクタリングは、異なる設計手法の間をマッピングするような手法であると言えると思う。

もう少し一般的に言えば、ある解からある解へのマッピング手法。同じ設計手法でのマッピングかもしれないし、異なる設計手法でのマッピングかもしれない。


一般的な議論すぎて何も面白くないかもしれない。でも、もし、設計手法によって生成できる解の数と種類が異なるとしたら、どんな設計手法が望ましいだろう?


解の数と種類だけを考えた場合、設計手法の種類としては次の可能性が考えられる。

design_method3.png


5番目は論外だとしても、じゃあ、4番目が一番望ましいのか、という話になるかもしれない(1番から3番と、4番と5番の図を一緒に表したのは間違いかも)。

そもそも、4番は手法ではないといえるかもしれない。

さらに、そもそも、ある手法の間で解の種類と数が異なるのは何故だろう? ということになる。異なるのは、適切な解(その手法の解空間に含まれる解)と適切でない解(その手法の解空間に含まれない解)を区別する、制約やガイドラインがあるためだと考えられる。


とすると、設計手法とは、制約やガイドラインの集合で構成されるといえる。

とすると、ある意味では、細かな構成要素に分解できたことになるので、構成要素を組み合すことで様々な設計手法を再構成できるとも考えられる。


中途半端だけど考察終わり。


本:A Theory of Architecture

建築の本なので、ソフトウェア関係の人はあまり読んでいないかもしれないけど、Nikos Salingaros さんの「A Theory of Architecture」という本が面白い。

Nikos A. Salingaros さんは、パターン言語などで有名な Christopher Alexander と一緒に仕事している仲らしい。

さて、目次だけを見てみても、この本はソフトウェアの人が興味を持つ内容でないかと思う。


Chapter 1. The Laws of Architecture from a Physicist's Perspective

Chapter 2. A Scientific Basis for Creating Architectural Forms

Chapter 3. Hierarchical Cooperation in Architecture: the Mathematical Necessity for Ornament

Chapter 4. The Sensory Value of Ornament

Chapter 5. Life and Complexity in Architecture From a Thermodynamic Analogy

Chapter 6. Architecture, Patterns, and Mathematics

Chapter 7. Pavements as Embodiments of Meaning for a Fractal Mind

Chapter 8. Modularity and the Number of Design Choices

Chapter 9. Geometrical Fundamentalism

Chapter 10. Darwinian Processes and Memes in Architecture: A Memetic Theory of Modernism

Chapter 11. Two Languages for Architecture

Chapter 12. Architectural Memes in a Universe of Information


キーワードの強調は僕の趣味だけど、ソフトウェア設計に興味ある人は、同意してくれる人もいるんじゃないかと思う。

-Patterns
-Modularity
-Design Choices
-Darwinian Processes
-Languages

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

一つ前の記事 では「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


コード進化パターン:列挙型への定数の追加

コード進化パターンを更新。

 Java におけるコード進化パターン

今回は、「列挙型への定数の追加」という単純なパターン。

コードの変化だけを書くなら、これだけ。

before:

public enum EnumType {
TypeA,
TypeB
}



after:

public enum EnumType {
TypeA,
TypeB,
TypeC
}




つまらない例に思えるけど、一つ議論するならば、このパターンが起こらない状況もあるってこと。どんな状況か。

sun の列挙型の例に載っているけど、たとえば、 季節を表す列挙の場合。


enum Season { WINTER, SPRING, SUMMER, FALL }



季節は普通四つしかないので、この列挙型に対する、定数の追加や削除の進化パターンはない。

この季節の例はわかりやすいけど、普通が通用しなくて、さらに進化パターンが許されていない状況もあるかもしれない。しかし、言語レベルで、許されていない進化パターンを制御する仕組みは無い。制御の仕組みがないということは、誤った進化が起こってしまうということ。

プログラミング:Spring-On-Rails

 Spring-On-Rails 1.0 Released (TheServerSide.com)

なんぞこれー。Spring-On-Rails かー。気になるところではある。

プロジェクトページによる説明。

Spring-On-Rails is a rapid Java Enterprise Application development Framework; It is a far distance cusin of Ruby-on-Rails. Spring-On-Rails is design to help developer to generate basic skelton of database CRUD type applications. Generated application is based upon SpringFramework, Ibatis and Hibernate for Java in middle tier.


プログラミング:Groovyでメタプログラミング

Groovyでメタプログラミングのコード例。

 The new meta-programming APIs in Groovy 1.1 beta 3

デザイン:「Design Rules」よりデザインの定義

デザインの定義例の紹介。今回は「Design Rules (日本語版)」という本の冒頭(二ページ目)にある定義というか、「デザインとは何か」の記述の紹介。


[...] Design is the process of inventing objects -- our "things" -- that perform specific functions[1]. These objects, the products of human intelligence and effot, are called "artifacts"[2]

[1] Christopher W. Alexander. Notes on the Synthesis of Form.

[2] Herbert A. Simon. The Sciences of the Artificial.


前回に書いた二つの記事と比べてみるといいかも。
「デザインとは何か?」対するGrady Boochの回答
Design is a decision-making procedure/process


FC2Ad

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