Как правильно приготовить DDD (domain-driven design) - ООП и паттерны - Ответ 16616487

Достался проект, который изначально планировался как DDD, но ребята которые его делали до меня нарушили все правила данного подхода. Вот теперь я пытаюсь разобраться что же такое DDD и как его правильно делать.

Почитал книжки, посмотрел видосики. Основной посыл понятен, но есть пару вопросов:

1. Если необходимо взаимодействие между двумя модулями, то должен ли ApplicationService модуля A иметь зависимость на ApplicationService модуля B? Или правильнее это сделать, например с использованием паттерна mediator? А если у них кроссзависимость A -> B -> A?

2. Если для выполнения операции необходимо взаимодействие с несколькими модулями, то где должна быть реализована логика? Или просто генерировать сообщение/событие, которое обработает каждый модуль отдельно (асинхронно??), то как в таком случае быть с транзакционностью?

3. Если имеется общий функционал, например на уровне Infrastructure, то это должно реализовываться в каждом домене или все же отдельная внешняя зависимость?

4. Дополнительно к пункту 3. Если DTO взаимодействия с другими модулями/системами не описаны в самом домене, то получается придется делать много маппингов. Это же шибко нагрузить систему большим количеством разных копий одного объекта.

5. Где вообще все же должна располагаться логика. Нахожу много примеров аналогично такому(вопросы сразу в примере):

C#Выделить код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

class ApplicationService
{
    DomainService  _domainService;
    AccontRepository _accountRepository;
 
    public void TransferMoney(decimal amount, int sourceAccountId, int destinationAccountId)
    {
        // Зачем это делать в ApplicationService и почему нельзя получить счета в DomainService передав в Transfer ID счетов???
        var sourceAccount = _accountRepository.Find(sourceAccountId);
        var destinationAccount = _accountRepository.Find(destinationAccountId);
 
        // Почему нельзя внутри Transfer сделать транзакцию???
        _domainService.Transfer(amount, sourceAccount, destinationAccount);
 
        // Если необходима обработка разных доменов, как организовать транзакцию???
        using (var transaction = new Transaction())
        {
            _accountRepository.Save(sourceAccount);
            _accountRepository.Save(destinationAccount);
            transaction.Commit();
        }
    } 
}

Добавлено через 14 минут

6. Если Агрегат содержит список элементов, которые необходимо извлекать для выполнения операции, то мы получаем сложные и большие запросы на получение данных. Разве нет?

C#Выделить код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

class Team
{
    List<Player> _players;
 
    publis void Add(Player player)
    {
        if (_players.Contains(player.Id))
            throw new Exception("Player in team");
 
        
    }
}
 
class ApplicationService
{
    PlayerRepository _playerRepository;
    TeamRepository _teamRepository;
    void AddPlayer(int playerId, int teamId)
    {
        var player = _payerRepository.Find(playerId);
 
        // Тут мы вынуждены вместе с командой загрузить всех игроков
        var team = _teamRepository.Find(teamId);
 
        team.Add(player);
 
        // Тут сохраняем весь список ИгроковКоманды
        _teamRepository.Save(team);
    }
}

Вернуться к обсуждению:

Как правильно приготовить DDD (domain-driven design) ООП и паттерны