プログラムや、プログラムを作るための部品は「プロジェクト」という単位で管理します。
ここでは、プロジェクトという単位に分ける動機などについて説明していきます。
概要
プロジェクト管理で触れたように、プログラムや、プログラムを作るための部品は「プロジェクト」という単位で管理します。
- 依存関係を考える最小単位がプロジェクト
- .NETの場合、プロジェクトの成果物は「アセンブリ」(dllもしくはexe)
- いろんなプログラム、いろんな環境で使える部分を別プロジェクトに切り出して使う
依存関係
プログラムをちゃんと部品として分けて作って、その部品をいろんなプログラムから再利用するためには、依存関係の整理が必要です。
依存関係(dependecy)について説明するために、まずはクラスの依存について考えてみます。例えば、以下の図のようなコードを見てください。
図中の矢印が「依存」です。あるクラスが別のクラスから使われているという状態。
この例は、ゲームでよくありそうなデータ構造です。
- 各ユーザー(
User
)が、ユニット(Unit
)を複数持っていて、1つの同盟(Alliance
)に入っている。 - 各同盟には複数のユーザー(
User
)がメンバーとして含まれている。 - 各ユニットは装備品(
Equipment
)を複数装備している。
今回の場合、1クラス1ファイルで分けているので、ソースコード ファイル的にも以下のような依存関係があります。
この関係からは、以下のようなことが言えます。
Equipment.cs
は単体で切り出せる。Unit.cs
を使うにはEquipment.cs
もセットで必要。User.cs
を使おうとすると、芋づる式にAlliance.cs
、Unit.cs
、Equipment.cs
すべてが必要。User.cs
とAlliance.cs
は相互依存していて、絶対に切り離せない。
このように、依存関係を整理することによって、「何かを抜き出して使うには別の何かが必要になる」というような状況が見えてきます。
補足: .NETのソースコード ファイル配置
(C#を含め).NETでは、.cs
ファイルなどのソースコードと、クラス、メソッドなどのC#文法構成要素との間に何の制約もありません。A.cs
というファイルにB
というクラスがあっても構いません。「クラスの分割定義」ができるので、複数のファイルにわたって1つのクラスを書くこともできます。
(他の言語だと、ファイル名を使って参照解決したり、ファイル名とクラス名が同じでないといけないという制約があったりするものもあります。)
ただ、一般的に推奨される方針としては、名前空間と同じフォルダー階層の下に、クラス名と同じ名前の.cs
ファイルを作る方がよいとされています。
プロジェクト
これまでファイル単位で説明してきましたが、クラスやファイルという単位は細かすぎて、依存管理には不向きです(管理しきれない)。もう少し大きな単位で区切る必要があって、これが「プロジェクト」を作る動機です。
プロジェクト内のファイルやクラスに関しては、依存関係をあまり気にする必要はありません。仕組み上は、どれだけ複雑な依存関係を持っていても構いません。
(ただし、もちろん、「最初は1つのプロジェクトとして作ってしまったけども、この部分は汎用的に使えそうだから抜き出して別プロジェクトにしよう」というようなこともよくあるので、プロジェクト内であっても依存関係には気をつけておいた方が後々よい結果になることはあります。)
一方で、プロジェクト間の依存関係はきちんと考えないと行けません。ここをサボると、何かを抜き出して使いたい時に、芋づる式にいろいろなものが必要になって困ることがあります。必要な物が増える事による問題の例をいくつか挙げると、以下のようなものがあります。
- 必要なコードが増えて、最終的なプログラムのサイズが肥大化する
- 依存先がアップデートされたときの追従が大変になる
- 動かせないリスク、例えば、「Windowsプログラムで今まで動いていたコードをiOSアプリで使いたい」とか言う時に動かせない可能性が高まる(依存先すべてがiOS実行に対応していないと行けない)
プロジェクトの成果物
プロジェクト内のファイルは個別に切り出して使うことをあまり想定しません。プロジェクトというものが、プログラム、あるいは、プログラムを作るための部品の最小単位です。そのため、プロジェクトによって得られる成果物は、1つのファイルにまとめたりします。
C#など、.NET言語の場合は、複数のソースコードのコンパイル結果を最初から1つのファイルにまとめて出力します。(他のプログラミング言語では、バラバラに出力されたコンパイル結果を ZIP 形式ファイルなどにまとめたりするものもあります。) 出力されるファイルは以下のいずれかです。
- ライブラリ … 単体で実行できない。他のプログラムから参照して使う部品。拡張子dll(dymamic link library。dymamicとかlinkとかの言葉の意味はまた別の機会に)。
- 実行可能ファイル … 単体で実行できるプ プログラム。拡張子exe。
.NET の場合、dllでもexeでも中身はほとんど同じ(exeの方にはプログラムの開始地点の情報が多い程度)です。これらは合わせて、アセンブリ(assembly: (組み立て)部品)といいます。
プロジェクトの分け方
プロジェクトを分ける(プログラムを部品化する)1番の動機は、いろんなプログラム、いろんな環境から使いたいというものです。
いろんなプログラムから1つの部品を使う
最初にゲームっぽい例を出したついでですし、ここでもゲームを作ることを考えましょう。
今どきはどんなゲームもオンラインでつながっています。ゲーム本体と同じコードをサーバー側で共有したいことも多いでしょう。また、ゲーム自体のプログラムの他にも、テスト用や、企画者向けのプログラムが必要になったりします。
- ゲーム本体 … ゲーム専用ハードウェア上で動かしたりします。今どきだとiPhoneやAndroid向けも多いです。
- ゲーム サーバー … 複数のプレイヤー間でゲーム本体からのデータを中継するだけの簡単なものから、ゲームの核となる処理がすべてサーバー上で動いている場合まであります。
- テスト用プログラム … ゲーム中の特定の部位だけを抜き出して、そこを重点的にデバッグしたりすることがあります。
- 企画者向けツール … ゲーム中のデータを作ったりバランス調整したりするため、開発者以外の人でも動作を確認しつつデータを編集できるツールが必要になります。
こういう場合、このいずれからも使う部分を別プロジェクトに切り出して、全部から参照して使います。
いろんな環境から1つの部品を使う
Windowsに限って言っても、組み込み製品、デスクトップ、サーバー、ゲーム機など、要件の異なるいろいろな機器の上で動きます。スマホやタブレットでいうと、iOSやAndroidとシェアが分かれていて、そのどちらにも対応したプログラムを書く必要がある場面は多いです。そして、こういう環境が変わると、使える機能(参照できるアセンブリ)が違ってきます。
こういう場合、環境によらず共通して使える部分と、それぞれの環境に応じた(それぞれの専用のフレームワークに依存した)部分に分かれます。