Why domain driven design?

There are many reasons to simplify domain-driven design for data storage. It’s fun to talk about why I want to promote domain-driven design in my company, because in the old data-driven development approach, which is the traditional multi-tier development architecture, they defined a bunch of Dales to manipulate data in. Net people generally have two ways to use, one is to use ORM like Entity Framework, the other want to use lightweight Mapping tool like Dapper, these are to transform relational data into objects. The result is the following.

Improper use of ORM results in excessive data loading and poor system performance. To solve the performance problem, it would be ugly not to load some navigation properties, but to return the DB Entity to the upper layer, so that some properties of the object are empty, and the upper layer can use this data without knowing when the property has value. So began to use some lightweight data methods, such as using Dapper and then write their own SQL statements, this is a very good way, but most people’s SQL ability is really dare not compliment, most of the SQL statements written, even worse than the statements generated by EnityFramework. , project to do so, I think we should be most of the processing business, how to make the programmer from the data store, model transformation of mire, domain driven design came into my line of sight, of course, the light from the data point of view is not enough to choose domain driven design, with a no database is solved? However, there are some problems with NoSQL, such as how MongoDB can make transactions and data consistency more elegant.

Many of the problems with our software, as we all know, are requirements, that is, customers’ requirements, which are difficult for us to understand accurately. As a result, programmers focus more on “HOW” rather than “WHAT”, and end up working on it for weeks or even longer, with customers saying, “WHAT? ! I told you”, but the customer told me, our understanding is different. For example, a client says, “Great job, I love you!” This Love is definitely not between a man and a woman. What we get is the demand of a customer. What is the context of his Love? If you’re playing basketball, you’re talking about basketball. If you’re playing table tennis, you’re talking about table tennis. In domain-driven design we can get business people more involved in the system, earlier in the system.

Ubiquitous Language Business people use the same Language as we do, and our programs to keep the business as domain-focused as possible, for example, in a traditional data-driven world, if Jack loves Rose, we would write something like this

Userservice. Love(Jack, Rose) but we business people very strange who Love who? Why UserService? If we write it like this

Jack.Love(Rose) and if we use

Company hire (employee) instead

Hire (company,employee) makes it easier to get business people involved, and the code can more easily represent real business scenarios.

Domain driven Design series ii: Domain model

There are a lot of things in domain-driven design that we can apply to a variety of development patterns, so some of the things that follow can be used in part.

When it comes to field-driven fields, people will certainly start to talk about Bounded Context, aggregation and aggregation roots, which will easily confuse people. I think I’ll leave those concepts behind and talk about how to design aggregations, just to keep it simple.

In the past, we defined many models in the multi-level design, the database Entity Model, and then in order to not rely on the database, we designed the business Domain Model, and we designed the ViewModel, which is generally fine, and the responsibilities are very clear. But there are a few problems

We do a lot of model transformations, roll-in, roll-out. Of course, we can use AutoMapper, but the performance of AutoMapper is really difficult to flatter, you can search AutoMapper Performance on the Internet. The domain model becomes a pure DTO. Domain model First, we need to look at the domain, that is, we try to aggregate business into a domain, for example, we want to make a function, you can see the user’s login log every time, that login log actually belongs to the user’s domain.

Secondly, we look at the model. In the past, our models were all attribute only, that is, anemia model, anemia means no behavior, like a mummy. But in fact, the field is the most important place for us to accomplish business.

For example, if there is an Employee whose state is Active, Pending, or DeActive, the Pending state can only be changed to Active.

 public class Employee : Entity
{
    public Name Name { get; set; }
   
    public EmployeeStatus EmployeeStatus { get; set; }}Copy the code

If the Employee model is anaemic, we tend to code as follows

public class EmployeeService : IEmployeeService
{
    private readonly IUnitOfWorkFactory _unitOfWorkFactory;
    private readonly IEmployeeRepository _employeeRepository;

    public EmployeeService(IUnitOfWorkFactory unitOfWorkFactory, IEmployeeRepository employeeRepository)
    {
        _unitOfWorkFactory = unitOfWorkFactory;
        _employeeRepository = employeeRepository;
    }

    public void ChangeStatus(EmployeeStatus status, Guid employeeId)
    {
        using (var unitOfWork = _unitOfWorkFactory.GetCurrentUnitOfWork())
        {
            varemployee = _employeeRepository.GetById(employeeId); employee.EmployeeStatus = status; unitOfWork.Commit(); }}}Copy the code

However, the problem of the above code is that the domain is not autonomous. It is my responsibility to modify my state originally, so can you modify it? It is very dangerous to modify my state arbitrarily outside, for example, the Pending state can only be changed to Active state. So if it’s not an anemic model, we code like this and let the domain manage itself

public class Employee : Entity
{

    public UserId UserId { get; private set; }
    public EmployeeStatus EmployeeStatus { get; private set; }


    public void ChangeStatus(EmployeeStatus status)
    {
        if (this.EmployeeStatus == EmployeeStatus.Pending && status ! = EmployeeStatus.Active) {throw new Exception("Only can Active when status is pending");
        }

        this.EmployeeStatus = status; }}public class EmployeeService : IEmployeeService
{
    private readonly IUnitOfWorkFactory _unitOfWorkFactory;
    private readonly IEmployeeRepository _employeeRepository;

    public EmployeeService(IUnitOfWorkFactory unitOfWorkFactory, IEmployeeRepository employeeRepository)
    {
        _unitOfWorkFactory = unitOfWorkFactory;
        _employeeRepository = employeeRepository;
    }

    public void ChangeStatus(EmployeeStatus status, Guid employeeId)
    {
        using (var unitOfWork = _unitOfWorkFactory.GetCurrentUnitOfWork())
        {
            varemployee = _employeeRepository.GetById(employeeId); employee.ChangeStatus(status); unitOfWork.Commit(); }}}Copy the code

As you can see, we keep the business code in the domain as much as possible to make the domain autonomous.

Postscript In fact, the most difficult aspect of domain-driven design is the AggregateRoot aggregation, which will be discussed later, but I want to make the Domain not anaemic, so that this pattern can be used in traditional multi-layer design, data-driven architecture and so on.

Domain driven design series (4) : event driven

Today I’m going to talk about Event driven, this is not an Event Source in domain-driven design, I’ll talk about that later, but today I’m going to talk about how to decouple with events, and the main reason is that we have a project that has a feature and I think it’s better to use events, so I don’t have to write a blog about it.

Decoupling Speaking of decoupling, we are familiar with layered design, such as relying on abstraction at the top rather than concrete implementation. For example, if one class uses another class, we use the interface instead of directly using the implementation class.

public EquipmentService(IEmailService emailService, IEquipmentRepository equipmentRepository) { _emailService = emailService; _equipmentRepository = equipmentRepository; } why events? SRP (Single responsibility) For example, we have a conference room reservation system, and one of our equipment is broken. We need to inform everyone who booked the meeting room. So we need to send emails.

The pseudocode is as follows

public class EquipmentService { private readonly IEmailService _emailService; private readonly IEquipmentRepository _equipmentRepository;

public EquipmentService(IEmailService emailService, IEquipmentRepository equipmentRepository)
{
    _emailService = emailService;
    _equipmentRepository = equipmentRepository;
}

public void SetEquipmentBroken(string Id)
{
    var equipment = _equipmentRepository.GetById(Id);
    equipment.DeActive();

    _emailService.SendEmail();
}
Copy the code

} However, the question arises, if we later say that we need to change the amount of inventory available if the device breaks, should we change the code here and introduce IInventoryService? Then if the manager says the equipment is broken and you don’t tell me, what are you going to do? Do we need to modify the code to introduce ismsService.info (Manager)? Even if we don’t consider the OCP principle, don’t consider the single responsibility, we programmers will cry, I DeActive a device, you want me to do so many things, how do I know all the functions? I scolded programmers, you do this function why did not consider all!! That’s an important feature that’s been left out.

And the problem, programmers never consider all, so I try to figure out how to solve this programmer not careful problem.

Event-driven because I’m familiar with iOS development, I thought of iOS Notification Center. So I DeActive a device, I only DeActive this device, very SRP right? But how else do you get notified? So the event will naturally pay out of the water. If the device is DeActive, all the program has to do is say, “I DeActive the device,” and you can do whatever you want. Here’s the code.

public void SetEquipmentBroken(string Id) { var equipment = _equipmentRepository.GetById(Id); equipment.DeActive();

    EventBus.Publish(new EquipmentDeActivedEvent {Id = equipment.Id});

}
Copy the code

In this way, the module that notifies conference room reservations will notify, and the module that sends SMS messages to the boss will notify the boss.

Let multiple receivers handle this event. The receivers can be dynamic. In the future, if the owner also wants to know, the code does not need to change.

4 Domain driven design series (4) : event driven

The introduction explained why you should use event-driven, but concepts are not enough, we need code! Remember when Facebook’s boss said: “Talk is cheap, Show me the code!”

An event, as the name suggests, is something that happens, like I’m going to headline, it’s not an event, it’s a Command, HeadCommand, and I’m headline, it’s an event, HeadedEvent, an event is something that has already happened. Okay, so let’s start with a pseudocode

Public void Head() {var NewsPaper = new NewsPaper(); NewsPaper. WriteToHeader (” Mr Wang “);

RaiseEvent(new HeadedEvent {Name = "wang Feng "}); }Copy the code

So we just need RaiseEvent in the code.

So how to subscribe to events is actually very simple, because we want to implement synchronous events, we just need to find all the implementation classes that handle this event, and then call all of them.

public interface IEventHandler where TEvent : Event { void Handle(TEvent e); }

public class HeadedEvent:Event { public string Name { get; set; Chapter}} if the mother pay attention to this Event, we will implement a GuoJiZhangMotherEventHandler

public class GuoJiZhangMotherEventHandler : IEventHandler { public void Handle(HeadedEvent e) { Console.WriteLine(e.Name+”, Are you kidding me?” ); }} We just need to implement another PiMingEventHandler if we care about this event

public class PiMingEventHandler:IEventHandler { public void Handle(HeadedEvent e) { Console.WriteLine(e.Name+”, Guo Ji Zhang is your last wife?” ); }} Look, we can arbitrarily increase the attention to the event code, do not need to modify the original code, the promise of OCP did not lie to you? So the question is, how do the person who sent the event and the person who received the event make contact? In the real world, we all subscribe to the newspaper to read the headlines, but in code we need a coordinator. If so, we need an EventBus. Let’s go to the code

Public void Head() {var NewsPaper = new NewsPaper(); NewsPaper. WriteToHeader (" Mr Wang "); RaiseEvent(new HeadedEvent {Name = "wang Feng "}); } private void RaiseEvent(HeadedEvent HeadedEvent) {EventBus.Publish<HeadedEvent>(new HeadedEvent {Name = "HeadedEvent"}); }Copy the code

EventBus finds all the implementation classes for the Event Handle and calls the corresponding Handle method, which we can easily implement through Castle or any injection framework

public class EventBus { public static void Publish(T concreteEvent) where T: Event { var handlers = _container.ResolveAll<IEventHandler>(); foreach (var handle in handlers) { handle.Handle(concreteEvent); }}} well, elder brother is only responsible for helping Wang teacher on the headlines, after I issued the event notice, who cares who deal with it, my code also need not change.