9. Assembly Definitionを活用する
しかし、namespaceには依存関係を強制する力はありません。usingさえすればアーキテクチャに違反するレイヤーに依存することもできてしまいます。これでは、アーキテクチャはただの口約束で、実際にそのルールが守れていることが保証できません。
そこで登場するのがAssembly Definitionです。Assembly DefinitionはUnityのスクリプトのアセンブリを分割するものです。これを使うと、あるアセンブリが参照できる他のアセンブリを明示的に指定でき、それ以外のアセンブリのクラスは参照できなくなります。つまり、依存関係をコンパイルレベルで強制できるのです。
Assembly Definitionの作成
Assembly DefinitionはUnityエディタの Assets > Create > Assembly Definition から作成できます。各レイヤーに対応するフォルダにasmdefファイルを配置します。
Assets/
├── Scripts/
│ ├── Domain/
│ │ ├── MyGame.Domain.asmdef ←
│ │ ├── ScoreModel.cs
│ │ ├── DamageCalculator.cs
│ │ ├── BattleService.cs
│ │ └── IScoreRepository.cs
│ ├── Application/
│ │ ├── MyGame.Application.asmdef ←
│ │ ├── DefeatEnemyUseCase.cs
│ │ ├── StartGameUseCase.cs
│ │ ├── FinishGameUseCase.cs
│ │ └── IGameOverPort.cs
│ ├── Presentation/
│ │ ├── MyGame.Presentation.asmdef ←
│ │ ├── ScoreView.cs
│ │ ├── ScorePresenter.cs
│ │ └── GameOverPresenter.cs
│ ├── Infrastructure/
│ │ ├── MyGame.Infrastructure.asmdef ←
│ │ └── JsonScoreRepository.cs
│ └── CompositionRoot/
│ ├── MyGame.CompositionRoot.asmdef ←
│ └── GameLifetimeScope.cs依存関係の強制
各asmdefファイルのインスペクターで「Assembly Definition References」を設定することで、そのアセンブリが参照できるアセンブリを制限できます。自分のプロジェクトのアセンブリだけでなく、R3やVContainerなど使用するフレームワークのアセンブリへの参照もここで設定しないと使えません。それくらいAssembly Definitionは強力で、その代わりにどのアセンブリに依存するかは手動で設定しなくてはいけないのです。
この設定により、例えばDomain層のクラスからPresentation層のクラスを参照しようとすると、コンパイルエラーになります。依存性のルール違反を人間のレビューに頼らず、コンパイラが自動的に検出してくれるのです。
csharp
// Domain層のコード
namespace MyGame.Domain
{
// using MyGame.Presentation; ← コンパイルエラー!参照が許可されていない
// asmdefが依存関係を強制してくれる
public class ScoreModel
{
// Presentation層のクラスを使おうとしても使えない。安全!
}
}