Felix M├╝hlenstedt (2) [Avatar] Offline
#1
Hallo Mark and Steve,

thank you for the great work in your first book Dependency Injection in .NET. Already purchased Second Edition which is also really great.

While reading the first book, I already started implementing what I have learned, my colleges joined me also. So most of the code was built like in the book descripted.
Had an WPF application as Client, Presentation Logic, a domain layer and data access (No WCF service).

The domain layer contained the repositories and services interfaces and their implementations, the POCO's for all the objects (e.g. order, products, customers, suppliers).
The Implementation of the repositories are contained in the data access layer.

Since now the company wants to move on, we want to improve our system more. While reading the second book, especially because of chapter 9 and 10, I get more and more confused.

I am not confused about what is written in these chapter. I am more confused how to implement it. What I did was first to split the ever-growing services into one Query service first, and all the commands into single implementations with the generic "ICommandService<TCommand>" interface.

After this I tried also to split up the Queries to single implementations with an interface "IQueryService<TQuery, TResult>" and "IQuery<TResult>". Later I also read about it in a blog from Steve.

First what I am missing is what happened now to the repository interfaces and implementations. Should these also change to SRP.

Then I am getting more confused. In the Listing in chapter 10 and the decorators. Like auditing security, there is no repository injected instead the CommerceContext is directly injected. This confused me because now the domain layer would have again a dependency to the data access layer.

The topic consumer owning the abstraction discussed to separate IService interface and Service implementation. The Discussion didn't mention the repository interfaces. I for my part think that service and repository interface should also be not in the same assembly, am I right?

The last problem I have is with implementation of POCO's, which depends on each other (e.g. order and items). What for me is important is especially an approach with Transaction in mind. So, when something went wrong there is a rollback for the order and all its items. Next to find and inform the right warehouse, inform the billings system when products are ordered, there has to already a change in the disposition within the scope of the transaction.

Thanks and best regards
Felix
Steven van Deursen (40) [Avatar] Offline
#2
Hi,

Sorry for my late response. We've been quite busy getting the book ready for print.

First what I am missing is what happened now to the repository interfaces and implementations. Should these also change to SRP.


That's actually a hard question to answer, because it will typically depend a lot on the system you are building. What I found, however, is that from the query side of things, query handlers (e.g. `IQueryHandler<TQuery, TResult>`) effectively replace the use of repositories. If we look at this from the point of view of an MVC Controller, for instance, you won't find any GET action to use a repository abstraction, they will solely use a query handler.

From a domain's perspective, things might be different though. The logic inside a command handler (which will typically contain domain logic), might still use repository interfaces, although you should definitely be conscious of any maintainability issues that might be caused by wide interfaces, which is something that might happen when you start applying cross-cutting concerns around those abstractions.

In the Listing in chapter 10 and the decorators. Like auditing security, there is no repository injected instead the CommerceContext is directly injected. This confused me because now the domain layer would have again a dependency to the data access layer.


One of the shown command handlers in chapter 10 accidentally depended on CommerceContext. This is an error and will be fixed before we go to print. This is a DIP violation.

Having a decorator depend on the CommerceContext, however, will not be a problem when the decorator is part of the Composition Root. The Composition Root depends on all other modules in the system anyway. If, however, you need to place that decorator in the Domain Layer, you will have to refactor the dependency on CommerceContext, because otherwise the Domain Layer would require a dependency on the Data Access Layer.

I for my part think that service and repository interface should also be not in the same assembly, am I right?


Since it is the Domain layer that uses the repository interfaces, the DIP states that it should own that interface. This typically means placing the interface inside the same assembly. It is possible to place the repository interfaces in a different assembly, but there should be a benefit of doing so. For instance to be able to deploy the Domain Layer and Data Access Layer separately. Deploying the DAL without the DL, however, typically makes no sense, because the DL is the heart of the application, and it is always needed.

The last problem I have is with implementation of POCO's, which depends on each other (e.g. order and items). What for me is important is especially an approach with Transaction in mind. So, when something went wrong there is a rollback for the order and all its items. Next to find and inform the right warehouse, inform the billings system when products are ordered, there has to already a change in the disposition within the scope of the transaction.


For any distributed system, transactional consistency is an illusion. Any time your application needs to communicate with a different system (e.g. billing, warehouse, etc.) you can't really have those systems perform that operation in a single transaction. Doing so would cause a distributed transaction, and this has many negative consequences.

The solution to this problem is Eventual Consistency, which is what chapter 6 is hinting at with its use of Domain Events. When we use Eventual Consistency rather than distributed transactions, any single application in the distributed system will ensure that its data is stored in such way that it won't lose any data, preferably with transactions. For instance, both the publication of the Domain events and the changes to its internal database will be transactional. So what this means is that once the OrderApproved Domain Event is stored in the durable queue (which could be a database table), we will not yet have notified Accounting and Billing, but those systems will *eventually* be notified. When the notification succeeds, the applications will be consistent again.

This whole concept of Eventual Consistency is very important when you start working with either distributed systems or when applying Domain Events. A discussion about this, however, was outside the scope of this book.

I hope this makes sense.




Felix M├╝hlenstedt (2) [Avatar] Offline
#3
Hi,

thank you for your replay. You realy helped me with the first three problems.

Your answer to the fourth problem rised new questions.The Part of using DomainEvents i realy understand and also that these event by theirselfs using transaction.

What I still not really understand is e.g. the CreateOrderCommand and its transaction. This command has to insert data in 2 tables the order with its details and the items of that order.



	public class CreateOrderCommandHandler : ICommandHandler<ApproveOrderCommand>
	{
		private readonly IOrderRepository     orderRepository;
		private readonly IOrderItemRepository orderItemRepository;
		
		public CreateOrderCommandHandler(IOrderRepository orderRepository, IOrderItemRepository orderItemRepository)
		{
			this.orderRepository     = orderRepository;
			this.orderItemRepository = orderItemRepository;
		}
		
		public void Handle(CreateOrderCommand command)
		{
			this.orderRepository.InsertOrder(command.Order);
			foreach(var item in command.OrderItems)
			{
				this.orderItemRepository.InsertOrderItem(item);
			}
		}
	}



If this somehow violates the Single Responsibility Principle the only thing i can imagine is to use an extra layer of abstraction.

Steven van Deursen (40) [Avatar] Offline
#4
I'm unsure why this would violate the SRP, but there are a few things to note here:

- When we look at the concept of Aggregate Roots from DDD, we would only have repositories on the Aggregate Root. Since an Order Line has no use by itself, it is part of the Aggregate of entities, with Order as its Aggregate Root. So it would be up to the OrderRepository to store the order lines as well, and it could do so transactionally.
- Chapter 10 shows how you can apply a transaction around business operations using a TransactionScope. In that case, everything within that scope runs within the same transaction. This solves the problem of having multiple individual updates of your database, or multiple calls to DbContext.SaveChanges.