DDD, onde usar serviços de infra-estrutura

5

Estou tentando aprender DDD e estou tendo alguns problemas com os serviços de infra-estrutura.

Na verdade, eu entendo o que eles querem, mas não vejo onde eles se encaixam na minha inscrição.

Na verdade, estou tendo as seguintes coisas

  • Um serviço de aplicativo (API REST)
  • Alguns serviços de domínio (gerenciados com padrão de especificação)
  • Alguns serviços de infra-estrutura (repositórios e remetente de e-mail)

Pergunta 1 Eu queria saber se era a função de serviço de domínio a usar (ou seja, serviços de infra-estrutura injetados em serviços de domínio), algo como (de uma maneira muito minimalista):

class UserDomainService {

  constructor (userRepository, emailService) {
    this.userRepository = userRepository
    this.emailService = emailService
  }

  saveUser (user) {
    /** Apply some business rules here ...*/
    const user = this.userRepository.save(user)
    this.emailService.send('New user added : ' + user.firstName)
  }

}

Ou deveria ser o papel do serviço de aplicativos, assim:

class ApplicationService {

  constructor (userDomainService, userRepository, emailService) {
    this.userDomainService = userDomainService
    this.userRepository = userRepository
    this.emailService = emailService
  }

  postUser (user) {
    if (this.userDomainService.manageSomeRules(user)) {
      this.userRepository.save(user)
      this.emailService.send('New user added : ' + user.firstName)
      return user
    }
    return new RuleNotSatisfied()
  }

}

Pergunta 2

Quem é responsável por converter o usuário recebido, de pontos de extremidade do POST (API REST), em uma boa entidade?

EDIT na pergunta 2: Que tipo de serviço pode converter Entidade em DTO e vice-versa? Onde devo colocá-los?

    
por mfrachet 07.09.2016 / 08:12
fonte

2 respostas

3

Pergunta 1

Não há problema se o serviço de domínio usar serviços de infraestrutura, se os serviços de infraestrutura aceitarem e retornarem conceitos de domínio - entidades e objetos de valor.

Além disso, os serviços de domínio devem encapsular parte da lógica de negócios que não cabe em uma entidade. Portanto, saveUser não é um ótimo método para um serviço de domínio.

A pergunta a fazer é - o envio de um email é um conceito de domínio importante? A Email é uma entidade no seu domínio? Em caso afirmativo, você pode ter uma interface para um remetente de e-mail definido em sua camada de domínio, com uma implementação separada na camada de infraestrutura, e você poderia fazer o seguinte de forma significativa serviço de domínio -:

sendEmailIfWhiteListed(id) {
    Email = this.emailRepository.get(id);
    if (email.isWhiteListed) {
        this.emailSender.send(email);
    }
}

Mas isso é sensato apenas se os e-mails forem entidades em seu domínio. Se eles não são, então pense - por que fazer o envio do e-mail a responsabilidade de salvar o usuário?

No seu caso, não parece que os e-mails sejam entidades em sua linguagem onipresente . Então aqui eu sou a favor do padrão de eventos de domínio . Criar um novo usuário deve gerar um evento de domínio NewUserCreated e o manipulador do evento de domínio, que eu colocaria na camada do aplicativo, delegaria a um remetente de email para enviar o email.

Questão 2

Quem é responsável por converter os dados de postagem em uma entidade significativa? Depende do que você está fazendo:

  1. Se adicionar um novo usuário
    1. Se for uma lógica simples, o serviço de aplicativo pode chamar new Entity() e passar argumentos de domínio significativos (valueobjects) mapeados a partir do api data argument
    2. Se for uma lógica complexa, um serviço de domínio especial chamado fábrica pode ser usado this.entityFactory.Create() e, novamente, passar argumentos de domínio significativos (valueobjects) mapeados a partir do api data argument
    3. Em ambos os casos, a entidade ou a fábrica não deve estar ciente da estrutura de data , pois essa é uma preocupação da API
  2. Se atualizar um usuário
    1. o serviço de aplicativo deve usar um repositório para obter o usuário existente
    2. o usuário deve ter métodos para atualizar dados relevantes. Mas eu fugiria de métodos no estilo CRUD como user.update - pense em por que os dados do usuário estão sendo atualizados? O DDD nos incentiva a pensar nos processos e objetivos do negócio.
      1. O usuário está sendo atualizado porque participou de algum processo de negócios? Em seguida, modele o processo de negócios explicitamente e modifique os dados do usuário como um efeito colateral do processo
      2. O usuário está sendo atualizado devido a uma interação CRUD simples, como a edição de uma página de perfil? Mesmo assim, eu encorajaria um método de entidade como user.UpdateProfile a ser explícito sobre o propósito da operação.

DDD é sobre o idioma - ouça a linguagem usada por especialistas em domínio, concorde com uma linguagem ubiquitious e use-a fielmente em seu código. Se os especialistas do seu domínio não disserem persist ou save , não use essas palavras na sua camada de domínio.

    
por 07.09.2016 / 21:24
fonte
2

Eu acho que a resposta DDD é a primeira. Coloque a lógica no objeto de domínio. Injete serviços, se necessário.

Eu teria outra 'camada de hospedagem' para converter a mensagem recebida para o objeto de domínio

A camada de aplicação usaria objetos de domínio para obter o efeito necessário.

No entanto. Eu não acho que o DDD se encaixa muito bem no padrão de serviço. Na minha opinião, a lógica geralmente pertence ao serviço, não ao objeto de domínio.

Ou seja. Eu teria RecordPlayer.PlayRecord(record) em vez de Record.Play()

Além disso, a natureza desses serviços é que eles são sem estado, eu jogo um recorde, retorno o resultado e jogo tudo fora.

Considerando que em um aplicativo de desktop DDD funciona melhor. Eu posso ter vários registros instanciados e executar várias funções neles ao longo do tempo. Saia da prateleira, reproduza, pause, etc. O código do estilo DDD corresponde às ações do usuário e ao processo de pensamento. 'Eu jogo este disco' - > record.Play()

    
por 07.09.2016 / 09:31
fonte