Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write functionality using DDD / CQRS

I have a bank account domain as listed below. There can be SavingsAccount, LoanAccount, FixedAccount and so on. One user can have multiple accounts. I need to add a new functionality – get all accounts for a user. Where should be the function written and how?

It would be great if the solution follows SOLID principles( Open-Closed principle,…) and DDD.

Any refactoring that would make the code better is welcome.

Note: The AccountManipulator will be used by a website client over a web service.

namespace BankAccountBL
{
public class AccountManipulator
{
    //Whether it should beprivate or public?
    private IAccount acc;

    public AccountManipulator(int accountNumber)
    {
        acc = AccountFactory.GetAccount(accountNumber);
    }

    public void FreezeAccount()
    {
        acc.Freeze();
    }

}

public interface IAccount
{
    void Freeze();
}

public class AccountFactory
{
    public static IAccount GetAccount(int accountNumber)
    {
        return new SavingsAccount(accountNumber);
    }
}

public class SavingsAccount : IAccount
{
    public SavingsAccount(int accountNumber)
    {

    }

    public void Freeze()
    {

    }
}
}

READING:

  1. When to use the CQRS design pattern?

  2. In domain-driven design, would it be a violation of DDD to put calls to other objects' repostiories in a domain object?

  3. Refactoring domain logic that accesses repositories in a legacy system

  4. Which of these examples represent correct use of DDD?

  5. Good Domain Driven Design samples

  6. Advantage of creating a generic repository vs. specific repository for each object?

like image 912
LCJ Avatar asked Jun 19 '12 06:06

LCJ


1 Answers

if your AccountManipulator is a Façade to your domain, I wouldn't put the account number in the constructor. I would refactor it this way:

public class AccountManipulator
{
    private  AccountFactory _factory;
    private UserRepository _users;

    public AccountManipulator(AccountFactory factory, UserRepository users)
    {
       _factory = factory;
       _users = users;
    }

    public void FreezeAccount(int accountNumber)
    {
       var acc = _factory.GetAccount(accountNumber);
       acc.Freeze();
    }

    public IEnumerable<IAccount> GetAccountsOf(User user) {
       return _users.GetAccountIds(user).Select(_factory.GetAccount);
    }
}

public interface UserRepository {
    IEnumerable<int> GetAccountIds(User user);
}

In order to state if your domain is SOLID, you should analyze it with the principle:

  • Single Responsibility: every object has is own responsibility (and only that one):
    • AccountFactory: creates IAccounts
    • SavingsAccount: implementation of IAccount that reads from/writes to (a database? a web service?)
    • AccountManipulator: provide a minimal and simple set of operations to do with domain objects.
  • Open/Closed: are you classes are open to extensions and closed to changes?
    • AccountFactory: well, no. If you write a new implementation of IAccount, in order to use it you have to change AccountFactory. Solution: abstract factory
    • SavingsAccount? It depends if it will use external dependencies. Need more code to say.
    • AccountManipulator: yes. If you need to do another operation with your domain objects, you can use directly the other services without change AccountManipulator. Or you can inherit from it
  • Liskov substitution: can you substitute any class with another implementation? Need more code to say. You have no other implementations of IAccount or IAccountFactory now
  • Dependency Inversion:
    • AccountManipulator should depend on abstractions: AccountFactory and UserRepository should be interfaces.
like image 56
onof Avatar answered Sep 27 '22 18:09

onof