「システムの共通化」とは
読み返せば読み返すほど駄文なんですが、さらすことで何かしら効果があれば。。
一応社内向けに書く文書の草稿レベルです。かなり初心者も意識して書いています。
今やっている仕事はWindowsベースのwebサイト構築(aspとaspx混在環境)が主で、その中で、「システムを共通化しよう」という話が持ち上がり、考え始めたら眠れなくなり、一気に書いてすっきりしてから寝ようと思い書きなぐりました。
Fさんが「共通化できそうな関数を見つければいいじゃん」と言いました。おそらくFさんが前提としているのはasp(vbscript)の共通と思われる部分を一つのfunction、subにまとめましょう、という話でしょう。メンテも楽だし、と。
確かに、現在稼働中のサイトでもJavascript、CSSは共通で使用する部分は共通フォルダに格納してそれを参照することで共通化、メンテナンス性の向上が図られていると思います。実際その方向性は正しいと思います。
vbs(vbscript)の共通化、つまりfunctionにまとめる場合、欠点としてはfunction自体が肥大化してしまうおそれがあること。
長い関数(function)はそれ自体がメンテナンスの困難さを発生させます。(個人的には9ポイントでA4縦でプリントアウトして1枚に収まらなかったら長いなー、と感じる。)
長い関数を避けるにはどうするかというと「分割する」。元々function A()があった場合、その中身をB、C、Dに分割して、AからB、C、Dを呼ぶ。またはAがBをBがCをCがDを呼ぶような作りにする。しかしここで最大の問題が発生する。それは何か?
本来B、C、DはAからしか呼ばれないことを前提としているのだが、別の関数や、aspが複数のvbsファイルをインクルードしている場合は他のファイルからB、C、Dを呼ぶことが可能になってしまうのである。それにより想定外の動きをすることがある。また、別の開発者から見れば、B、C、Dって何の関数なんだ?どこで使うんだよ?と戸惑うことになる。
仮にB、C、Dにコメントで「この関数はAからしか呼ばない前提で作っています。ほかの方は使わないように」と書いてもいまいちである。(さらにたちの悪いことに、こういうのが「ルール化」だと思っている節もあり困ったものです。
つまり、vbsという言語にはprivateスコープが無い、という言語仕様がもたらす弊害です。よってvbsベースで「共通化」を考える場合、上記の前提をふまえることが必要。
(まさにこれを克服するための言語がオブジェクト指向言語な訳ですが)
ここで視点を変えて徐々に「システム」を俯瞰していきましょう。(Google Mapsでたとえるならlv=1からlv=15くらいまで徐々に)
話が多少ごっちゃになっていますが。.netも前提なしに入れ込みます。(このごちゃごちゃ具合を各自整理していただければ・・・他人任せモード。。)
ステートメント(変数の宣言、代入、ループ、if文による分岐)
↓まとめる
サブルーチン(function、sub)
↓
クラス(class)
function、変数の集合体
↓
物理的ファイル(.asp、.inc、.js、aspx、aspx.cs、cs)
csなどの場合は1ファイルに複数クラスが含まれる場合が多い。(ちなみにActionScriptは1クラス1ファイル。Javaも?忘れた。。)
↓
モジュール、ライブラリ
結構定義が曖昧。一般的にはある一定の機能を満たす一つ、または複数ファイルの集合体か。(例:Javascriptの「script.aculo.us」というライブラリは複数のjsファイルから成る。)
↓
プロジェクト
.NET独自。複数のaspx、aspx.cs、csなどから成る。コンパイルすることで複数のaspx.cs、csから1dll(アセンブリ)ができる。aspxは元のまま。複数aspxのまま。
↓
ソリューション
.NET独自。複数のプロジェクトから成る。よってコンパイルすると複数dll(アセンブリ)ができる。
一般にはこの単位を「サブシステム」と呼ぶことが多いのではないか。
↓
サブシステム
各業務(検索、予約、管理、など)の粒度と一致するか。プログラム的にはaspx、アセンブリの集合体。
↓
システム
「サイト全体」と思っていただければ。各サブシステムの集合体でもあるわけで、その連携にはwebサービス(API)や、アセンブリの参照(別ソリューションのアセンブリを参照するにはGAC(Global Assembly Cache)に登録しておく必要がある)
という風に「システム」をとらえています。だから、「システムの共通化」と言った場合に、「え?どこの?」と思ってしまうわけです。
このようにシステムは多層構造を成している。さらにその上部には人的要素、組織システムや、組織間の連携など社会的システムもあるわけですが今回は割愛。
ここで急にズームインしてコードレベルに話を戻します。
「コードの共通化」
同じ働きをするものを一つにまとめる。
オブジェクト指向的言語風に言えば、基底クラスを作ってそこに共通部分を置く。そして異なる部分は派生クラスで実装する、と言うのが教科書的回答。
オブジェクト指向的設計(言語ではなく設計)論的に言えば、共通化というか一カ所にまとめることは必ずしも正しいアプローチではなく、大事なのは「的確にクラスに責務を割り当てること」だと言われています。それぞれのクラスが自分の役割をしっかり内包して各個が「自律分散的に協調して動く」これが理想です。
かといって各自が勝手にプログラムを0から組むのは非効率ですし、「車輪の再発明」と言われる現象を招きます。何度もプログラムを作っているうちに、あれ?これ以前にもやったことあるぞ、ということが増えてきます。そこで出てきたのが「デザインパターン」という考え方です。「アルゴリズム」よりは粒度大きめで、複数クラスの組み合わせレベルで同じような仕事に対して名前を付けたものです。(GoFの23パターンが有名)
しかし、実装レベルでは10年くらい前から、基底クラスをあらかじめきっちり決めるのは難しく、要件変更時の基底クラスの変更のあたりがとても大きく問題となっています。
GoFの本でもこの点は指摘されており、「継承よりも委譲(コンポジション)を使え」と何度も書かれています。
実はそれもC++と言う言語に縛られた考えかたで、その後に出てきたJava、C#には「インターフェース」という言語仕様があります。これにより、より柔軟な継承構造をとることができ、実際インターフェースを基本にしてデザインパターンの書き直しも行われています。
さらにC#、Javaの1.5以降では、AOP(アスペクト指向的)な、「属性」「アノテーション」という言語仕様が組み込まれており、クラス自体に影響を与えずに機能を横串的に増やすことができます。
と言うようにソースコードレベルの「共通化」でもこのくらい思いつきます。
おそらく各レベルにおいてこのくらい考えるべきことがあると思います
さらに各レベルは独立しているわけではなく、依存、協調、影響しあっています。依存度は減らした方がいいのですが、それが「共通化」なのかと考え始めるとずいぶんと遠くまで来たもんだ、という気になります。。
「依存」「協調」という視点でもう一度俯瞰していきましょう。
vbs(asp)の場合
同一ファイル内でfunctionがfunctionを呼び出す
↓
あるファイルが別ファイルのfunctionを呼び出す。
.NETの場合
同一プロジェクト内でクラスのメソッド、プロパティにアクセスする。
スコープによりアクセス可不可が異なる。
・private:同一クラスからのみアクセス可能
・protected:派生クラスからのみアクセス可能(基底クラスが別ファイルにあっても可能。たぶん)
・public:別のクラスからアクセス可能
・property:publicと同じく他のクラスからアクセス可能
↓
同一ソリューションから別プロジェクトのクラスにアクセスする
参照設定(プロジェクトの参照?)で別プロジェクトのアセンブリを参照しておく。さらにusing句をつけてアクセスしやすくする場合が多い。
↓
別ソリューションからアクセスしたい
・参照設定(アセンブリの参照)で参照する。参照される側はあらかじめGACに登録されて無くてはならない(GACに登録せずに直接参照もありなんでしたっけ?)
↓
別のマシン(イントラ内)からアクセスしたい
.net Remotingという分散コンピューティング技術を使う
↓
別のサイト(インターネットの世界)越しにアクセスしたい
webサービス(REST、SOAP)を使う
など。矢印が進むごとに依存性は弱くなります。
少なくとも自分の頭の中ではシステムとはこのような構造になっています。
あ、さらにシステム外と思われているかもしれない部分に関して。
上記の長いシステムの説明も時間軸的に見れば静的なものです。とある時間で切り取った平面にすぎません。
時間を考慮すると、このシステムができあがるまでの過程(分析→設計→実装)とできあがってからの動き(運用、仕様変更に伴う再開発)があります。
できあがるまでの過程を考えると、社内では「ユーザ要件」「システム要件」という単語がよく使われますが自分では未だに理解できないので、というかサイトの構築に当たってはこの分け方は厳しいのではないかと思っていて。
一般的な、分析、設計、実装の3フェーズで考えます。忘れてはならないことは、インターネットのサイトの構築なので、デザイン、サイトマップ、ワイヤーフレームといった、上記では全くふれなかったものを考慮しなければならないこと。
要するにやりたいことは「制作、開発におけるワークフローの認識あわせ、共通化」な訳ですが。これがとても重要だと考えています。
例えば、分析、設計の前段階の時点は「ユーザ要件」と言われシステムの人は関わらないことが多いですが、実はデータベースのフィールドの構成まで知らないと分析、情報設計に漏れが生じる可能性があったりするわけです。
極端な例だと、CSSでBackground に画像を入れ込む場合、その画像のパスはCSSを読み込むasp、aspxと画像を保管するフォルダの相対関係が決まっていないといけないわけで、CSSを外注する場合、その以前に物理的なフォルダ構成(仮想ディレクトリとか)が決まっていないとダメだったり。それが漏れたために手戻りが発生したり。
つまり、「開発の進め方の共通化」も重要であると考えます。
いまどきウォーターフォールもないだろう、と思います。かといってアジャイル、XP、RUPにいきなり移行するのも難しいと考えています。ですのでこれは自分では答えがないけど考えなければならない重要項目です。
以上。おやすみなさい。