portaldacalheta.pt
  • Principal
  • Noticias Do Mundo
  • Lucratividade E Eficiência
  • Ágil
  • Família
Processo Interno

Princípio de responsabilidade única: uma receita para o Grande Código



Independentemente do que consideramos um ótimo código, ele sempre requer qualidade simples - o código deve ser sustentável. Indentação adequada, nomes de variáveis ​​limpos, 100% de cobertura de teste e muito mais só funcionam até certo ponto. Qualquer código que não pode ser mantido e não pode ser adaptado com relativa facilidade aos requisitos em mudança é um código que apenas espera estar obsoleto. Podemos não ter que escrever um bom código quando estamos tentando construir um protótipo, prova de conceito ou produto mínimo viável, mas em todos os outros casos, devemos sempre escrever código que seja sustentável. Isso é algo que deve ser considerado uma qualidade fundamental da engenharia e design de software.

Princípio de responsabilidade única: uma receita para o Grande Código



Neste artigo, vou discutir como o princípio de responsabilidade única e algumas técnicas que giram em torno dele podem dar ao seu código essa qualidade. Escrever bons códigos é uma arte, mas alguns princípios sempre podem ajudar a dar ao seu trabalho de desenvolvimento a direção necessária para a produção de software forte e sustentável.



O modelo é tudo

Quase todos os livros sobre algum novo framework MVC (MVP, MVVM ou outro M **) estão cheios de exemplos de códigos ruins. Esses exemplos tentam mostrar o que o framework tem a oferecer. Mas também acabam fornecendo conselhos ruins para iniciantes. Exemplos como “digamos que temos este ORM X para nossos modelos, o mecanismo de modelo Y para nossas visões para que tenhamos controladores para lidar com tudo ”, eles alcançam nada mais do que controladores gigantescos. No entanto, em defesa desses livros, os exemplos pretendem demonstrar a facilidade com que você pode usar sua estrutura. Eles não se destinam a ensinar design de software. Mas os leitores que seguem esses exemplos percebem, só depois de anos, como é contraproducente ter pedaços de código monolíticos em seu projeto.



Os modelos são o coração do seu aplicativo. Se você tiver modelos separados do resto da lógica do aplicativo, a manutenção será muito mais fácil, não importa o quão complicado o aplicativo possa se tornar. Mesmo para aplicativos complicados, uma boa implementação do modelo pode resultar em um código extremamente expressivo. E para conseguir isso, você deve começar certificando-se de que seus modelos façam apenas o que devem fazer e não se preocupe com o que o aplicativo construído em torno deles faz. Além disso, não lida com o que é a camada de armazenamento de dados subjacente - seu aplicativo depende de um banco de dados SQL ou armazena tudo em arquivos de texto?



À medida que continuamos neste artigo, você perceberá que um bom código trata da separação de interesses.

s corp vs c corp vs llc

Princípio de Responsabilidade Única

Você provavelmente já ouviu falar dos princípios SÓLIDO : responsabilidade única, aberto-fechado, substituição de liskov, segregação de interface e inversão de dependência. A primeira letra, S, representa o Princípio de Responsabilidade Única ( FOICE ) e sua importância não pode ser exagerada. Diria mesmo que é uma condição necessária e importante para um bom código. Na verdade, em qualquer código que é mal escrito, você sempre pode encontrar uma classe que tem mais de uma responsabilidade - form1.cs ou index.php, contendo alguns milhares de linhas de código não é estranho e todos nós provavelmente já vimos. ou pronto.



Vamos dar uma olhada em um exemplo em C # (ASP.NET MVC e framework Entity). Mesmo se você não for um Desenvolvedor C # , com um pouco de experiência OOP você pode seguir em frente com facilidade.

public class OrderController { ... public ActionResult CreateForm() { /* * View data preparations */ return View(); } [HttpPost] public ActionResult Create(OrderCreateRequest request) { if (!ModelState.IsValid) { /* * View data preparations */ return View(); } using (var context = new DataContext()) { var order = new Order(); // Create order from request context.Orders.Add(order); // Reserve ordered goods …(Huge logic here)... context.SaveChanges(); //Send email with order details for customer } return RedirectToAction('Index'); } ... (many more methods like Create here) }

Esta é uma aula OrderController usual e seu método é mostrado Crio . Em controladores como este, frequentemente vejo casos em que a própria classe Ordem ele é usado como um parâmetro de solicitação. Mas eu prefiro usar classes de pedidos especiais. Claro, mais uma vez, FOICE !



Observe no trecho de código mostrado acima como o controlador sabe muito sobre 'fazer um pedido', incluindo, mas não se limitando a, armazenar o objeto Ordem , enviar e-mails, etc. Isso é simplesmente muito trabalhoso para uma única classe. Para cada pequena mudança, o desenvolvedor precisa alterar o código de todo o controlador. E apenas no caso de outro controlador também precisar criar comandos, na maioria das vezes os desenvolvedores recorrem a copiar e colar o código. Os controladores devem controlar apenas o processo geral e não hospedar cada bit da lógica do processo.



Mas hoje é o dia em que paramos de escrever esses drivers gigantescos!

Vamos primeiro extrair toda a lógica de negócios do controlador e movê-la para uma classe OrderService :



public class OrderService { public void Create(OrderCreateRequest request) { // all actions for order creating here } } public class OrderController { public OrderController() { this.service = new OrderService(); } [HttpPost] public ActionResult Create(OrderCreateRequest request) { if (!ModelState.IsValid) { /* * View data preparations */ return View(); } this.service.Create(request); return RedirectToAction('Index'); }

Feito isso, o controlador agora faz apenas o que deve fazer: controlar o processo. Ele só conhece as visualizações, as classes OrderService Y Pedido de ordem - o conjunto mínimo de informações necessárias para a realização do seu trabalho, que é a gestão das solicitações e o envio das respostas.

Assim, em raras ocasiões, o código do controlador será alterado. Outros componentes, como visualizações, objetos de solicitação e serviços, podem ser alterados porque estão vinculados aos requisitos de negócios, mas não aos motivadores.

É isso FOICE , e existem muitas técnicas para escrever código que atenda a esse princípio. Um exemplo disso é a injeção de dependência (algo que também é útil para escrever código testável )

Injeção de dependência

É difícil imaginar um grande projeto baseado no Princípio de Responsabilidade Única sem Injeção de Dependência. Vamos dar uma olhada em nossa classe novamente OrderService :

public class OrderService { public void Create(...) { // Creating the order(and let’s forget about reserving here, it’s not important for following examples) // Sending an email to client with order details var smtp = new SMTP(); // Setting smtp.Host, UserName, Password and other parameters smtp.Send(); } }

Este código funciona, mas não é muito ideal. Para entender como o método de criação de classe funciona OrderService , são forçados a compreender as complexidades de SMTP . E, novamente, copiar e colar é a única maneira de replicar esse uso de SMTP onde necessário. Mas com um pouco de refatoração, isso pode mudar:

public class OrderService { private SmtpMailer mailer; public OrderService() { this.mailer = new SmtpMailer(); } public void Create(...) { // Creating the order // Sending an email to client with order details this.mailer.Send(...); } } public class SmtpMailer { public void Send(string to, string subject, string body) { // SMTP stuff will be only here } }

Muito melhor! Mas a classe OrderService você ainda sabe muito sobre como enviar e-mails. Você precisa exatamente da aula SmtpMailer Enviar um email. E se quisermos mudar isso mais tarde? E se quisermos imprimir o conteúdo do e-mail que é enviado para um arquivo de log especial em vez de enviá-lo em nosso ambiente de desenvolvimento? E se quisermos testar nossa classe OrderService ? Vamos continuar com a refatoração criando uma interface IMailer :

projeto do exame de arquiteto de soluções certificadas aws
public interface IMailer { void Send(string to, string subject, string body); }

SmtpMailer irá implementar esta interface. Além disso, nosso aplicativo usará um contêiner IoC e podemos configurá-lo para que IMailer ser implementado pela classe SmtpMailer . OrderService pode ser alterado da seguinte forma:

public sealed class OrderService: IOrderService { private IOrderRepository repository; private IMailer mailer; public OrderService(IOrderRepository repository, IMailer mailer) { this.repository = repository; this.mailer = mailer; } public void Create(...) { var order = new Order(); // fill the Order entity using the full power of our Business Logic(discounts, promotions, etc.) this.repository.Save(order); this.mailer.Send(, , ); } }

Agora estamos avançando! Aproveitei para fazer outra mudança. OrderService agora é baseado na interface IOrderRepository para interagir com o componente que armazena todos os nossos pedidos. Você não se preocupa mais com a forma como essa interface é implementada ou com qual tecnologia de armazenamento a alimenta. Agora aula OrderService você só tem um código que trata da lógica de negócios dos pedidos.

Dessa forma, se um testador encontrar algo que não está funcionando corretamente ao enviar e-mails, o desenvolvedor saberá exatamente onde procurar: classe SmtpMailer . Se algo estava errado com os descontos, o desenvolvedor sabe mais uma vez onde procurar: o código da aula OrderService (ou no caso de você ter aceitado FOICE do coração então pode ser DiscountService )

Arquitetura Orientada a Eventos

No entanto, ainda não gosto do método OrderService.Create:

public void Create(...) { var order = new Order(); ... this.repository.Save(order); this.mailer.Send(, , ); }

O envio de um e-mail não faz parte do fluxo principal de criação do pedido. Mesmo que o aplicativo não envie o e-mail, o pedido continua sendo criado corretamente. Imagine também uma situação em que você tem que adicionar uma nova opção na área de configurações do usuário que permite que eles optem por não receber um e-mail após fazer um pedido com sucesso. Para incorporar isso em nossa classe OrderService , teremos que introduzir uma dependência: IUserParametersService . Adicione o local e você já terá uma nova dependência, ITranslator (para produzir e-mails corretos no idioma de escolha do usuário). Várias dessas ações são desnecessárias, especialmente a ideia de adicionar tantas dependências e terminar com um construtor que não cabe na tela. Achei um ótimo exemplo disso na base de código Magento (a CMS software de comércio eletrônico escrito em PHP) em uma classe com 32 dependências!

como obter token jwt

Às vezes é difícil imaginar como separar essa lógica e a classe Magento é provavelmente uma vítima de um desses casos. É por isso que gosto da forma “orientada por eventos”:

namespace .Events { [Serializable] public class OrderCreated { private readonly Order order; public OrderCreated(Order order) { this.order = order; } public Order GetOrder() { return this.order; } } }

Cada vez que um pedido é criado, em vez de enviar um e-mail diretamente da turma OrderService , a classe de eventos especiais é criada Pedido criado e um evento é gerado. Em algum lugar nos manipuladores de eventos do aplicativo, ele será configurado. Um deles enviará um email ao cliente.

namespace .EventHandlers { public class OrderCreatedEmailSender : IEventHandler { public OrderCreatedEmailSender(IMailer, IUserParametersService, ITranslator) { // this class depend on all stuff which it need to send an email. } public void Handle(OrderCreated event) { this.mailer.Send(...); } } }

A aula Pedido criado está marcado como Serializável a propósito. Podemos lidar com esse evento imediatamente ou armazená-lo serializado em uma linha (Redis, ActiveMQ ou qualquer outro) e processá-lo em um processo / thread separado daquele que lida com as solicitações da web. Dentro este artigo , o autor explica em detalhes o que é arquitetura orientada a eventos (não preste atenção à lógica de negócios dentro OrderController )

Alguns podem argumentar que agora é difícil entender o que acontece ao criar o pedido. Mas isso não é verdade. Se você se sente assim, aproveite a funcionalidade do seu AQUI . Ao encontrar todos os usos da classe Pedido criado no AQUI , podemos ver todas as ações associadas ao evento.

Mas quando devo usar injeção de dependência e quando devo usar uma abordagem baseada em eventos? Nem sempre é fácil responder a essa pergunta, mas uma regra simples que pode ajudá-lo é usar a injeção de dependência para todas as suas atividades principais no aplicativo e a abordagem orientada a eventos para todas as ações secundárias. Por exemplo, use injeção de dependência com coisas como criar um pedido dentro da classe OrderService com IOrderRepository , bem como delegar o envio de emails, que não é uma parte crucial do fluxo de criação do pedido principal, a algum manipulador de eventos.

conclusão

Começamos com um controlador muito importante, apenas uma classe, e terminamos com uma coleção elaborada de classes. Os benefícios dessas mudanças são um tanto aparentes a partir dos exemplos. No entanto, ainda existem muitas maneiras de melhorar esses exemplos. Por exemplo, o método OrderService.Create pode ser movido para uma classe própria: OrderCreator . Como a criação de pedidos é uma unidade independente da lógica de negócios, que segue o Princípio de Responsabilidade Única, é natural que ela tenha sua própria classe com seu próprio conjunto de dependências. Da mesma forma, a exclusão e o cancelamento de um pedido podem ser implementados em suas próprias classes.

Quando escrevi código altamente emparelhado, algo semelhante ao primeiro exemplo deste artigo, qualquer mudança, mesmo pequena, nos requisitos poderia levar a muitas mudanças em outras partes do código. FOICE ajuda os desenvolvedores a escrever um código 'desemparelhado', onde cada classe tem seu próprio trabalho. Se alguma especificação dessa tarefa for alterada, o desenvolvedor fará alterações apenas nessa classe específica. É menos provável que a alteração interrompa todo o aplicativo, já que outras classes deveriam estar fazendo seu trabalho como antes, a menos que tenham sido interrompidas inicialmente.

Desenvolver código usando essas técnicas e seguindo o Princípio da Responsabilidade Única pode parecer uma tarefa difícil, mas os esforços serão recompensados ​​conforme o projeto cresce e o desenvolvimento continua.

Criando uma criptomoeda na linguagem de programação Crystal

Tecnologia

Criando uma criptomoeda na linguagem de programação Crystal
O front end: usando Gatsby.js e Node.js para atualizações estáticas do site

O front end: usando Gatsby.js e Node.js para atualizações estáticas do site

Tecnologia

Publicações Populares
Quem, o quê e por quê - um guia para métodos de teste do usuário
Quem, o quê e por quê - um guia para métodos de teste do usuário
Aflição financeira em uma crise: você não pode prever, você pode se preparar
Aflição financeira em uma crise: você não pode prever, você pode se preparar
Bangladesh condena seis militantes à morte por matar dois ativistas gays
Bangladesh condena seis militantes à morte por matar dois ativistas gays
Mães solteiras na arte de criar filhos sozinhas
Mães solteiras na arte de criar filhos sozinhas
Vender uma empresa para valor máximo em um mercado desafiador de fusões e aquisições
Vender uma empresa para valor máximo em um mercado desafiador de fusões e aquisições
 
Robo-conselheiro Risco de portfólio da indústria: eficiência ou redução de cantos?
Robo-conselheiro Risco de portfólio da indústria: eficiência ou redução de cantos?
EUA: corrida para prefeito de Honolulu segue para segundo turno
EUA: corrida para prefeito de Honolulu segue para segundo turno
13 podcasts que todo designer deve ouvir
13 podcasts que todo designer deve ouvir
Vazamentos de Panama Papers podem dar a Sanders algum poder de fogo contra o rival Clinton
Vazamentos de Panama Papers podem dar a Sanders algum poder de fogo contra o rival Clinton
Com 21 anos e raízes de Kerala, é o mais jovem na lista de MBE do Queen
Com 21 anos e raízes de Kerala, é o mais jovem na lista de MBE do Queen
Publicações Populares
  • como adicionar power pivot ao excel
  • problemas e soluções de aprendizado de máquina
  • o que os bots discord fazem
  • qual escola de psicologia desenvolveu o princípio de fechamento
  • diferença entre ac e s corp
  • problemas e soluções de segurança cibernética
Categorias
  • Noticias Do Mundo
  • Lucratividade E Eficiência
  • Ágil
  • Família
  • © 2022 | Todos Os Direitos Reservados

    portaldacalheta.pt