Features vs Services
Moongate should not treat every gameplay change as a standalone top-level subsystem.
This page defines when a new area should become a dedicated Feature and when it should remain a normal Service.
Use a Feature When
Create a dedicated feature area only when the domain is large enough to own its own behavior and boundaries.
Typical signals:
- the domain has its own state or lifecycle
- the domain has more than one integration point
- the domain spans C# code plus
moongate_datascripts or templates - the domain needs dedicated documentation
- the domain is easier to reason about as a named gameplay subsystem
Examples that fit this model:
- plants and gardening
- harvesting
- reputation
- quests
- factions
Use a Service When
Keep the code as a normal service when the responsibility is local and supports a wider domain instead of defining a new one.
Typical signals:
- the code has one narrow responsibility
- the code does not need its own lifecycle
- the code is an implementation detail of another subsystem
- the code does not justify its own docs section
Examples that fit this model:
BandageServiceCombatAccuracyResolverItemFactoryServiceMobileModifierAggregationService
Naming
Prefer Features over Engines.
ModernUO uses Engines mostly as a broad organizational convention, not as a strict runtime contract. Moongate should be stricter and simpler.
Recommended naming:
Moongate.Server.Features.PlantsMoongate.Server.Features.HarvestingMoongate.Server.Features.Reputation
Avoid creating a generic catch-all Engines area for unrelated systems.
Standard Shape for a Feature
When a domain is large enough to become a feature, keep its structure predictable.
Recommended shape:
Interfaces/Services/Data/Types/Internal/
Each feature should also have one clear entrypoint or orchestration layer, for example:
PlantSystemServiceHarvestSystemServiceReputationSystemService
Decision Rule
Before creating a new top-level feature area, ask these questions:
- Does this domain have state or lifecycle of its own?
- Does it integrate with more than one boundary?
- Would a dedicated docs page make sense for it?
- Would grouping it as a named subsystem make the code easier to understand?
If the answer is mostly no, keep it as a service inside the existing domain.
If the answer is mostly yes, a feature boundary is justified.
KISS Rule
Do not promote code into a feature too early.
Most gameplay additions should start as focused services. A feature boundary is justified only when the domain is clearly broader than one service and needs a stable, documented shape.
This keeps Moongate easier to navigate than the looser Engines model used by older UO server codebases.
Previous: Architecture Overview | Next: Network System