Ao pensar no desenvolvimento ágil de software e em todos os princípios (SRP, OCP, ...), pergunto-me como tratar o log.
O registro ao lado de uma implementação é uma violação do SRP?
Eu diria yes
porque a implementação também deve ser capaz de executar sem o log. Então, como posso implementar o log de uma maneira melhor? Eu verifiquei alguns padrões e cheguei à conclusão de que a melhor maneira de não violar os princípios de uma maneira definida pelo usuário, mas usar qualquer padrão conhecido por violar um princípio é usar um padrão decorador.
Digamos que temos um monte de componentes completamente sem violação do SRP e, em seguida, queremos adicionar o log.
- componente A
- componente B usa A
Queremos registrar para A, então criamos outro componente D decorado com A, ambos implementando uma interface I.
- interface I
- componente L (componente de log do sistema)
- componente A implementa I
- o componente D implementa I, decora / usa A, usa L para registrar
- componente B usa um I
Vantagens: - Posso usar A sem registrar - testando A significa que não preciso de zombarias - os testes são mais simples
Desvantagem: - mais componentes e mais testes
Sei que essa parece ser outra questão de discussão aberta, mas na verdade quero saber se alguém usa melhores estratégias de log do que um decorador ou uma violação do SRP. E o registrador singleton estático, que é o NullLogger padrão e, se o log de syslog for desejado, altere o objeto de implementação no tempo de execução?
Respostas:
Sim, é uma violação do SRP, pois o registro é uma preocupação transversal.
A maneira correta é delegar o log para uma classe de logger (interceptação) cujo único objetivo é cumprir o log pelo SRP.
Veja este link para um bom exemplo: https://msdn.microsoft.com/en-us/library/dn178467%28v=pandp.30%29.aspx
Aqui está um pequeno exemplo :
Os benefícios incluem
fonte
TenantStoreLogger
alteração é alterada toda vezTenantStore
. Você não está separando as preocupações mais do que na solução inicial.Eu diria que você está levando o SRP muito a sério. Se o seu código estiver organizado o suficiente para que o log seja a única "violação" do SRP, você estará se saindo melhor do que 99% de todos os outros programadores e deverá dar um tapinha nas costas.
O objetivo do SRP é evitar códigos espaguetes horríveis, onde códigos que fazem coisas diferentes são todos misturados. Misturar o registro com o código funcional não soa nenhum sinal de alarme para mim.
fonte
Do you mock the logger?
é PRECISAMENTE o que você faz. Você deve ter umaILogger
interface que defina O QUE o criador de logs faz. O código em teste é injetado com umILogger
que você especificar. Para testar, você temclass TestLogger : ILogger
. O melhor disso é queTestLogger
pode expor coisas como a última string ou erro registrado. Os testes podem verificar se o código em teste está registrado corretamente. Por exemplo, um teste pode ser oUserSignInTimeGetsLogged()
local em que o teste verificaTestLogger
o logado.Não, não é uma violação do SRP.
As mensagens enviadas para o log devem ser alteradas pelos mesmos motivos que o código circundante.
O que é uma violação do SRP está usando uma biblioteca específica para fazer logon diretamente no código. Se você decidir alterar a maneira de registrar, o SRP declara que isso não deve afetar seu código comercial.
Algum tipo de resumo
Logger
deve estar acessível ao seu código de implementação, e a única coisa que sua implementação deve dizer é "Enviar esta mensagem para o log", sem preocupações quanto ao modo como isso é feito. Decidir sobre a maneira exata de registrar-se (até mesmo no registro de data e hora) não é responsabilidade da sua implementação.Sua implementação também não deve saber se o criador de logs para o qual está enviando mensagens é a
NullLogger
.Dito isto.
Eu não descartaria o registro como uma preocupação transversal muito rápido . A emissão de logs para rastrear eventos específicos que ocorrem no seu código de implementação pertence ao código de implementação.
O que é uma preocupação transversal, OTOH, é o rastreamento de execução : o registro entra e sai em todo e qualquer método. AOP está em melhor posição para fazer isso.
fonte
Login
interface decorada com o mesmo logger.Como o log é geralmente considerado uma preocupação transversal, sugiro usar o AOP para separar o log da implementação.
Dependendo da linguagem, você usaria um interceptador ou alguma estrutura de AOP (por exemplo, AspectJ em Java) para fazer isso.
A questão é se isso realmente vale a pena. Observe que essa separação aumentará a complexidade do seu projeto, proporcionando muito pouco benefício.
fonte
Isso parece bom. Você está descrevendo um decorador de log bastante padrão. Você tem:
Isso tem uma responsabilidade: registrar as informações que são passadas para ele.
Isso tem uma responsabilidade: fornecer uma implementação da interface I (supondo que eu seja adequadamente compatível com SRP).
Esta é a parte crucial:
Quando afirmado dessa maneira, parece complexo, mas veja da seguinte maneira: o componente D faz uma coisa: reunir A e L.
A única responsabilidade que o componente D tem é garantir que L seja notificado quando A for usado. As implementações de A e L estão em outro lugar. Isso é totalmente compatível com SRP, além de ser um exemplo puro de OCP e um uso bastante comum de decoradores.
Uma ressalva importante: quando D usa seu componente de registro L, deve fazê-lo de uma maneira que permita alterar a forma como você está registrando. A maneira mais simples de fazer isso é ter uma interface IL implementada por L. Então:
Dessa forma, nada depende diretamente de qualquer outra coisa, facilitando a troca. Isso facilita a adaptação às mudanças e a simulação de partes do sistema para que você possa fazer o teste de unidade.
fonte
D implements I
. Obrigado pela sua resposta.Claro que é uma violação do SRP, pois você tem uma preocupação transversal. No entanto, você pode criar uma classe responsável por compor o log com a execução de qualquer ação.
exemplo:
fonte