<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wali Queiroz</title>
    <description>The latest articles on DEV Community by Wali Queiroz (@waliqueiroz).</description>
    <link>https://dev.to/waliqueiroz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1696846%2F18a3c445-2bae-4301-a1e9-a11cabfb188c.jpg</url>
      <title>DEV Community: Wali Queiroz</title>
      <link>https://dev.to/waliqueiroz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/waliqueiroz"/>
    <language>en</language>
    <item>
      <title>Princípios SOLID em GoLang - Dependency Inversion Principle (DIP)</title>
      <dc:creator>Wali Queiroz</dc:creator>
      <pubDate>Sat, 03 Aug 2024 17:10:29 +0000</pubDate>
      <link>https://dev.to/waliqueiroz/principios-solid-em-golang-dependency-inversion-principle-dip-3nk9</link>
      <guid>https://dev.to/waliqueiroz/principios-solid-em-golang-dependency-inversion-principle-dip-3nk9</guid>
      <description>&lt;p&gt;Olá, pessoas!&lt;/p&gt;

&lt;p&gt;Estou de volta para concluir nossa série de artigos sobre SOLID, apresentando o princípio que tem o impacto mais significativo nos testes unitários em Go: O Princípio da Inversão de Dependência.  Para ver os artigos onde detalho os outros, acesse:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-single-responsability-principle-srp-af5"&gt;Princípios SOLID em GoLang - Single Responsability Principle (SRP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-openclosed-principle-ocp-422p"&gt;Princípios SOLID em GoLang - Open/Closed Principle (OCP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-liskov-substitution-principle-lsp-4a1"&gt;Princípios SOLID em GoLang - Liskov Substitution Principle (LSP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-interface-segregation-principle-isp-175a"&gt;Princípios SOLID em GoLang - Interface Segregation Principle (ISP)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y4c7e2ldm52ic3g7n33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y4c7e2ldm52ic3g7n33.png" alt="GoLang - Dependency Inversion Principle" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como desenvolvedor, você já se deparou com softwares altamente acoplados, onde as regras de negócio se misturam com detalhes de apresentação e recursos de bibliotecas externas? Quando é necessário substituir ou alterar uma dessas dependências, muitas partes da aplicação precisam ser modificadas. E aí está uma coisa que todo dev odeia.&lt;/p&gt;

&lt;p&gt;Aqui entra o DIP, uma luz no fim do túnel para esse problema. Segundo Robert C. Martin, seu formulador:&lt;/p&gt;

&lt;p&gt;“Os módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações. Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.”&lt;/p&gt;

&lt;p&gt;Mas o que são módulos de alto e baixo nível?&lt;/p&gt;

&lt;p&gt;Os módulos de alto nível, nesse contexto, são os componentes mais próximos das regras de negócio da aplicação, enquanto os de baixo nível são as ferramentas que usamos para executar essas regras, eles escondem detalhes técnicos sobre diferentes integrações de infraestrutura. Por exemplo, poderia ser uma struct que contém a lógica para recuperar dados do banco de dados, enviar uma mensagem SQS, buscar um valor do Redis ou enviar uma solicitação HTTP para uma API externa.&lt;/p&gt;

&lt;p&gt;O DIP sugere que as regras de negócio não devem interagir diretamente com os recursos utilizados para sua execução. A comunicação deve ocorrer através de interfaces, definidas pelo negócio, e as ferramentas externas ou detalhes de implementação são encapsulados em classes que implementam essas interfaces. Isso pode aumentar um pouco a base de código, mas vale a pena, pois torna o sistema mais flexível e fácil de modificar.&lt;/p&gt;

&lt;p&gt;Vamos aos exemplos práticos com Go.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;No trecho de código acima definimos um componente de alto nível, TaskService. Esta estrutura tem um método ChangeStatus, responsável por mudar o estado da tarefa, que espera o ID e um novo estado. Observem que nosso componente de alto nível depende diretamente do componente de baixo nível sql.DB. Essa dependência direta aumenta o acoplamento entre componentes, tornando o código mais difícil de manter e evoluir. A substituição do banco de dados ou a introdução de um repositório diferente exige modificações no TaskService, o que viola &lt;a href="https://www.tecnofator.com.br/2023/03/principios-solid-em-golang-single.html" rel="noopener noreferrer"&gt;o princípio da responsabilidade única&lt;/a&gt;. Também limita a capacidade de reutilizar o TaskService em diferentes contextos, onde uma implementação diferente de persistência pode ser necessária. Além disso, sem definir uma conexão real com o banco de dados, não podemos inicializar nossa estrutura de caso de uso. Tal anti-padrão impacta diretamente nossos testes unitários em Go. Vejamos:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Em contraste com algumas linguagens, como PHP ou Java, não podemos simplesmente criar mocks de "qualquer coisa" em Go. A criação de mocks aqui depende do uso de interfaces, para as quais podemos definir uma implementação simulada, mas não podemos fazer o mesmo para structs. Portanto, não podemos criar um mock de sql.DB, pois é uma struct. Nesse caso, precisamos criar um mock em um nível mais baixo, instanciando uma conexão falsa, o que podemos conseguir usando o pacote &lt;a href="https://github.com/DATA-DOG/go-sqlmock" rel="noopener noreferrer"&gt;SQLMock&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;No entanto, mesmo essa abordagem não é nem confiável nem eficiente para testes. Qualquer mudança dentro do banco de dados requer que adaptemos também os testes unitários. Além dos problemas com testes, temos um dilema ainda maior: o que acontecerá se decidirmos mudar o armazenamento para algo diferente, como MongoDB? Nesse cenário, se continuarmos usando essa implementação de TaskService, isso levará a inúmeras refatorações.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como aplicar a inversão de dependências
&lt;/h2&gt;

&lt;p&gt;“Os módulos de alto nível não devem depender de módulos de baixo nível. &lt;strong&gt;Ambos devem depender de abstrações&lt;/strong&gt;. Abstrações não devem depender de detalhes. &lt;strong&gt;Detalhes devem depender de abstrações&lt;/strong&gt;.”&lt;/p&gt;

&lt;p&gt;Vamos revisitar a diretriz original do Princípio da Inversão de Dependência e focar nas frases em negrito. Elas nos fornecem algumas orientações para o processo de refatoração. Precisamos definir uma abstração (uma interface) da qual nossos componentes, TaskService (alto nível) e sql.DB (baixo nível), dependerão. Esta abstração não deve estar vinculada a nenhum detalhe técnico, somente à entidades que compõem o cerne da regra de negócio. Vamos dar uma olhada no código a seguir:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Na nova estrutura de código, adicionamos a interface &lt;strong&gt;TaskRepository&lt;/strong&gt; como um componente que depende da estrutura &lt;strong&gt;Task&lt;/strong&gt;. Task não reflete diretamente o esquema do banco de dados; em vez disso, usamos a estrutura &lt;strong&gt;TaskModel&lt;/strong&gt; para essa finalidade. Também temos uma função &lt;strong&gt;mapTaskModelToTask&lt;/strong&gt; que facilita o mapeamento para a estrutura Task real.&lt;/p&gt;

&lt;p&gt;Nesta configuração, o componente de alto nível depende de uma abstração, pois contém um campo do tipo TaskRepository. Para fazer o componente de baixo nível depender da mesma abstração, aplicamos o &lt;a href="https://github.com/DATA-DOG/go-sqlmock" rel="noopener noreferrer"&gt;pattern Adapter&lt;/a&gt;, fazendo com que sql.DB sirva como parte dos detalhes em &lt;strong&gt;taskSQLRepository&lt;/strong&gt;, que atua como a implementação concreta de TaskRepository. Podemos definir quantas implementações para TaskRepository forem necessárias, como taskFileRepository ou taskMongoDBRepository.&lt;/p&gt;

&lt;p&gt;Agora nossas estruturas dependem de interfaces e, se precisarmos alterar nossas dependências, podemos definir diferentes implementações e injetá-las. Essa técnica está alinhada com o padrão de &lt;strong&gt;Injeção de Dependência (DI)&lt;/strong&gt;, uma prática comum em vários frameworks. A diferença entre injeção de dependência e inversão de dependência é sutil, mas crucial. O DIP é um princípio de design que orienta o desacoplamento de módulos de alto nível dos de baixo nível, enquanto a DI é uma técnica de implementação usada para realizar esse desacoplamento, injetando dependências em vez de criá-las internamente.&lt;/p&gt;

&lt;p&gt;Agora, vamos examinar como essa refatoração afeta nossos testes unitários:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Após essa mudança, fica fácil criar mocks. Essa forma de fazer as coisas torna o processo de teste mais simples e elegante. Agora, podemos facilmente usar diferentes versões do TaskRepository para testar diferentes situações e controlar com precisão os resultados dos testes. Mas você pode estar se perguntando: "Eu tenho que fazer isso manualmente?" A resposta é não. No exemplo, criei mocks manualmente apenas para facilitar o entendimento, mas na prática, você pode usar bibliotecas como Mockery e GoMock para gerar automaticamente o código desses mocks com base nas interfaces, o que acelera bastante o desenvolvimento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações finais
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Aumento de Código e Manutenção
&lt;/h3&gt;

&lt;p&gt;Ao aplicar o Princípio da Inversão de Dependência (DIP), é natural que o código aumente em termos de quantidade. A necessidade de criar interfaces e classes adicionais para cumprir o princípio pode parecer um overhead inicialmente. No entanto, essa abordagem traz inúmeros benefícios a longo prazo. O código torna-se mais modular e cada componente se torna independente dos detalhes de implementação dos outros. Isso facilita a manutenção e a evolução do sistema, pois mudanças em uma parte do código não requerem alterações em outras partes, minimizando o risco de introduzir novos bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Facilidade de Teste
&lt;/h3&gt;

&lt;p&gt;Outro benefício crucial de seguir o DIP é a facilidade de testar o código. Quando dependências são abstraídas através de interfaces, é simples substituir implementações reais por mocks ou stubs nos testes unitários. Isso permite que cada parte do sistema seja testada de maneira isolada, garantindo uma cobertura de testes mais eficaz e uma detecção precoce de falhas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relevância em Arquiteturas em Camadas
&lt;/h3&gt;

&lt;p&gt;Em arquiteturas modernas, como a Arquitetura Limpa e a Arquitetura Hexagonal, o DIP não é apenas uma recomendação, mas uma necessidade para garantir que o sistema seja robusto, flexível e preparado para mudanças futuras.&lt;/p&gt;

&lt;p&gt;E assim concluímos nossa série sobre SOLID em Golang! Espero que tenha sido útil para vocês. &lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;

&lt;p&gt;Referências:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.cleancoder.com/" rel="noopener noreferrer"&gt;Clean Coder Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://balta.io/blog/dependency-inversion-principle#:~:text=O%20princ%C3%ADpio%20da%20invers%C3%A3o%20de,entre%20as%20camadas%20do%20sistema." rel="noopener noreferrer"&gt;Dependency Inversion Principle | balta.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://imasters.com.br/codigo/solid-de-verdade-dependency-inversion-principle-dip" rel="noopener noreferrer"&gt;SOLID de verdade – Dependency Inversion Principle (DIP) | iMasters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>solidprinciples</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Princípios SOLID em GoLang - Interface Segregation Principle (ISP)</title>
      <dc:creator>Wali Queiroz</dc:creator>
      <pubDate>Sat, 03 Aug 2024 16:47:35 +0000</pubDate>
      <link>https://dev.to/waliqueiroz/principios-solid-em-golang-interface-segregation-principle-isp-175a</link>
      <guid>https://dev.to/waliqueiroz/principios-solid-em-golang-interface-segregation-principle-isp-175a</guid>
      <description>&lt;p&gt;E aí, galerinha!&lt;/p&gt;

&lt;p&gt;Hoje vamos falar sobre o quarto princípio SOLID: o Interface Segregation Principle. Para ver os artigos onde detalho os 3 primeiros, acesse:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-single-responsability-principle-srp-af5"&gt;Princípios SOLID em GoLang - Single Responsability Principle (SRP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-openclosed-principle-ocp-422p"&gt;Princípios SOLID em GoLang - Open/Closed Principle (OCP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-liskov-substitution-principle-lsp-4a1"&gt;Princípios SOLID em GoLang - Liskov Substitution Principle (LSP)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tzicccdjs2igjbclep2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tzicccdjs2igjbclep2.png" alt="GoLang - Interface Segregation Principle" width="800" height="816"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O Interface Segregation Principle ou Princípio da Segregação de Interfaces é bem simples de ser compreendido. Ele postula que "nenhum cliente deve ser forçado a depender de métodos que não utiliza". "Cliente", nesse contexto, não são os usuários finais do software, mas os módulos que dependem de uma interface dentro do sistema.&lt;/p&gt;

&lt;p&gt;Em outras palavras, o princípio prega que nossas interfaces devem ser concisas, de forma que não precisemos fazer com que as classes ou structs implementem métodos apenas para "respeitar o contrato".&lt;/p&gt;

&lt;p&gt;Semelhante ao Princípio da Responsabilidade Única, o objetivo do ISP é reduzir os efeitos colaterais e a frequência das alterações necessárias, dividindo o software em várias partes independentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Violando o ISP
&lt;/h2&gt;

&lt;p&gt;Ninguém quer escrever código ruim, mas manter princípios de design nem sempre é fácil ou intuitivo. Com o crescimento do sistema em usuários e funcionalidades, cada mudança se torna um desafio. Às vezes, a solução rápida é adicionar um novo método a uma interface existente, mesmo que não tenha relação direta. Isso pode resolver problemas quando o requisito é o prazo (o que a gente sabe que acontece ⛓️💼💔), mas polui a interface e gera contratos confusos com métodos de diferentes responsabilidades.&lt;/p&gt;

&lt;p&gt;Vamos dar uma olhada em um exemplo onde esse tipo de equívoco poderia acontecer.&lt;/p&gt;

&lt;p&gt;Começaremos definindo uma interface chamada &lt;strong&gt;Phone&lt;/strong&gt; que representa um telefone celular com funcionalidades básicas, como discar num teclado físico e fazer e receber chamadas.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Nesta etapa, temos uma interface clara e uma implementação para telefones simples. Tudo funciona bem até aqui.&lt;/p&gt;

&lt;p&gt;Vamos supor que agora o sistema precise acomodar funcionalidades de smartphones. Uma abordagem inicial para lidar com isso poderia ser incluir todos os métodos de smartphones na interface do telefone básico, como demonstrado abaixo:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Como a interface &lt;strong&gt;Phone&lt;/strong&gt; mudou e mais métodos foram adicionados, todos os seus clientes precisam ser atualizados. O problema é que implementá-los é indesejado e pode levar a muitos efeitos colaterais. Neste ponto, estamos forçando a struct SimplePhone a implementar métodos como &lt;strong&gt;TakePhoto()&lt;/strong&gt; e &lt;strong&gt;SendEmail()&lt;/strong&gt;, mesmo que eles sejam irrelevantes para esse tipo de telefone. O mesmo ocorre com a struct AdvancedPhone, que implementa o método &lt;strong&gt;DialPhysicalKeypad()&lt;/strong&gt; mesmo que smartphones geralmente não o tenham teclado físico. Nesse cenário, as implementações têm que lidar com as funcionalidades não suportadas lançando &lt;strong&gt;panics&lt;/strong&gt; (em outras linguagens a gente vê bastante o uso de exceções nessas situações). &lt;/p&gt;

&lt;p&gt;Para evitar a interrupção abrupta de um caso de uso, o código que utiliza essas implementações (como a função &lt;strong&gt;performPhoneActions&lt;/strong&gt;) teria que ser modificado para verificar a capacidade do telefone antes de chamar cada método. Isso funciona? Funciona! Mas não é nada escalável e aumenta bastante a chance de introduzirmos um bug mexendo em código que já existia sem necessidade. Além disso, como já vimos, essa abordagem quebra pelo menos mais dois princípios SOLID, o OCP e o LSP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aplicando o Interface Segregation Principle
&lt;/h2&gt;

&lt;p&gt;Na seção anterior poluímos intencionalmente a interface Phone e violamos o ISP. Vejamos como corrigi-lo.&lt;/p&gt;

&lt;p&gt;Observando o código com problemas, podemos ver que os métodos &lt;strong&gt;MakeCall&lt;/strong&gt; e &lt;strong&gt;ReceiveCall&lt;/strong&gt; são necessários em ambas as implementações. Por outro lado, &lt;strong&gt;DialPhysicalKeypad&lt;/strong&gt; só é necessário em telefones básicos, e &lt;strong&gt;TakePhoto&lt;/strong&gt; e &lt;strong&gt;SendEmail&lt;/strong&gt; são apenas para Smartphones. Com isso resolvido, vamos dividir as interfaces e aplicar o ISP. &lt;/p&gt;

&lt;p&gt;Assim, agora temos uma interface comum:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Mais duas para os respectivos tipos de telefone:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;E as respectivas implementações:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Com essa abordagem, conseguimos corrigir muitos problemas do código anterior. Agora, diferentes tipos de telefones têm contratos que fazem sentido para eles. Não precisamos mais nos preocupar com métodos desnecessários ou pânicos. E se quisermos adicionar um novo tipo de telefone ou funcionalidade, podemos fazer isso sem estragar o que já estava funcionando.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde aplicar no mundo real?
&lt;/h2&gt;

&lt;p&gt;Imagine que você está desenvolvendo uma aplicação de comércio eletrônico que precisa lidar com diferentes gateways de pagamento para processar transações. Cada gateway tem suas próprias capacidades e limitações. Como você pode garantir que sua aplicação seja flexível e adaptável a essas diferenças?&lt;/p&gt;

&lt;p&gt;Inicialmente, você pode criar uma interface única que engloba todas as operações possíveis:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;No entanto, a disponibilidade de cada recurso pode variar de uma solução para outra. Alguns gateways de pagamento podem ser mais limitados em termos de funcionalidades e recursos.&lt;/p&gt;

&lt;p&gt;Para aplicar o ISP nesse cenário, é sensato separar as operações em interfaces mais específicas, de acordo com a disponibilidade de recursos em cada gateway. Isso permite que você modele de forma precisa o comportamento esperado para cada serviço de pagamentos.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Formas práticas de seguir o ISP
&lt;/h2&gt;

&lt;p&gt;Antes que vocês saiam por aí quebrando toda e qualquer interface em várias de um método só, lembrem-se: não é assim que a banda toca. A depender do seu contexto, pode ser que faça sentido ter uma interface grande. No mundo das interfaces, ao contrário do que podemos ser levados a pensar quando estamos começando a estudar boas práticas, não é a fragmentação que importa, é a coesão. Em vez de se perguntar se suas classes/structs estão lidando com interfaces "inchadas", questionem: "Esses métodos fazem sentido juntos?". Se a resposta for um enigmático "não", refatore o quanto antes!&lt;/p&gt;

&lt;p&gt;That's all, folks!&lt;/p&gt;

&lt;p&gt;Refrências:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/java-interface-segregation" rel="noopener noreferrer"&gt;Baeldung - Interface Segregation Principle in Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackify.com/interface-segregation-principle/" rel="noopener noreferrer"&gt;SOLID Design Principles Explained: Interface Segregation with Code Examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>solidprinciples</category>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Princípios SOLID em GoLang - Liskov Substitution Principle (LSP)</title>
      <dc:creator>Wali Queiroz</dc:creator>
      <pubDate>Mon, 29 Jul 2024 00:51:26 +0000</pubDate>
      <link>https://dev.to/waliqueiroz/principios-solid-em-golang-liskov-substitution-principle-lsp-4a1</link>
      <guid>https://dev.to/waliqueiroz/principios-solid-em-golang-liskov-substitution-principle-lsp-4a1</guid>
      <description>&lt;p&gt;Hoje vamos falar sobre o Liskov Substitution Principle. Para ver os artigos anteriores da série acesse:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-single-responsability-principle-srp-af5"&gt;Princípios SOLID em GoLang - Single Responsability Principle (SRP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-openclosed-principle-ocp-422p"&gt;Princípios SOLID em GoLang - Open/Closed Principle (OCP)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypihvu1jd1de5holika0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypihvu1jd1de5holika0.png" alt="Gopher - Liskov Substitution Principle" width="800" height="785"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentre os princípios SOLID, o LSP é o que tem a definição formal mais complicada. Por outro lado, é o de mais simples execução, porque o conceito é intuitivo e você acaba aplicando sem muito esforço cognitivo na maioria das vezes.&lt;/p&gt;

&lt;p&gt;O princípio foi definido por Barbara Liskov da seguinte forma: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Se q(x) é uma propriedade demonstrável dos objetos x de tipo T. Então q(y) deve ser verdadeiro para objetos y de tipo S onde S é um subtipo de T."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Complicado, né?&lt;/p&gt;

&lt;p&gt;Mas, no fim das contas, essa definição matemática pode ser traduzida na seguinte sentença: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Se um ObjetoX é uma instância da ClasseX, e um ObjetoY é uma instância da ClasseY, e a ClasseY herda da ClasseX— se usarmos ObjetoY em vez de ObjetoX em algum lugar do código, a funcionalidade não deve ser interrompida."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como podemos ver, esse é um princípio que parece estar diretamente ligado aos conceitos de classe e herança, e nenhum dos dois está presente no Go. Então como podemos aplicar?&lt;/p&gt;

&lt;p&gt;Já vi alguns artigos explicando o LSP em GoLang utilizando os recursos de composição (embedding) da linguagem, mas, do meu ponto de vista, não é uma boa abordagem, pois a composição não permite substituir a estrutura pai pela estrutura filha. Observem:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A definição do princípio leva muitos (eu incluso por bastante tempo) a pensar que se trata de somente de herança, mas na verdade trata-se de subtipagem. Logo, em Go, o LSP é melhor expresso através do uso de &lt;strong&gt;interfaces&lt;/strong&gt; e &lt;strong&gt;polimorfismo&lt;/strong&gt;. Vamos ao próximo exemplo:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Neste cenário, fizemos o método &lt;strong&gt;Refuel()&lt;/strong&gt; na struct &lt;strong&gt;ElectricCar&lt;/strong&gt; lançar um &lt;strong&gt;panic&lt;/strong&gt; indicando que carros elétricos não podem ser abastecidos com gasolina.&lt;/p&gt;

&lt;p&gt;Ao chamar a função &lt;strong&gt;PerformVehicleActions()&lt;/strong&gt; com uma instância de &lt;strong&gt;ElectricCar&lt;/strong&gt;, ocorre uma quebra óbvia do princípio de substituição de Liskov. Embora &lt;strong&gt;ElectricCar&lt;/strong&gt; implemente o método &lt;strong&gt;Refuel()&lt;/strong&gt; definido pela interface &lt;strong&gt;Vehicle&lt;/strong&gt;, a implementação específica do carro elétrico interrompe a execução do programa.&lt;/p&gt;

&lt;p&gt;No exemplo, vimos a quebra da funcionalidade da interface em vez de seguir a expectativa. E essa é a sacada do LSP em Go: &lt;strong&gt;Uma struct não deve violar o propósito da interface&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Poderíamos alterar o design de modo que o cliente do método &lt;strong&gt;Refuel()&lt;/strong&gt; tenha que estar ciente de um possível erro ao chamá-lo. No entanto, isso significaria que os clientes teriam que ter conhecimento especial do comportamento inesperado do subtipo. Isso começa a quebrar o Open/Closed Principle.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Em resumo, toda violação do LSP se torna uma violação do OCP. Então, como corrigir?&lt;/p&gt;

&lt;p&gt;Uma possível modificação para respeitar o princípio seria mudar a interface &lt;strong&gt;Vehicle&lt;/strong&gt; para ter um método mais genérico, como &lt;strong&gt;Recharge&lt;/strong&gt;, em vez de &lt;strong&gt;Refuel&lt;/strong&gt;. Assim, cada subtipo pode implementar esse método de acordo com a sua fonte de energia, seja gasolina ou eletricidade.&lt;/p&gt;

&lt;p&gt;Outra possível modificação seria criar uma interface separada para os veículos elétricos, como &lt;strong&gt;ElectricVehicle&lt;/strong&gt;, que tenha um método específico para recarregar a bateria, como &lt;strong&gt;RechargeBattery&lt;/strong&gt;. Assim, o &lt;strong&gt;ElectricCar&lt;/strong&gt; implementaria essa interface e não haveria conflito com o método &lt;strong&gt;Refuel&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Aqui está um exemplo de código usando a segunda modificação:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Depois disso tudo vocês podem estar pensando: "Ah, Wali, com código de mentirinha é tudo muito fácil, quero ver no mundo real." Então vejamos um exemplo de aplicação do LSP no mudo real: &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Neste exemplo, temos a definição da interface &lt;strong&gt;Cache&lt;/strong&gt;, com os métodos Get, Set e Delete, e as implementações &lt;strong&gt;RedisCache&lt;/strong&gt; e &lt;strong&gt;MemoryCache&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;UserService&lt;/strong&gt; utiliza a interface Cache como dependência, permitindo a troca entre o &lt;strong&gt;RedisCache&lt;/strong&gt; e o &lt;strong&gt;MemoryCache&lt;/strong&gt; sem problemas.&lt;/p&gt;

&lt;p&gt;No cenário apresentado, o LSP poderia ser quebrado se a implementação específica de algum método de Cache na struct derivada não cumprisse as mesmas garantias e pré-condições definidas pela interface.&lt;/p&gt;

&lt;p&gt;Por exemplo, se a implementação do método Get em MemoryCache lançasse um erro diferente ou não respeitasse a garantia de retornar um erro quando a chave não é encontrada, isso quebraria o LSP. Da mesma forma, se a implementação do método Set em RedisCache não armazenasse corretamente os valores no Redis, ou a implementação do método Delete não excluísse corretamente as chaves, isso também violaria o LSP.&lt;/p&gt;

&lt;p&gt;Isso é tudo, pessoal! Até a próxima!&lt;/p&gt;

&lt;p&gt;Referências:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.cleancoder.com/uncle-bob/2020/10/18/Solid-Relevance.html" rel="noopener noreferrer"&gt;Clean Coder Blog - SOLID Relevance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://levelup.gitconnected.com/practical-solid-in-golang-liskov-substitution-principle-e0d2eb9dd39" rel="noopener noreferrer"&gt;Practical SOLID in Golang: Liskov Substitution Principle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/java-liskov-substitution-principle" rel="noopener noreferrer"&gt;Baeldung - Liskov Substitution Principle in Java&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>solidprinciples</category>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Princípios SOLID em GoLang - Open/Closed Principle (OCP)</title>
      <dc:creator>Wali Queiroz</dc:creator>
      <pubDate>Mon, 29 Jul 2024 00:27:48 +0000</pubDate>
      <link>https://dev.to/waliqueiroz/principios-solid-em-golang-openclosed-principle-ocp-422p</link>
      <guid>https://dev.to/waliqueiroz/principios-solid-em-golang-openclosed-principle-ocp-422p</guid>
      <description>&lt;p&gt;Dando continuidade à série sobre os princípios SOLID em Go, hoje vamos falar sobre o Open/Closed Principle (OCP). Para ler o primeiro artigo acesse:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/waliqueiroz/principios-solid-em-golang-single-responsability-principle-srp-af5"&gt;Princípios SOLID em GoLang - Single Responsability Principle (SRP)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsnnrii3udksbqubna3jq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsnnrii3udksbqubna3jq.png" alt="Gopher - Open Closed Principle" width="800" height="759"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A definição formal do OCP diz que "um artefato de software deve estar aberto para extensão, mas fechado para modificações".&lt;/p&gt;

&lt;p&gt;Este é provavelmente o princípio mais polêmico e difícil de assimilar logo de cara, afinal de contas, software é evolutivo, é incomum que um programa seja desenvolvido uma vez e nunca mais modificado. Então onde esse princípio tenta chegar?&lt;/p&gt;

&lt;p&gt;Se uma nova funcionalidade precisa ser adicionada, deve ser possível implementá-la criando uma nova classe, módulo ou função, sem precisar modificar o código de outras partes do sistema. Isso significa que as entidades de software devem ser projetadas de forma modular e coesa, com interfaces claras e contratos bem definidos.&lt;/p&gt;

&lt;p&gt;Em resumo, o "fechado para modificações" do OCP não significa que o software nunca pode ser modificado, mas sim que as modificações devem ser realizadas de forma consciente e planejada, sem gerar impactos negativos.&lt;/p&gt;

&lt;p&gt;Agora vamos sair da teoria e ver como isso funciona na prática com GoLang. Vejamos primeiro um exemplo mais lúdico. Observem o código abaixo:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A struct &lt;strong&gt;Calculator&lt;/strong&gt; possui um método &lt;strong&gt;sumAreas&lt;/strong&gt; que define como parâmetro a variável &lt;strong&gt;shapes&lt;/strong&gt;, que pode ser qualquer coisa. Linhas a frente podemos encontrar um switch-case para mapear cada tipo possível. &lt;/p&gt;

&lt;p&gt;O que aconteceria se definíssemos uma forma &lt;strong&gt;Triangle&lt;/strong&gt; e quiséssemos que a área dela fosse somada também? Teríamos que modificar a função sumAreas para mapeá-la e realizar o cálculo, certo? Por esse motivo, o código acima quebra o Open/Closed Principle; para cada nova forma, uma modificação é necessária em sumAreas. Isso pode afetar negativamente a manutenibilidade do código, aumentando a complexidade, o risco de erros e a dificuldade de alterações futuras.&lt;/p&gt;

&lt;p&gt;Então como resolver?&lt;/p&gt;

&lt;p&gt;Podemos delegar a responsabilidade do cálculo das áreas às suas respectivas formas geométricas (alô SRP) e fechar um contrato através de uma interface chamada &lt;strong&gt;Shape&lt;/strong&gt; com um método &lt;strong&gt;Area()&lt;/strong&gt;. Vejamos:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Neste exemplo, a função sumAreas está aberta para extensão porque podemos adicionar novas formas que implementam a interface Shape sem modificá-la. Ela também está fechada para modificação porque não precisamos alterar seu código interno para lidar com novas formas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mas e no mundo real, onde podemos aplicar o Open/Closed Principle?
&lt;/h2&gt;

&lt;p&gt;Vamos supor que você esteja desenvolvendo um sistema de e-commerce e precisa calcular o frete para entrega dos produtos. A função que faz esse cálculo poderia facilmente ser escrita assim:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;O problema com essa implementação é da mesma natureza do que vimos no caso das formas geométricas: sempre que uma nova transportadora for adicionada, será necessário modificar a função &lt;strong&gt;CalculateShipping&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para corrigir essa violação do OCP, podemos criar uma interface &lt;strong&gt;ShippingProvider&lt;/strong&gt; que define um método &lt;strong&gt;CalculateShipping&lt;/strong&gt; e, em seguida, implementar uma struct para cada transportadora. A função CalculateShipping pode receber uma instância da struct correspondente e delegar o cálculo do frete para ela.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Formas práticas de seguir o OCP
&lt;/h2&gt;

&lt;p&gt;Do meu ponto de vista, o Open/Closed Principle é o mais complicado e consequentemente incompreendido dentre os 5 princípios SOLID. Nesse artigo eu trouxe exemplos onde fica claro quando aplicá-lo, mas no dia a dia nem sempre vai ser assim. Precisamos ser capazes de identificar corretamente áreas no código que precisam ser isoladas para que possam ser modificadas sem afetar outras partes do sistema (pontos de variação). Ao mesmo tempo, não queremos desenvolver software com muita complexidade inicial. Tendo isso em mente, aqui estão maneiras práticas de seguir OCP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se você ainda não consegue identificar os pontos de variação em seu código, comece de um jeito simples, mas não simplório. Então, à medida que o sistema evolui, faça sua refatoração e construa a abstração correta em torno desses pontos.&lt;/li&gt;
&lt;li&gt;Se você conhece seus pontos de variação antecipadamente, tente identificar o nível certo de abstração que seu software precisa sem complicar demais as coisas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isso é tudo, pessoal! Até a próxima!&lt;/p&gt;

&lt;p&gt;Referências:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="script%20src="&gt;Clean Coder Blog - The Open Closed Principle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="script%20src="&gt;Open-Closed Principle: The Hard Parts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>solidprinciples</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Princípios SOLID em GoLang - Single Responsability Principle (SRP)</title>
      <dc:creator>Wali Queiroz</dc:creator>
      <pubDate>Mon, 29 Jul 2024 00:15:54 +0000</pubDate>
      <link>https://dev.to/waliqueiroz/principios-solid-em-golang-single-responsability-principle-srp-af5</link>
      <guid>https://dev.to/waliqueiroz/principios-solid-em-golang-single-responsability-principle-srp-af5</guid>
      <description>&lt;p&gt;No mundo do desenvolvimento de software, os princípios SOLID nos dizem como organizar funções e dados de forma que nossos códigos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tolerem mudanças&lt;/li&gt;
&lt;li&gt;Sejam fáceis de entender&lt;/li&gt;
&lt;li&gt;Sejam a base de componentes que podem ser usados em muitos sistemas de software&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O termo SOLID é um acrônimo para cinco postulados de design, descritos a seguir:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(S) Single Responsability Principle (Princípio da Responsabilidade Única)&lt;/strong&gt;: "Um módulo deve ter um, e apenas um motivo para mudar"&lt;br&gt;
&lt;strong&gt;(O) Open/Closed Principle (Princípio Aberto/Fechado)&lt;/strong&gt;: "Um artefato de software deve estar aberto para extensão, mas fechado para modificações"&lt;br&gt;
&lt;strong&gt;(L) Liskov Substitution Principle (Princípio de Substituição de Liskov)&lt;/strong&gt;: "Uma classe derivada deve ser substituível por sua classe base"&lt;br&gt;
&lt;strong&gt;(I) Interface Segregation Principle (Principio da Segregação de Interface)&lt;/strong&gt;: "Uma classe não deve ser forçada a implementar interfaces e métodos que não utilizará"&lt;br&gt;
&lt;strong&gt;(D) Dependency Inversion Principle (Principio da Inversão de Dependência)&lt;/strong&gt;: "Dependa de abstrações e não de implementações"&lt;/p&gt;
&lt;h2&gt;
  
  
  SOLID e GoLang
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbu4mkrzr0kuo21yab7e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbu4mkrzr0kuo21yab7e.jpg" alt="Gopher SOLID" width="800" height="825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O SOLID é pensado para programação orientada a objetos, e é sabido que GoLang não é uma linguagem que adota esse paradigma. Contudo, podemos usar os recursos que ela disponibiliza para atender à metodologia POO. Por exemplo, Go não tem suporte de herança, mas a ideia pode ser compensada com seu suporte de composição. Da mesma forma, um tipo de polimorfismo pode ser criado usando interfaces.&lt;/p&gt;

&lt;p&gt;Nesse artigo, o primeiro de uma série de 5, pretendo detalhar o primeiro princípio com exemplos que se aproximam de situações que nos deparamos no dia a dia.&lt;/p&gt;
&lt;h2&gt;
  
  
  Single Responsibility Principle (SRP)
&lt;/h2&gt;

&lt;p&gt;Já sabemos o que o termo significa, agora é hora de aprender como implementá-lo em GoLang.&lt;br&gt;
Nessa linguagem, poderíamos definir este princípio como “Uma função ou tipo deve ter um e apenas um trabalho, e uma e apenas uma responsabilidade”, vejamos o seguinte código:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Acima, temos uma struct que chamamos de &lt;strong&gt;userService&lt;/strong&gt;. Ela tem duas propriedades: &lt;strong&gt;db&lt;/strong&gt; que é responsável pela comunicação com um banco de dados relacional, e &lt;strong&gt;amqpChannel&lt;/strong&gt;, que viabiliza a comunicação com o serviço de mensageria RabbitMQ.&lt;/p&gt;

&lt;p&gt;UserService implementa um método chamado Create. Dentro desse método armazenamos as informações do usuário recebido no banco de dados e, em seguida, publicamos os dados no RabbitMQ.&lt;br&gt;
Percebe-se que a responsabilidade do método Create no userService não é apenas uma, e sim, duas: armazenar uma informação no banco de dados e publicar uma mensagem numa fila do RabbitMQ.&lt;/p&gt;

&lt;p&gt;Isso pode levar a vários problemas, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dificuldade de manutenção: se um dos requisitos mudar, como por exemplo, a forma como os dados do usuário são serializados, você terá que modificar a lógica do método Create, mesmo que isso não tenha nada a ver com a sua responsabilidade principal, que é salvar os dados no banco de dados.&lt;/li&gt;
&lt;li&gt;Dificuldade de teste: como o método Create tem duas responsabilidades diferentes, você terá que criar testes para cada uma delas, o que pode ser difícil e trabalhoso.&lt;/li&gt;
&lt;li&gt;Acoplamento desnecessário: a lógica de publicação dos dados do usuário em uma fila do RabbitMQ é totalmente independente da lógica de salvar esses dados num banco de dados. Misturar essas duas responsabilidades no mesmo método cria um acoplamento desnecessário.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No código a seguir, modificamos a estrutura para respeitar o SRP. Vejam só:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Observe que separamos as responsabilidades em três partes distintas: o repositório &lt;strong&gt;UserRepository&lt;/strong&gt; para persistir o usuário no banco de dados, o publicador &lt;strong&gt;UserPublisher&lt;/strong&gt; para enviar uma mensagem para o RabbitMQ e o serviço &lt;strong&gt;UserService&lt;/strong&gt; que orquestra essas duas operações.&lt;/p&gt;

&lt;p&gt;Dessa forma, cada componente é responsável por uma tarefa específica e independente, facilitando a manutenção e evolução do código, além de permitir que cada uma dessas partes possa ser substituída ou aprimorada sem afetar as outras. Por exemplo, se for necessário mudar o banco de dados utilizado, basta substituir o repositório. Se for necessário alterar a forma de comunicação, basta alterar o publicador.&lt;/p&gt;

&lt;p&gt;Vale ressaltar que há uma diferença sutil entre executar duas tarefas distintas e delegar a execução delas. No exemplo original do &lt;strong&gt;userService.Create&lt;/strong&gt;, havia a execução de duas operações em um único lugar, violando o princípio da responsabilidade única. Após a refatoração, delegamos as execuções para structs distintas e o método Create ficou responsável apenas por coordenar este fluxo.&lt;/p&gt;

&lt;p&gt;Para aplicar o SRP neste exemplo, também acabamos implementando alguns dos outros princípios SOLID:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;strong&gt;Interface Segregation Principle (ISP)&lt;/strong&gt;: cada interface representa uma única responsabilidade. Tanto o UserRepository quanto o UserPublisher são interfaces que possuem apenas um método, cada um representando uma única responsabilidade.&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;Dependency Inversion Principle (DIP)&lt;/strong&gt;: a struct userService depende de abstrações (interfaces) e não de implementações concretas, ou seja, ela não conhece a implementação específica do UserRepository e do UserPublisher, apenas as interfaces que eles implementam.&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;Open/Closed Principle (OCP)&lt;/strong&gt;: o código está aberto para extensão, uma vez que novos repositórios ou publicadores podem ser facilmente adicionados sem modificar userService.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nos próximos artigos dessa série trarei uma explicação mais detalhada de cada um deles, com exemplos específicos.&lt;/p&gt;

&lt;p&gt;Até mais, galera!&lt;/p&gt;

&lt;p&gt;Referências:&lt;br&gt;
&lt;a href="https://www.digitalocean.com/community/conceptual-articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design#single-responsibility-principle" rel="noopener noreferrer"&gt;SOLID: The First 5 Principles of Object Oriented Design &lt;/a&gt;&lt;br&gt;
&lt;a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html" rel="noopener noreferrer"&gt;Clean Coder Blog - The Single Responsibility Principle&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>solidprinciples</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
