In my web app I'm tracking view counts on pages.
Right now, the action in the controller issues a command to the data layer to increment the view count on the model before returning the result of the query.
This action seems to break the rules of Command-Query-Separation, since with the request the user agent is submitting a query and unwittingly issuing a command (to increment the view count)
What architectural decisions need to be taken to maintain the Command-Query-Separation in this action?
You should consider CQS relative to the conceptual level of the operation in question. Here are some examples that all seem to violate CQS, but only do so on a different conceptual level:
A ReadFile call on a file system object does not modify the file - but it canupdate the last accessed timestamp on the file.
A FindById call to a repository should not change the database - but it can very well add the queried object to a cache.
A GET operation on a REST API should not change the model - but it can update statistical data.
These examples have one thing in common: They maintain the state of the model the client works on, but they do modify data outside of that model. And this is not a violation of CQS.
Another way to see this is through the principle of least surprise. A client of the above mentioned REST API would not expect the model to change with a GET request, but he doesn't care if the API updates a statistical counter.
Related
What should we do in case when we have UI that's not task based with tasks corresponding to our entity methods which, in turn, correspond to ubiquitous language?
For example, lets say we have a domain model for WorkItem that has properties: StartDate, DueDate, AssignedToEmployeeId, WorkItemType, Title, Description, CreatedbyEmployeeId.
Now, some things can change with the WorkItem and broken down, it boils to methods like:
WorkItem.ReassignToAnotherEmployee(string employeeId)
WorkItem.Postpone(DateTime newDateTime)
WorkItem.ExtendDueDate(DateTime newDueDate)
WorkItem.Describe(string description)
But on our UI side there is just one form with fields corresponding to our properties and a single Save button. So, CRUD UI. Obviously, that leads to have a single CRUD REST API endpoint like PUT domain.com/workitems/{id}.
Question is: how to handle requests that come to this endpoint from the domain model perspective?
OPTION 1
Have CRUD like method WorkItem.Update(...)? (this, obviously, defeats the whole purpose of ubiquitous language and DDD)
OPTION 2
Application service that is called by endpoint controller have method WorkItemsService.Update(...) but within that service we call each one of the domain models methods that correspond to ubiquitous language? something like:
public class WorkItemService {
...
public Update(params) {
WorkItem item = _workItemRepository.get(params.workItemId);
//i am leaving out check for which properties actually changed
//as its not crucial for this example
item.ReassignToAnotherEmployee(params.employeeId);
item.Postpone(params.newDateTime);
item.ExtendDueDate(params.newDueDate);
item.Describe(params.description);
_workItemRepository.save(item);
}
}
Or maybe some third option?
Is there some rule of thumb here?
[UPDATE]
To be clear, question can be rephrased in a way: Should CRUD-like WorkItem.Update() ever become a part of our model even if our domain experts express it in a way we want to be able update a WorkItem or should we always avoid it and go for what does "update" actually mean for the business?
Is your domain/sub-domain inherently CRUD?
"if our domain experts express it in a way we want to be able update a
WorkItem"
If your sub-domain aligns well with CRUD you shouldn't try to force a domain model. CRUD is not an anti-pattern and can actually be the perfect fit for certain sub-domains. CRUD becomes problematic when business experts are expressing rich business processes that are wrongly translated to CRUD UIs & backends by developers, leading to code/UL misalignment.
Note that business processes can also be expensive to discover & model explicitly. Sometimes (e.g. lack of resources) it may be acceptable to let those live in the heads of domain experts. They will drive a simple CRUD UI from paper-based processes as opposed to having the system guide them. CRUD may be perfectly fine here since although processes are complex, we aren't trying to model them in the system which remains simple.
I can't tell whether or not your domain is inherently CRUD, but I just wanted to point out that if it is, then embrace it and go for simpler business logic patterns (Active Record, Transaction Script, etc.). If you find yourself constantly wanting to map every bit of data with a single method call then you may be in a CRUD domain.
Isolate corruption
If you settle that a domain model will benefit your model, then you should stop corruption from spreading through the system as early as you can. This is done with an anti-corruption layer which in your case would be responsible for interpreting CRUD calls and transforming them into more meaningful business processes.
The anti-corruption layer should sit between the parts of the system you want to protect and the legacy/misbehaving/etc part. That would be option #2. In this case the anti-corruption code will most likely have to compare the current state with the new state to try and figure out what changes were done and how to correlate these to more explicit business processes.
Like you said, option 1 is pretty much against the ruleset. Additional offering a generic update is no good to the clients of your domain enitity.
I would go with a 2ish option: having an Application level service but reflecting the UL to it. Your controller would need to call a meaningful application service method with a meaningful parameter/command that changes the state of a Domain model.
I always try to think from the view of a client of my Service/Domain Model Code. As this client i want to know exactly what i call. Having a CRUD like Update is counter intiuitiv and doesn't help you to follow the UL and is more confusing to the clients. They would need to know the code behind that update method to know what they are changing.
To your Update: no don't include a generic update (atleast not with the name Update) always reflect business rules/processes. A client of your code would never know what i does.
In terms if this is a specific business process that gets triggered from a specific controller api endpoint you can call it that way. Let's say your Update is actually the business process DoAWorkItemReassignAndPostponeDueToEmployeeWentOnVacation() then you could bulk this operation but don't go with the generic Update. Always reflect UL.
I have an AngularJS application that is backed by a .NET core CQRS API and MongoDB database. Whilst I know and understand most of the technologies really well, MongoDB and document databases as a whole are new to me and I'm still learning.
The data in its simplest form is a document that can have up to 3 tiers of hierarchy (top level, group level and final node). When the document is first created and inserted into the Mongo database it has no tiers/nodes at all just the high level info like name, author etc. Then afterwards in the UI the user may add any number of new groups and final nodes in those groups.
In a relational database I would simply post the necessary info to the command that would insert the new rows and the command would be called something like 'AddNewGroup'. I wouldn't have to post all the information just the key IDs needed and new information to insert.
However, this approach doesn't seem correct with a Mongo. Am I right in assuming that I should post the whole document and have a single update command that overwrites the existing document in the database? Or is there a better way?
Also should I still break my commands down to the specific kind of updates that are being done e.g. UpdateAuthorName, AddNewGroup etc if the whole document is always being updated.
Your Document is the Write model, the Aggregate in the Domain driven design world. Being CQRS without Event sourcing you need to store the Document state along with the generated events. You also need to protect from concurrent writes. That being said, you have two options:
For each command you update only the nested-document that changed, i.e. the Document's header.
It has the advantage that is fast and the probability of concurrent modification exceptions is lower, if you have separate protection for each document section in place (i.e. a version attribute for each as oppose to a single version for the entire document).
It has the disadvantage that it couples too much the Domain model (class) with the infrastructure, as you need to put the queries inside the Document class. If you mix the Domain with the Infrastructure then you don't have a pure model anymore and you lose the ability to safely retry the command. This can be done outside the Domain class, in the infrastructure, if you "teach" the infrastructure repository to react differently based on the emitted events.
It is also an indication that you have in fact multiple write models, each model for the document's sections (header, body, footer, notes etc), as a write model is dictated by the consistency boundary. In this case they would share the same Document ID though.
For all commands you replace the whole document, no matter what changed inside.
It has the huge advantage that you can have a pure Domain class, with no dependency to the infrastructure whatsoever. The infrastructure just take the whole state and replace the persisted state and append the new events, in the same transaction.
It has the disadvantage that is slower than the first solution. This is the course if you follow the DDD approach, after you identified the Document as an Aggregate (in DDD the Aggregate is fully loaded and fully persisted in response to executing commands).
I m building a website in ASP.NET MVC 4 C#.
Requirement is as follows:
0. Build an order by collecting required details across several pages.
User should be able to navigate back and forth (to check the values entered) before submitting the order finally.
There may be a dependency w.r.t data collected in subsequent pages based on the current selection. For example, if I change the country to which product needs to be shipped, custom duties & taxes applicable in the next page needs to be changed. Hence data in subsequent pages need to be invalidated. If modification to a field does not impact any other data(change in quantities ordered), current selection needs to be persisted.
For scenario 1, I m planning to use Memento pattern. The object will be serialized and persisted in database.
However, I m not sure how to deal with scenario 2. I m sure there would be a design pattern that I can use here. A code sample would be definitely helpful.
Initially I thought of Observer pattern. However, I do not have any subscribers active to be acted on the change.(Values will be saved in DB and will be loaded of next/previous page). Also, we are mostly looking at a single entity of storage here (Field 1 and 2 will be populated on page 1, field 3,4,5 in page2......etc)
I would separate the responsibilities like this for your scenarios:
1. managing the page navigation and interactions
2. awareness of state of the object
Because you are going to have a complex page navigation based on your scenario, I would recommend you to use a Mediator to manage the interaction/communication between pages.
In the other hand you need to somehow manage the state of the object and based on that state you would need to invalidate and take action, so you also would need to have a State pattern.
After this, there is one level upper that has the knowledge about what the scenario is that you can use something like usecase/application controller that manages your scenario using those implemented patterns (Mediator, State).
I'm try to understand Repository pattern to implement it in my app. And I'm stuck with it in a some way.
Here is a simplified algorithm of how the app is accessing to a data:
At first time the app has no data. It needs to connect to a web-service to get this data. So all the low-level logic of interaction with the web-service will be hiding behind the WebServiceRepository class. All the data passed from the web-service to the app will be cached.
Next time when the app will request the data this data will be searched in the cache before requesting them from the web-service. Cache represents itself as a database and XML files and will be accessed through the CacheRepository.
The cached data can be in three states: valid (can be shown to user), invalid (old data that can't be shown) and partly-valid (can be shown but must be updated as soon as possible).
a) If the cached data is valid then after we get them we can stop.
b) If the chached data is invalid or partly-valid we need to access WebServiceRepository. If the access to the web-service is ended with a success then requested data will be cached and then will be showed to user (I think this must be implemented as a second call to the CacheRepository).
c) So the entry point of the data access is the CacheRepository. Web-service will be called only if there is no fully valid cache.
I can't figure out where to place the logic of verifying the cache (valid/invalid/partly-valid)? Where to place the call of the WebServiceRepository? I think that this logic can't be placed in no one of Repositories, because of violation the Single Responsibility Principle (SRP) from SOLID.
Should I implement some sort of RepositoryService and put all the logic in it? Or maybe is there a way to link WebServiceRepository and WebServiceRepository?
What are patterns and approaches to implement that?
Another question is how to get partly-valid data from cache and then request the web-service in the one method's call? I think to use delegates and events. Is there other approaches?
Please, give an advice. Which is the correct way to link all the functionality listed above?
P.S. Maybe I described all a bit confusing. I can give some additional clarifications if needed.
P.P.S. Under CacheRepository (and under WebServiceRepository) I meant a set of repositories - CustomerCacheRepository, ProductCacheRepository and so on. Thanks #hacktick for the comment.
if your webservice gives you crud methods for different entities create a repository for every entityroot.
if there are customers create a CustomerRepository. if there are documents with attachments as childs create a DocumentRepository that returns documents with attachments as a property.
a repository is only responsible for a specific type of entity (ie. customers or documents). repositories are not used for "cross cutting concerns" such as caching. (ie. your example of an CacheRepository)
inject (ie. StuctureMap) a IDataCache instance for every repository.
a call to Repository.GetAll() returns all entities for the current repository. every entity is registered in the cache. note the id of that object in the cache.
a call to Repository.FindById() checks the cache first for the id. if the object is valid return it.
notifications about invalidation of an object is routed to the cache. you could implement client-side invalidation or push messages from the server to the client for example via messagequeues.
information about the status whether an object is currently valid or not should not be stored in the entity object itself but rather only in the cache.
Are non-data classes (that are not representing anything in the database) still considered a part of an application's domain model or not? Would you put them together with your Linq2Sql domain model or somewhere else??
Edit: Info about classes: For example, I have a "StatusMessage" class which is instantiated under certain circumstances, and may be discarded, or displayed to the user. It has nothing to do with data from the database (neither retrieval nor storage). Another example is an "Invitation" class. Users on my site can 'invite' each other, and if they do, an Invitation class is created which will encrypt some information and then output a link that the user can give to someone else. I have >25 of those classes. They are not for data transfer, they do real work, but they are not related to the database, and I wouldn't say they are all 'helpers'?! ....
Domain model is data pertinent to the domain. It can come from any source, could be one way (e.g. calculated and persisted only, and never read back). The database is just one domain data persistence strategy.
So yes the data from different places could be part of the domain model.
Personally I would consider a message to be more of a view model entity, whereas the state indicating the requirement for particular messages could be in the domain model. In the case of the invite I would have said that the message flows through to a service and thus becomes domain data - that is ultimately passed to and I suppose becomes domain data pertinent to the other user (and say displayed using some other view model).
It depends.
If these classes represent a combination of data coming from different tables, process data, take decisions and orchestrate operations, I would consider them business level entities and keep them in the business layer.
If these are some kind of helpers, then it will depend.
ADDED: After having read you extra info on those classes, I think many of them would deserve a rightful place in your business logic. You may wish to draw a line between a domain model and business logic. I suppose you consider you domain model to only contain database mapping classes and that's fine. But then there are also business rules, worker classes that accept user input, process it, take decisions and invoke necessary operations to enact them. These could include CRUDing something to the database, sending email notifications, initiating scheduler tasks, notifying other services etc. For many actions their result will only be distantly reflected in the database, some values may be changed, but not like a complete business object state goes directly to the database. Therefore, it would make sense to keep them together in a dedicated layer.
Another option would be to put the logic of those classes into stored procedures thus persisting it in the database. What doesn't fit there may be grouped together as helpers.
With "StatusMessage", it may not be necessary to have a separate class for that. Messages belong to the view level. A class could just decide on which message to show but then the real display work will take place closer to the UI.