We have (roughly) following architecture:
Application service does the infrastructure job - fetches data from repositories which are hidden behind interfaces.
Object graph is created and passed to appropriate domain service.
Domain service does it thing and raises appropriate events.
Events are handled in different application services which perform some persistent operations (altering repositories, sending e-mails etc).
However. Domain service (3) has become so complex that it requires data from different external APIs only if particular conditions are satisfied. For example - if Product X is of type Car, we need to know price of that car model from some external CatalogService (example invented) hidden behind ICatalogService. This operation is potentially expensive one (REST call).
How do we go about this?
A. Do we pre-fetch all data in Application Service listed as (1) even we might not need it? Do we inject interface ICatalogService into given Domain Service and fetch data only when needed? The latter solution might create performance issues if, some other client of Domain Service, calls this Domain Service repeatedly without knowing there is a REST call hidden inside it.
Or did we simply get the domain model wrong?
This question is related to Domain Driven Design.
How do we go about this?
There are two common patterns.
One is to pass the capability to make the query into the domain model, allowing the model to fetch the information itself when it is needed. What this will usually look like is defining an interface / a contract that will be consumed by the domain model, but implemented in the application/infrastructure layers.
The other is to extend the protocol between the domain model and the application, so that we can signal to the application layer what information is needed, and then the application code can decide how to provide it. You end up with something like a state machine for the processes, with the application code coordinating the exchange of information between the external api and the domain model.
If you use a bit of imagination, you've already got a state machine something like this; as your application code is already coordinating the movement of inputs to the repository and the domain model. The difference, of course, is that the existing "state machine" is simple and linear enough that it may not be obvious that there is a state machine present at all.
how exactly would you signal application layer?
Simple queries; which is to say, the application code pulls the information it needs out of the domain model and uses that information to compute the next action. When the action is completed, the application code pushes information to the domain model.
There isn't enough information to give you targeted good advice. I suspect you need to refactor your domains into further subdomains. It sounds like your domain service has way more than 1 responsibility. Keep the service simple.
In addition, If you have a long running task like a service call that takes a long time, then you need to architect it away. The most supple design will not keep the consumer waiting. It'll return immediately with some sort of result to the user even if it's simply a periodic status update.
Related
I've been trying to use Reso Coder's Flutter adaptation of Uncle Bob's Clean Architecture.
My app connects to an API, and most requests (other than logging in) require an authentication token.
Furthermore, upon logging in, user profile information (like a name and profile picture) is received.
I need a way to save this data upon login, and use it in both future API requests and my app's UI.
As I'm new to Uncle Bob's Clean Architecture, I'm not quite sure where this data belongs. Here are the ideas I've come up with, all involving storing the data in a User object:
Store the User in the repository layer, in an authentication feature directory. Other repository-level methods can pass it to the appropriate datasource methods.
This seems to make the most sense; other repository-level methods that call other API calls can use the stored User easily, passing it to methods in the data source layer.
If this is the way to go, I'm not quite sure how other features (that use the API) would access the User - is it okay to have a repository depend on another, and pass the authentication repository to the new feature repository?
Store the User in the repository layer, in an authentication feature directory. Other (non-login) usecases can depend on both this repository and on one relevant to their own feature, passing the User to their repository methods.
This is also breaking the vertical feature barrier, but it may be cleaner then idea 1.
For both these ideas, here's what my repository looks like:
abstract class AuthenticationRepository {
/// The current user.
User get currentUser;
/// True if logged in.
bool get loggedIn;
/// Logs in, saving the [User].
Future<void> login(AuthenticationParams params);
/// Logs out, disposing of the [User].
Future<void> logout();
/// Same as [logout], but logs out of all devices.
Future<void> logoutAll();
/// Retrieves stored login credentials.
Future<AuthenticationParams> retrieveStoredCredentials();
}
Are these ideas "valid", and are there any better ways of doing it?
I see another option to tackle the problem. The solution I want to talk about comes from the domain-driven design and is an event based approach.
In DDD you have the concept of a bounded context. A business object (uncle bob's entity) can have different meanings in different bounded contexts. Take a look at your user business object. The data and methods that some use case uses is often differnt to the data and methods that other use cases use. That's why you have differnt user objects in differnt bounded contexts. They are a kind of perspective that each use case has on the same business object.
If a business object is modified in one bounded context it can emit a business event. Another feature can listen to those events. The event mechanism can either be a simple observer pattern or if you need to distribute your application features via microservices a message queue. In case you use a simple observer patter the event emitter and event handler can run within the same data source transaction. But they can also run in differnt ones. It depends on your needs.
So when the sign-up use case registers a new user it emits a UserSignedUpEvent. Other features can now listen to this event. The event carries the information of the user, like the email, the name, the profile image and other infomration that the user provided during sign-up. Other features can now save the piece of data they need to their own data source. It can be the same as the sign-up use case uses (just other tables or another schema). But it is also possible that is a completely differnt data source, maybe another kind of data source like a nosql db. The part I wrote above about transactions is of course more difficult if you have different data sources.
The main point is that each feature has it's own data and manages it. It might be a copy of the whole user infromation, but in a lot of cases it is only a subset.
The event-based approach can give you perfect modularization. But as it is always when something looks great, it comes at a cost. You have to duplicate some part or even all data. When you think of a microservice architecture and some features are in different microservices it means that the duplication increases the availability of the service. The service can operate even the main service that manages the data is down, because a local copy exists. But now you have to deal with consistency issues - eventual consistency.
At this point I like to stop and guide you to other sources for details:
Chapter 8: Domain Events, Implementing Domain-Driven Desing, Vaughn Vernon
The many meanings of event-driven architectures, Martin Fowler
I am working on a WinForms application using Entity Framework 6 with the following layers:
Presentation
Application
Domain
Infrastructure
When a user clicks the save button from the UI, it calls an application service in the Application layer and passes in the request. The application service then calls a domain service with the request. The domain service calls on an several entities within a domain model to perform validations on data used in the request.
One or more validations in the domain model require information from a repository to determine if data in the request received from the Presentation Layer conforms to certain business rules.
I am considering two options to address this.
Have the Application Service retrieve the information needed from
the repositories for validation and pass those values into the
Domain Service which will call on the domain model and entities to
validate the incoming request for rules and values. Then let the
Application Service save the request when the Domain Service has
finished its validations, which will result in returning control
back to the Application Service which was synchronously waiting for
completion of validations. If I do this, then the domain layer will
have no direct or indirect (injected) reference to the repositories.
Unit testing of the Domain Service will be easier if I do this
because nothing is injected into it to perform validations.
Everything it needs is already passed in. The drawback is that some
business knowledge is put into the Application Service because now
it needs to know which repository information to retrieve for
validations of a request.
When calling the domain service for validation of the request,
inject an instance of the Application Service into it. The Domain
Service can then get information from the repository using the
injected Application Service, whose service contract is defined in
the Domain Layer. Once all the information is available it is passed
as needed to various entities to validate rules and values. Once
validation is completed, the Domain Service saves the request using
the injected Application Service. When the Domain Service is done
and exits, it returns the status of the save operation to the
Application Service which has been waiting for validation to
complete. The outer waiting application service can then return the
results of the save to the UI. One concern I have here is that when
unit testing the Domain Service I will have to mock the injected
Application Service.
Which option or other course of action would work out better? Thanks in advance.
"Should An Application Service Be Injected Into A Domain Service"
No, never!
Resolving the data from the application service and passing it to the domain service is usually fine, but if you think that domain logic is leaking then
you can apply the Interface Segregation Principle (ISP) and define an interface in the domain based on what contract is required to query for the "wanted data". Implement that interface on your repository or any other object that can fulfill the task and inject it into your domain service.
E.g. (pseudo-code)
//domain
public interface WantedDataProvider {
public WantedData findWantedData(...) {}
}
public class SomeDomainService {
WantedDataProvider wantedDataProvider;
}
//infrastructure
public class SomeRepository implements WantedDataProvider {
public WantedData findWantedData(...) {
//implementation
}
}
EDIT:
I have a request aggregate root with an employee name. One rule is the
employee must be full time and not a contractor
If the information to perform the validation already exists on an aggregate, you may also use this AR as a factory for other ARs. Assuming an employee holds it's contract type...
Employee employee = employeeRepository.findById(employeeId);
Request request = employee.submitRequest(requestDetails); //throws if not full time
requestRepository.add(request);
Note that the invariant can only be made eventually consistent here, unless you change your aggregate boundaries, but it's the same with the other solutions.
When a significant process or transformation in the domain is not a natural responsibility of an Entity or Value Object, add an operation to the model as a standalone interface declared as a Service. Define the interface in terms of the language of the model and make sure the operation name is part of the Ubiquitous Language. Make the Service stateless - Evans, the Blue Book
Don't lean to heavily toward modelling a domain concept as a Service. Do so only if the circumstances fit. If we aren't careful,, we might start to treat Services as our modelling "silver bullet". Using Services overzealously will usually result in the negative consequences of creating an Anemnic Domain Model, where all the domain logic resides in Services. - Vernon, the Red Book
What I am trying to tell by extensive citing, is that you seems to see Domain Services as something you MUST have where you absolutely don't have to do it. Your application services can happily use repositories to fetch the aggregate and then call the aggregate root method to perform necessary operations. Your aggregate root is responsible to protect its own invariants by executing necessary validations inside it and throw validation exception if anything should go wrong.
In case you absolutely must use a domain service, if you are doing it right, meaning you implement onion architecture, where inner layers do not know about outer layers, your domain service won't be able to know about the application service. However, you can, if you absolutely have to, send a delegate into the domain service to do something that the application service desires. However, this scenario is too complex to be true. Seeing that you only require the validation, please read the cited parts of the blue and red books and make the right decision. Again, there is no mandatory domain service in DDD, this is one of common misconceptions.
In the last days I spent a lot of time creating the architecture for my program, but still have a problem with it. At the moment it looks like this:
DataLayer: Here my context class which derived from DbContext and the mapper classes which derived from EntityTypeConfiguration like JobMap for the Domain objects reside
DomainLayer: Here my domain/business objects like Job or Schedule reside.
Presentation Layer: Here I have the *ViewModel and *View classes (I use WPF for the views)
Now to my question: I want to build a scheduling application with some optimization abilities (it is a single user and single pc application so no further decoupling like web application is needed). But I have the problem that I don't know where this application fits into this architecture?
Considering the following use case: The user clicks a button "Start" on the View which calls the ViewModel which redirects to my scheduling/optimization application. This app then gets all the new jobs from the database and creates/updates the current schedule. The ViewModel should then update the old schedule with the new created one. Finally the View shows the generated schedule to the user.
In this case my ViewModel knows about my application (because it calls it) and about my domain/business objects (because my app will deliver e.g. a Schedule domain object, which the ViewModel encapsulates).
Is this a correct usage of the EF, MVVM and my application?
Regards
To start, you'll want to identify which pieces of your application go where, and that's fairly easy to do. Essentially, you have to ask yourself: Does this method or class help define my domain. If the answer is yes, you put it in the domain layer, and if not, you'll put it in presentation.
Here's how you'd look at it in your example:
Your Presentation layer (PL) receives a message via the start
button.
The PL calls the Domain and tells it to generate a schedule. This call is probably to a domain service.
Your domain service is then in charge of populating the Job domain objects, creating a new Schedule domain object (or modifying an existing one), and returning the Schedule domain object.
Your PL then simply displays the returned Schedule.
This might be different if you just wanted to obtain an existing Schedule object. Instead of calling a domain service, you would ask a domain repository to get the existing schedule. The repository would be the way of encapsulating or otherwise obscuring the data layer from your PL and from your Domain.
Now, what you DON'T want to do:
Do not get the list of jobs in your PL, and then use that list of jobs to create the schedule in the controller of your MVVM. This would be business logic that defines your domain.
If Schedules are commonly generated from Jobs, regardless of whether it's called from MVVM or a PHP site, then don't add complexity in your PL and Domain Layer by forcing the PL to first get the jobs and pass them back into the Domain for a Schedule to be generated. The fact that those two concepts are tied to each other means that the relationship helps define your domain, and thus belongs in your domain layer. An exception might be when both the jobs and the schedule to be modified both rely on context from the front end (user input), but even this isn't always an exception.
Do not pass in VMs to your domain. Let your controller filter out the data and determine what needs to be sent to which domain part.
It's really hard to give a precise detail of what you should place where because only you would have a clear view of what defines your domain, but here's essentially how I break it down:
Could I change/replace this without affecting how my business/domain works?
If the answer is yes, it does not belong in your domain. Example: You could replace your entire MVVM front-end to flat PHP or ASPX, and even though it'd be a lot of work and a huge pain, you could to do it without affecting how the rest of the business operates.
This has happend to me more than once, thought someone can give some insight.
I have worked on multiple projects where my project depends on external service. When I have to run the application locally, i would need that service to be up. But sometimes I would be coding to the next version of their service which may not be ready.
So the question is, is there already a way that can have a mock service up and running that i could configure with some request and responses?
For example, lets say that I have a local application that needs to make a rest call to some other service outside to obtain some data. E.g, say, for given a user, i need to find all pending shipments which would come from other service. But I dont have access to that service.
In order to run my application, i need a working external service but I dont have access to it in my environment. Is there a better way rather than having to create a fake service?
You should separate the communications concerns from your business logic (something I call "Edge Component" see here and here).
For one it will let you test the business logic by itself. It will also give you the opportunity to rethink the temporal coupling you currently have. e.g. you may want the layer that handle communications to pre-fetch, cache etc. data from other services so that you will also have more resilient services at run time
I'm trying to get my head around mvvm and came up with a test application that I think will give me a good foundation. Suppose my application has a service that goes out every minute and gets the latest flight arrival and departure information at an airport. Now suppose I have 3 different views: InboundView, OutboundView and GateView. The Inbound and Outbound views would simply display the various flight details for inbound and outbound flights that I'm sure we've all seen on the flight boards in the airport. The GateView would display similar flight information but might be sorted by gate # instead of flight #.
So the model for the Flight object would contain the flight data details as well as an instance of a Gate object that would be updated appropriately once a flight arrives.
So all 3 views are using the same flight data service and I know I can pass an instance of that service to each VM but then I'd need to hook up the appropriate INPC events at each view model and that seems less than ideal as the number of views/vms increases.
Right now, each VM uses a ListCollectionView wrapped around the passed in collection of flight data and I just sort/filter based on inbound/outbound, etc.. but I was hoping to incorporate the service results into a sort of parent view model that would then pass a reference to itself along to the sub-views and then I could just handle all the INPC, etc.. events at the parent view model level and those will automatically trickle down to each of the subviews if data on a particular flight changes (such as its gate) instead of having to handle that separately in each of the VMs.
I've looked into the Messenger framework for MVVM Light but it still seems like each of the sub-VMs would have to register for the message and respond to it individually.
Does that make sense? Am I on the right track here?
So all 3 views are using the same flight data service and I know I can pass an instance of that service to each VM but then I'd need to hook up the appropriate INPC events at each view model and that seems less than ideal as the number of views/vms increases.
You don't necessarily have to do this, if the "service" implements INotifyPropertyChanged. Remember, you can bind to a property within a property, ie: {Binding Path=FlightService.Gate} or whatever, which may work. (It's difficult to know your requirements here, though.)
I've looked into the Messenger framework for MVVM Light but it still seems like each of the sub-VMs would have to register for the message and respond to it individually.
Yes, if you wanted to use a messaging framework, you would need this to be handled in each of the ViewModels. Alternatively, you could use some form of service location or constructor injection to "pull in" the flight service. The latter is my personal preference here.
The advantage of handling this in each VM is that each VM will likely want to handle things somewhat differently (otherwise, why is there more than 1?). By pulling a reference to the service in via IoC, you can handle this anyway you need to.