はじめに
今回は、Projucerでディレクトリの並び順を保持できる機能を使って、
依存関係を意識しやすくするTipsについて紹介します。
Projucerの好きなところ
Projucerの好きな点の一つに、
「ファイルやディレクトリの並び順を自由に並べ替え、それを保持できる」
というのがあります。(XcodeなどにExportしてもこの順番は保持される)
自分はこれを利用して依存関係順に並べて開発を行うことが多いです。
ディレクトリの並べ方のルール
基本的な考え方はとてもシンプルです。
- 上にあるファイルやディレクトリほど、他からインクルードされる側
- 下に行くほど、上位層に依存する側
このように「下が上に依存する」というように並べます。
(上下逆順でも...という話もあると思いますがソースコードの中身自体もこの順番で依存関係が存在しているのでこれに合わせています)
例
- (Library or JUCEモジュール、もしくはその予備軍)
- 共通使用される系ディレクトリ
- 音声処理系ディレクトリ
- UI系ディレクトリ
- PluginProcessor.h/.cpp
- PluginEditor.h/.cpp
この場合、以下のルールで行なっています。
- 下側から上側をインクルード、逆の上側から下側にはインクルードしない
- ディレクトリも、ディレクトリ内のファイルもこの順番で並べる
- 依存関係的に同階層の場合は将来的にどのようになりうるかを考慮して決定
(AudioProcessorはUI系ディレクトリについて知らなくて良いはずなので逆順にしてもよいとも思いますが、見やすさなど扱いやすいためこの順番にしています)
(.h/.cppの順番も本来気にすべきですがこちらについてはProjucerでの追加順のままにしてしまいがち...)
メリット
- 分離しやすさ
- 切り分けての確認や修正がやりやすくなる
- 問題発生時に「この層だけ見ればいい」が明確になる
- ドメイン特有でない場合は分離してJUCEモジュールにするなりして他プロジェクトで使いやすくなる
- 切り分けての確認や修正がやりやすくなる
- 依存構造が一目で分かる
- 時間が経ったり、複数人で書いていたとしてもルールを共有していればコードが把握しやすくなる
- PluginEditor・Processor周辺は見やすくても中間層は把握しにくいものですが、この並び順で整理していると一目で関係性が分かる
- Doxygenでも依存関係が見れますが、全体を俯瞰して確認したい場合はこちらのほうが見やすい
- .cpp実装ファイルでのインクルードをしたとしても混乱しない
- 依存関係を気にせず前方宣言なりで無理矢理対応→ファイル間の循環依存が発生してしまった場合に分離が難しい(特に複数ファイル間でこの対応が行われている場合)、という状況を避けられる。
- (妥当な場合はヘッダーで#includeすると唯一設計についてコンパイラがエラー判定してくれる)
- 依存関係を気にせず前方宣言なりで無理矢理対応→ファイル間の循環依存が発生してしまった場合に分離が難しい(特に複数ファイル間でこの対応が行われている場合)、という状況を避けられる。
- 時間が経ったり、複数人で書いていたとしてもルールを共有していればコードが把握しやすくなる
- 常に設計を意識できる
- 責務やこのクラスはどこまで知っている(=依存)するべきか、切り分けて共通使用できるようにすべきか考えるようになり、不必要に大きいクラスは生み出すことが少し減る。
- あとで実装しよう(ほとんどそんなタイミングはこない)を減らせる。
デメリット
- 設計について考える必要があるので少し時間がかかる(良いことだと思いますが勢いで書く時よりかは初動は遅くなります)
+α
- 初期コストは少し上がるが、後々のリファクタや拡張が圧倒的に楽になる
- 逆にある程度膨れ上がったものにこれを適用するよう修正するのはコストが高い場合もあり、できれば最初の方から対応できる場合におすすめ
- スパゲッティコードを紐解いていくときも、同じように可能な範囲で並び順を整えつつ切り分けるのも有効
- (JUCEの1ファイルの長めのサンプルコードを見るときもクラスをファイル分けして並び順を整えると多少見やすくなる)
