Skip to content

Service Classes

Open CraftingService.cs, or HealthSystem.cs, or StatusEffectController.cs, and you will find a large file. That is a deliberate choice rather than an accident, and this page gives you the reasoning instead of leaving you to guess at it.

The short version

The domain model is decomposed. The Unity-facing service sitting on top of it is deliberately one readable file, because the flow it orchestrates is the thing you opened it to understand.


What the large file actually is

Every one of these is a scene component — the MonoBehaviour you drop on an object and wire up in the inspector. None of them is the system itself.

Underneath each sits the domain layer proper, built from ordinary small types with no Unity component among them: Crafting's jobs, recipes, scheduling and results live in Core, and StatusEffects keeps its effects and timing the same way. The folder names differ by system, but the split is the same one every time — the model is separate from the component that drives it.

Above both sits Abstractions, which every system has, and no abstraction depends on a service. IStatusEffectController is the contract; StatusEffectController is one implementation of it that happens to be a MonoBehaviour.

That matters for the obvious question, what if I don't want your service? The answer is not "rewrite the system". The contracts and the model beneath stand on their own.


Why one file rather than six collaborators

A craft runs: preflight → reserve the inputs → escrow → schedule the job → complete → deliver the outputs, with a failure path at every step and a rollback behind most of them.

In one file you read that sequence top to bottom. Split across six collaborating types with interfaces between them, the same sequence costs you six jumps, and the shape of the whole operation ends up in your head rather than on the screen.

The decomposed version is easier to modify. The single-file version is easier to learn. A framework you are meant to read, understand and then build on top of should optimise for the second, and that is the choice made here.

The trade, stated plainly

A large orchestrator is harder to change safely than a set of small collaborators. That cost is real, and we pay it rather than you — which is exactly why the seams underneath it exist for anyone who wants their own.


Close to half of each file is not executable

These files carry an unusual amount of documentation. The XML comments are written for a person reading the code, not to feed an API reference generator: they record why a branch exists, what a method deliberately does not do, and which cases were considered and rejected.

Read CraftChanceSpacePolicy in CraftingService.cs for a representative example — a small enum whose documentation explains how chance outputs are budgeted, why the ceiling is taken per output rather than over their sum, and what the framework does instead when it cannot answer the question properly.

When you are learning a system, that is the part you actually need, and it is the part that would be lost by splitting a file to make it look smaller.


Where they are split, and why there

CraftingService is a partial class. Escrow and the persistence context live in their own files, because those are genuine seams with their own lifecycle and their own reasons to change.

So the size is a boundary decision, not the absence of one. Things are separated where separation buys something. They are kept together where splitting would only scatter one flow across a folder.


This is not a licence for large classes everywhere

The domain layers are made of small files, deliberately. The size lives in exactly one kind of file — the scene component — and that is the one whose entire job is to show you the whole operation at once.

If you would rather write your own

You can, and it is a supported path rather than a workaround. Build against the contracts in Abstractions and drive the domain layer directly; each system's Public API page states exactly what is supported and what may change without a major version.

The service is a convenience with an opinion. Disagreeing with the opinion costs you the convenience, not the system.