Theoretically, whether the data comes from a database or other SOAP/external service doesn't matter, right?
When you consider the data handling algorithm, the method of fetching the data doesn't matter. But that doesn't lead to the conclusion that domain services are part of the domain.
Quite the opposite, in fact. It suggests that the domain shouldn't change just because the source of the (same) data changes, which in turn suggests that the data fetching should be a domain service. Specifically so that the domain doesn't care where the data came from.
accessing data from external service (REST, SOAP, etc.) as part of domain
The fact that you describe it as an external service proves the point that this resource endpoint is not part of the current domain.
Just because your domain has a necessary dependency (i.e. data source) doesn't mean that it personally embodies that dependency. That would violate the basic principle of what a "domain" is.
What matters is if this is a key part of the aggregate, which I believe it is.
Your external resource can map to an aggregate in your domain, or part of aggregate. That's perfectly fine either way.
But your aggregate is not your dependent resource's aggregate (or vice versa), even if they happen to have the same properties. Different domain, different aggregates, regardless of whether you domain is an extension of the other one.
With years of working mostly with relational database for fetching data, I think my brain may be stuck in a pattern that's not really helpful.
My guess is that while the domain service could technically be OK, I could also create a repository that fetches the data from both the database and the external service, building my aggregate (probably using a factory to be safe).
What I think is going on here is that you consider your database repository to not be a domain service, hence why you're arguing your external resource shouldn't be either.
It's the opposite: database repositories are also external services as far as your domain is concerned. Your reasoning then supports itself: since database repositories are domain services, and it doesn't matter where you get the data from, then your other external resources should also be domain services.
My assumption would be I'd need a domain service if whatever I need to do has to involve multiple aggregates, but if not I can keep it within the aggregate itself.
Whether your external data gives you (a) partial/single/multiple aggregate(s) is irrelevant. Taking a simple example:
- Single aggregate: My application fetches all movies from IMDb.
- Partial aggregate: My application fetches the rating for each movie in my database.
- Multiple aggregates: My application serves up a list of actors and/or movies to its end users.
In all cases, my ImdbService
is a domain service. Not because of how much data it supplies me with, but because it is external to my application.
but the fact of the matter is that it needs to be coupled
You're oversimplifying your assumption. It needs to be coupled:
- this exact way
- because that's how the resource does it today
Over time, your external resource is liable to change. Whether it expands its API, refactors it, or plainly goes down and migrates to a new platform; in all cases you're going to have to deal with the changes in the environment.
Even if you/your company manages the external resource, you cannot know what technological advancements we'll achieve in the near future, which could give a solid reason to update the platform to reap its benefits.
The tighter you couple your domain to your external resource, the more difficult and troublesome the implementation of the changes is going to be.
Your argument is definitely not the first time anyone has argued this. But it essentially boils down to cutting a corner today to save on a bit of effort, while glossing over how big the consequences of that cut corner might end up in the future.
Skipping good practice is like not getting insurance. Sure, if nothing bad ever happens then you've saved a bit of money/effort, but are you willing to take the full weight of the consequences when something bad does happen, even if outside of your control?