Summary
If a capability exists only inside the caller that first needed it, the company will pay to rediscover it at every new surface. Services give durable ownership to behavior that must survive across APIs, jobs, UI workflows, and agents.
Problem
Direct access can feel efficient: let a route query a table, let a job call the provider, let the UI assemble the result it needs. But those callers see only their local transaction. They tend to reproduce policy, scope, failure handling, and provider assumptions in slightly different forms.
The result is not flexibility. It is a coordination problem inside the codebase. No single boundary can answer what the capability means, which rules it enforces, or how its failures should be repaired.
Principle
Put reusable behavior behind service functions, classes, or packages with clear ownership. Callers should request an outcome from the domain, not orchestrate tables or provider clients themselves.
Platform Shape
The service layer owns capabilities with persistence, state transitions, or orchestration behind them. The service-category reference distinguishes operational state machines, lakehouse and data services, execution services, operations support, shared capabilities, bounded domains, and domain job helpers. The categories are not taxonomy for its own sake. They identify where a behavior belongs and who must preserve its contract.
A useful service can change its repository or provider adapter without forcing every caller to learn the new shape. It also gives human and agent surfaces the same governed action instead of parallel implementations.
Tradeoffs
Services can become vague dumping grounds if their capabilities are named too broadly or their ownership is unclear. A service boundary earns its place when it expresses domain behavior, not when it merely renames a database operation.