<?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: thayseonofrio</title>
    <description>The latest articles on DEV Community by thayseonofrio (@thayseonofrio).</description>
    <link>https://dev.to/thayseonofrio</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%2F290254%2Ffbab286d-d348-4ab7-8ca2-43d9e74dbcd3.jpeg</url>
      <title>DEV Community: thayseonofrio</title>
      <link>https://dev.to/thayseonofrio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thayseonofrio"/>
    <language>en</language>
    <item>
      <title>Guia rápido de testes no front-end</title>
      <dc:creator>thayseonofrio</dc:creator>
      <pubDate>Mon, 13 Apr 2020 18:26:22 +0000</pubDate>
      <link>https://dev.to/thayseonofrio/guia-rapido-de-testes-no-front-end-2lpc</link>
      <guid>https://dev.to/thayseonofrio/guia-rapido-de-testes-no-front-end-2lpc</guid>
      <description>&lt;p&gt;Ouvimos muito falar sobre a importância de testar nosso código. Queremos ter feedback instantâneo sobre as mudanças que fazemos e ter confiança que o código funciona como planejado, sem precisar esperar ter uma aplicação pronta que possa ser validada. Para isso ser possível, temos diferentes tipos de testes automatizados que podemos implementar na nossa aplicação. Com o Desenvolvimento Orientado a Testes, podemos até mesmo escrever o teste antes de implementar o código, definindo o que esperamos que aquele pedaço de código faça antes que ele exista.&lt;/p&gt;

&lt;p&gt;No Desenvolvimento Ágil, testar é parte da nossa rotina como pessoas desenvolvedoras. É tão importante que, há muito tempo atrás, Mike Cohn introduziu o conceito da Pirâmide de Testes, buscando apresentar uma forma de como pensar a estratégia de testes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Finn0v523cch7npqrgwl6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Finn0v523cch7npqrgwl6.png" alt="Ilustração de uma pirâmide, na base sendo os Testes Unitários. Em cima deles, os Testes de Integração. No topo da pirâmide, estão os Testes de UI. Há uma nuvem em cima com os Testes Manuais. As setas indicam que, conforme sobe na pirâmide, aumentam os esforços e os custos."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na &lt;strong&gt;Pirâmide de Testes&lt;/strong&gt;, vemos mais testes unitários na base, por serem mais rápidos de desenvolver e rodar. A quantidade de testes diminui conforme vamos subindo na pirâmide, pois aumenta o esforço necessário e o tempo de execução de cada tipo de teste. Para fazer um teste de UI, por exemplo, é necessário muito mais esforço e demora mais para rodar e ter feedback. Por isso, segundo a pirâmide, devemos ter menos testes deste tipo.&lt;/p&gt;

&lt;p&gt;Porém, como foi dito, a pirâmide é apenas uma forma de pensar a nossa estratégia de testes, e não um caminho para ser seguido ao pé da letra. Se pensarmos em como colocar em prática em aplicações que são exclusivamente front-end, pode ser que usá-la não faça sentido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Que tipos de testes podemos usar no front-end?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F08tg1ywruvk21bmpd8ud.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F08tg1ywruvk21bmpd8ud.jpg" alt="Ilustração de mulher negra utilizando o laptop com um café ao lado"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes Unitários
&lt;/h3&gt;

&lt;p&gt;É o tipo de testes que mais ouvimos falar. Podemos considerar uma unidade como sendo a menor parte de um código. Pode ser uma função, por exemplo. Quando falamos de testes unitários, estamos verificando que essa pequena parte de código faz o que deveria fazer, independente de outras unidades.&lt;br&gt;
Esse tipo de teste é rápido e fácil de escrever e, por isso, é recomendo escrever muitos destes. Quanto mais partes do código conseguirmos testar com esse tipo de teste, menos vamos precisar fazer os outros tipos de testes, que são mais custosos.&lt;/p&gt;

&lt;p&gt;Quando desenvolvemos software para o front-end, muitas vezes trabalhamos com componentes. Os testes unitários nos permitem garantir que eles funcionam como esperado de forma isolada, mas também é preciso saber se esses componentes funcionam quando utilizados de forma conjunta. Por exemplo, podemos alterar as propriedades que um componente espera receber e alterar seus testes unitários, garantindo que continua funcionando de forma isolada. Os testes unitários vão continuar passando. Porém, como saber que os outros componentes que o utilizam não vão parar de funcionar com essa mudança? Para isso, podemos precisar de outros tipos de testes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Algumas Ferramentas&lt;/em&gt;: &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt;, &lt;a href="https://jasmine.github.io/" rel="noopener noreferrer"&gt;Jasmine&lt;/a&gt;, &lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;Mocha&lt;/a&gt; e &lt;a href="https://www.chaijs.com/" rel="noopener noreferrer"&gt;Chai&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes de Integração
&lt;/h3&gt;

&lt;p&gt;Nós já sabemos que as unidades do nosso código estão funcionando corretamente de forma isolada, mas precisamos garantir que, quando uma parte se comunicar com a outra, as coisas vão funcionar como esperado.&lt;br&gt;
No front-end, eu acredito que os testes de integração são ainda mais importantes, porque queremos nos certificar de que nossos componentes funcionam conforme esperado quando estão sendo usados em conjunto.&lt;/p&gt;

&lt;p&gt;Por exemplo, se tivermos um formulário contendo vários inputs diferentes e com um botão para enviar os dados. Queremos testar que, ao preencher todos os dados corretamente e clicar no botão, veremos a mensagem de sucesso esperada. Sendo cada input e botão um componente separado, não seria suficiente testar cada um isoladamente.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Algumas Ferramentas&lt;/em&gt;: &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt; e &lt;a href="https://www.cypress.io/" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes E2E
&lt;/h3&gt;

&lt;p&gt;Os testes end-to-end vão ainda além. Com eles, testamos os componentes trabalhando de forma integrada, mas pensando na jornada do usuário.&lt;br&gt;
Podemos utilizar ferramentas que automatizam ações que seriam realizadas pelo usuário em um contexto real. A aplicação é iniciada no browser, que navega para a nossa página e executa as ações que forem definidas, como clicando em botões, preenchendo campos e verificando se os resultados são conforme esperado.&lt;/p&gt;

&lt;p&gt;É necessário investir mais esforço para escrever esses testes e eles demoram mais para rodar, porém é o tipo de teste que nos traz mais confiança, pois sabemos que a aplicação está funcionando exatamente como esperado para o fluxo que será utilizado pelo usuário. É importante ter cuidado para não testar a mesma coisa em testes diferentes, tornando esse tipo de teste ainda mais custoso.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Algumas Ferramentas&lt;/em&gt;: &lt;a href="https://www.cypress.io/" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt; (❤️), &lt;a href="https://github.com/DevExpress/testcafe" rel="noopener noreferrer"&gt;TestCafe&lt;/a&gt; e &lt;a href="https://github.com/puppeteer/puppeteer" rel="noopener noreferrer"&gt;Puppeteer&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes de Snapshot
&lt;/h3&gt;

&lt;p&gt;Esse tipo de teste é focado na interface. A ideia é ter certeza que, quando fizermos quaisquer alterações, ela não terá mudanças inesperadas.&lt;/p&gt;

&lt;p&gt;Quando um teste de snapshot é criado, ele renderiza o componente, ou seja, transforma em algo que o navegador consegue entender e mostrar na tela. Em seguida, "tira uma foto" do que foi renderizado, e guarda aquela imagem. Cada vez que os testes forem rodados, o que for renderizado é comparado com a imagem que estava guardada. Se houver alguma diferença, o teste falha e sabemos que algo na nossa interface foi alterado, sem precisar rodar a aplicação inteira pra isso. Se fizemos uma alteração intencional na interface, basta atualizarmos a imagem daquele teste.&lt;/p&gt;

&lt;p&gt;Esse tipo de teste não substitui os outros, pois tem objetivos diferentes e devem ser usados em conjunto. Os testes de snapshot ajudam a ver exatamente o que foi alterado e de uma forma bem simples.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Algumas Ferramentas&lt;/em&gt;: &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes de Acessibilidade
&lt;/h3&gt;

&lt;p&gt;Quando escrevemos software para o front-end, é muito importante manter em mente a acessibilidade. Queremos remover barreiras que possam impedir pessoas de utilizar nossa aplicação. Existem uma série de padrões de como desenvolver software que é acessível para todas.&lt;/p&gt;

&lt;p&gt;Nós podemos ter testes automatizados que verificam esse aspecto do nosso código. Existem diversas ferramentas que nos permitem fazer isso, verificando se não temos nenhuma violação das diretrizes de acessibilidade na web.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Algumas Ferramentas&lt;/em&gt;: &lt;a href="https://github.com/nickcolley/jest-axe" rel="noopener noreferrer"&gt;Jest Axe&lt;/a&gt; e &lt;a href="https://github.com/pa11y/pa11y-ci" rel="noopener noreferrer"&gt;Pa11y&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Verificação de Tipos Estáticos
&lt;/h3&gt;

&lt;p&gt;Por mais que não seja exatamente um tipo de teste, a verificação de tipos estáticos pode ser muito útil quando trabalhamos com linguagens como Javascript. Utilizando ferramentas que trazem essa funcionalidade, podemos identificar problemas e possíveis erros antes mesmo de executar o código. Esse tipo de verificação pode tornar nosso processo de desenvolvimento mais produtivo e trazer mais confiança sobre o código.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Algumas Ferramentas&lt;/em&gt;: &lt;a href="https://flow.org/" rel="noopener noreferrer"&gt;Flow&lt;/a&gt; e &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Existem muitos outros tipos de testes que podemos utilizar no front-end. Escolher quais tipos vamos utilizar depende do contexto do nosso projeto e do que for decidido com a equipe. O que sabemos é que a abordagem tradicional nem sempre é válida aqui, sendo necessário adaptar os tipos, e a quantidade de cada tipo, para o que faz sentido no nosso contexto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escreva código fácil de testar
&lt;/h2&gt;

&lt;p&gt;Quando trabalhamos com um código em que há muitas dependências e em que as responsabilidades não estão bem definidas, escrever testes pode se tornar uma tarefa chata e difícil. Por isso, é importante ter em mente que queremos escrever código que seja fácil de testar.&lt;/p&gt;

&lt;p&gt;Podemos fazer isso tendo em mente alguns princípios quando estamos desenvolvendo, como manter uma única responsabilidade para cada pedaço de código (uma função deve fazer apenas uma coisa, por exemplo), buscar ter menos dependências entre diferentes partes do código e, ainda mais relevante para o front-end, manter a lógica de negócio separada da interface da aplicação. Escrever código fácil de testar também ajuda a tornar o código mais legível, fácil de dar manutenção e de implementar funcionalidades novas.&lt;/p&gt;

&lt;p&gt;Outra forma de fazer isso é ter o desenvolvimento sendo guiado por testes, escrevendo o teste antes mesmo de implementar o código. É o que conhecemos por TDD (Test Driven Development) e que também pode ser utilizado no front-end. Dessa forma, pensamos no comportamento que estamos esperando para aquela funcionalidade e escrevemos um teste para isso. O teste irá falhar, pois a funcionalidade ainda não existe. Logo após, implementamos o código e rodamos o teste novamente, que agora irá passar. Seguimos nesse fluxo também para fazer refatorações, garantindo que aquele pedaço de código faz somente o que é esperado dele e que está funcionando corretamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Legal, mas por onde eu começo?
&lt;/h3&gt;

&lt;p&gt;Implementar uma aplicação com uma estratégia de testes bem pensada é ótimo na teoria, mas na prática sabemos que é muito mais complicado. Diversas vezes grande parte da aplicação já foi escrita e com quase nenhum teste. Como saber onde começar a testar as funcionalidades que já existem?&lt;/p&gt;

&lt;p&gt;Nesse caso, acredito que faz mais sentido começar pelo fim. Podemos utilizar os testes E2E para garantir que a aplicação funciona conforme esperado pelo usuário, testando de forma automatizada os principais fluxos e garantindo que eles não irão quebrar quando fizermos alterações ou incluirmos novas funcionalidades. Depois, podemos começar a inserir os outros tipos de testes no nosso processo de desenvolvimento e aos poucos ir "equilibrando".&lt;/p&gt;

&lt;p&gt;Independente da estratégia de testes que decidirmos seguir, o importante é começar uma conversa e estimular a cultura de testes, tendo em mente que todo o time é responsável pela qualidade.&lt;/p&gt;

</description>
      <category>ptbr</category>
      <category>testing</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to get started with Design Patterns</title>
      <dc:creator>thayseonofrio</dc:creator>
      <pubDate>Thu, 13 Feb 2020 23:36:12 +0000</pubDate>
      <link>https://dev.to/thayseonofrio/how-to-get-started-with-design-patterns-iai</link>
      <guid>https://dev.to/thayseonofrio/how-to-get-started-with-design-patterns-iai</guid>
      <description>&lt;p&gt;When we are learning how to code, we usually only worry about making software work - and that’s already pretty important. However, as we make progress towards our journey as software developers, we start considering other aspects that can improve the quality of the things we develop. For instance, if we are working on a project with other people, how can we make the code more readable, easy to understand, to maintain, and to evolve? How can we avoid code duplication? How can we make the code more flexible? &lt;/p&gt;

&lt;p&gt;We often hear some concepts related to trying to solve these issues, such as the famous Design Patterns. However, what exactly are Design Patterns? We can start talking about the things they &lt;strong&gt;are not&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Design Patterns are not magic formulas that solve problems. They are not code snippets that can be inserted into our application. They are also not algorithms. Design Patterns, as the name suggests, are just patterns that offer a concept of a solution for a design problem that happens frequently. Implementation of each pattern can change according to the domain, language, and other factors. These patterns were created from the experience of several developers who were trying out different solutions for recurring problems they faced. A book called &lt;a href="https://www.amazon.com/dp/B000SEIBB8/"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt; was published a long time ago and presented 23 Design Patterns. Since then, other patterns were identified. These patterns have even come to influence programming languages and, as everything in software engineering, they are frequently changing. &lt;/p&gt;

&lt;h3&gt; Why should we learn Design Patterns? &lt;/h3&gt;

&lt;p&gt;Imagine you’re doing something for the first time. For instance, learning a new recipe. You know where you want to get and you have an ideia of how to mix the ingredients to do so. However, it would be very helpful if you could follow a recipe that would guide you to achieve this result in a way that several people have done before and avoiding common problems in the way. That’s sort of how it works with design patterns.&lt;br&gt;
A lot of developers have tested these patterns, faced these problems, and documented these solutions. Besides that, Design Patterns define a common language for us to talk about possible solutions with our teams, for instance, while pairing. &lt;/p&gt;

&lt;h3&gt; Is it the same as SOLID principles? &lt;/h3&gt;

&lt;p&gt;No, but it has everything to do with it. Actually, I believe it’s necessary to have a better understanding of &lt;strong&gt;SOLID principles&lt;/strong&gt; before starting to study Design Patterns, because these principles are used in most of the patterns.  The goal is to help us create software that is easy to maintain and to understand. The name SOLID is an acronym for: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt;ingle Responsibility: a class should have only one responsibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O&lt;/strong&gt;pen/Closed: classes should be closed for change and open for extension. In other words, if a class works properly and has been tested, we should avoid changing it. To insert new behaviour, we should extend the class instead of modifying it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L&lt;/strong&gt;iskov Substitution: a subclass should be able to substitute the superclass without changing the behaviour of the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I&lt;/strong&gt;nterface Segregation: a class shouldn’t depend on methods it doesn’t use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D&lt;/strong&gt;ependency Inversion: dependencies can determine how easy it is to make changes to the system. If we have a lot of them, that can lead to high coupling. This principle says that high level modules should depend on high level generalisations, and not on details. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Design Patterns follow some of these design principles to cover topics such as flexibility and maintainability. For instance, a lot of Design Patterns use the Open/Closed system, following the idea that it should be possible to extend your software, or the Dependency Inversion patterns, abstracting behaviour through interfaces. That’s why it makes sense to first have a good understanding of design principles and then continue to Design Patterns. &lt;/p&gt;

&lt;h3&gt; What type of Design Patterns exist? &lt;/h3&gt;

&lt;p&gt;&lt;code&gt; Design Patterns were classified in three different types, based on its purpose. &lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creational Patterns&lt;/strong&gt; are about the process of creating objects. Depending on the context or on our goal, the traditional way of creating objets might not be the best solution. For example, if we have a class that connects to a database, we may want to create just one instance of this class, instead of having new connections in different places of the system. For that we can use a pattern called Singleton. There are other patterns included in Creational Patterns, such as Factory Method, Builder, Prototype, and others, all of them trying to solve problems related to the creation of objects. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structural Patterns&lt;/strong&gt; entails how objects are connected and their relationships. These patterns are necessary because the more a system grows, the more complex it gets. With more complexity, we need to find a sustainable way of maintaining the relationship between objects in which we allow for the creation of new functionality in a simple manner. For instance, let’s say we created a hamburger and we want to add items dynamically, such as extra cheese or a salad. Instead of creating a hamburger class and several subclasses with each type of additional item, we could apply the Decorator patterns, which uses aggregation to dynamically combine behaviours. Other well known patterns in this category include Adapter, Composite, and Facade.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioural Patterns&lt;/strong&gt; deal with how objects distribute work, how they collaborate to achieve a common goal. If we go back to the hamburger case and we want to let our customers know every time a hamburger is ready for delivery, we can use a pattern from this category, which is called Observer. We would have clients observing and waiting to be notified. This type of pattern include others well known, such as Command, Iterator, and Strategy. &lt;/p&gt;

&lt;h3&gt; How can we know which patterns to use? &lt;/h3&gt;

&lt;p&gt;There is a huge catalog of Design Patterns and it’s very unlikely we will remember all of them after reading a book about the subject. The important thing is to first know that these patterns exist. After that, we need to understand what problem we are trying to solve. Then, we can deepen our knowledge in the patterns that try to solve these problems. Having a better understanding of how the pattern is applied and looking at example code is a good starting point. It’s important to remember there is no “right answer” when it comes to Design Patterns. It is a choice that should be made based on the context and its needs, and evaluating the trade-offs. &lt;/p&gt;

&lt;h4&gt; References and Study Materials &lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Book: Design Patterns: Elements of Reusable Object-Oriented Software&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sourcemaking.com/design_patterns"&gt;https://sourcemaking.com/design_patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://refactoring.guru/design-patterns"&gt;https://refactoring.guru/design-patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursera.org/learn/design-patterns/"&gt;https://www.coursera.org/learn/design-patterns/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/solid-principles"&gt;https://www.baeldung.com/solid-principles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;a href="https://dev.to/thayseonofrio/como-comecar-com-design-patterns-31f2"&gt; Originally posted in Portuguese - PT-BR &lt;/a&gt; &lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>solid</category>
      <category>beginners</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Como começar com Design Patterns</title>
      <dc:creator>thayseonofrio</dc:creator>
      <pubDate>Thu, 06 Feb 2020 12:26:14 +0000</pubDate>
      <link>https://dev.to/thayseonofrio/como-comecar-com-design-patterns-31f2</link>
      <guid>https://dev.to/thayseonofrio/como-comecar-com-design-patterns-31f2</guid>
      <description>&lt;p&gt;Quando estamos aprendendo a programar, é comum nos preocuparmos apenas em fazer o software funcionar — e essa já é uma parte bem importante. Porém, ao caminharmos na nossa jornada como desenvolvedoras de software, começamos a pensar em outros aspectos acerca de como podemos melhorar a qualidade do que desenvolvemos. Se estamos trabalhando em um projeto com mais pessoas, por exemplo, como podemos tornar esse código mais legível, fácil de entender, dar manutenção e criar nossas funcionalidades em cima do que já existe? Como podemos evitar a duplicação do código? Como tornar o código mais flexível?&lt;/p&gt;

&lt;p&gt;Existem alguns termos que ouvimos com frequência que buscam solucionar essas questões, como as famosas Design Patterns (Padrões de Projeto). Mas afinal, o que são Design Patterns? Podemos começar falando sobre o que elas &lt;strong&gt;não são&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Design Patterns não são fórmulas mágicas que solucionam problemas, não são códigos prontos que inserimos nas nossas aplicações e também não são algoritmos. Design Patterns, como o nome diz, são apenas padrões que oferecem um conceito de uma solução para um problema de design que acontece com frequência. A implementação de cada padrão pode variar muito de acordo com o domínio, a linguagem utilizada e outros fatores. Esses padrões foram criados a partir da experiência de pessoas desenvolvedoras, que foram experimentando soluções diferentes para problemas recorrentes que encontraram ao longo dos anos. Um livro chamado &lt;a href="https://www.amazon.com.br/dp/B016N8RJUQ/"&gt;Padrões de Projeto — Soluções Reutilizáveis de Software Orientado a Objetos&lt;/a&gt; foi publicado há um bom tempo atrás, apresentando 23 Padrões de Projeto, e, desde então, muitos outros padrões já foram identificados. Esses padrões até mesmo influenciaram linguagens de programação e, como tudo na área de engenharia de software, estão em constante mudança.&lt;/p&gt;

&lt;h3&gt; Por que aprender Design Patterns? &lt;/h3&gt;

&lt;p&gt;Imagine que você está fazendo algo novo pela primeira vez. Por exemplo, aprendendo uma receita nova. Você sabe em qual resultado quer chegar e tem uma ideia de como misturar os ingredientes para isso. Porém, ajudaria muito se você pudesse consultar uma receita que te guiasse para chegar nesse resultado de uma forma que muitas pessoas já fizeram antes, evitando muitos problemas que você poderia encontrar ao longo do caminho. É mais ou menos assim que funciona com os padrões de projeto.&lt;br&gt;
Muitas pessoas desenvolvedoras já testaram esses padrões, enfrentaram esses problemas e documentaram essas soluções. Além disso, Design Patterns definem uma linguagem única para que possamos conversar sobre soluções possíveis com nosso time, até mesmo durante o pareamento.&lt;/p&gt;

&lt;h3&gt; É a mesma coisa que princípios SOLID? &lt;/h3&gt;

&lt;p&gt;Não, mas tem tudo a ver. Na verdade, acredito ser necessário aprofundar conhecimentos nos princípios SOLID antes de começar a estudar Design Patterns, até porque esses princípios são utilizados em muitos dos padrões. O objetivo é nos ajudar a criar software de fácil manutenção e entendimento. O nome SOLID é um acrônimo para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt;ingle Responsibility: uma classe deve ter uma única responsabilidade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O&lt;/strong&gt;pen/Closed: as classes devem estar fechadas para mudanças e abertas para extensão. Ou seja, se uma classe funciona direitinho e já foi testada, deve ser evitado alterar ela. Para inserir um novo comportamento, devemos extender a classe ao invés de modificá-la.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L&lt;/strong&gt;iskov Substitution: uma subclasse deve poder substituir a superclasse sem alterar o comportamento do sistema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I&lt;/strong&gt;nterface Segregation: uma classe não deve depender de métodos que não usa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D&lt;/strong&gt;ependency Inversion: as dependências podem determinar o quão fácil é fazer mudanças no sistema. Se tivermos muitas, isso pode levar a alto acoplamento. Esse princípio diz que módulos de alto nível devem depender de generalizações de alto nível, e não de detalhes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Os padrões de projeto seguem alguns destes princípios de design para cobrir assuntos como flexibilidade e manutenção. Por exemplo, muitas Design Patterns utilizam o princípio Open/Closed, seguindo a ideia de que deve ser possível extender seu software, ou então o princípio de Dependency Inversion, generalizando comportamentos através de interfaces. Por isso, faz sentido entender bem esses princípios de design para então seguir para as Design Patterns.&lt;/p&gt;

&lt;h3&gt; Que tipos de Design Patterns existem? &lt;/h3&gt;

&lt;p&gt;&lt;code&gt; Os padrões de projeto foram classificados em três tipos diferentes, com base no seu propósito. &lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Os padrões de criação, ou &lt;strong&gt;Creational Patterns&lt;/strong&gt;, são sobre o processo de criar objetos. Dependendo do contexto ou do nosso objetivo, a forma tradicional de criação pode não ser a melhor solução. Por exemplo, se tivermos uma classe para conexão com banco de dados, podemos querer ter apenas uma instância da classe, ao invés de ter novas conexões em diversos lugares do sistema. Para isso, poderíamos usar o padrão chamado Singleton. Existe ainda outros padrões que se encaixam no tipo Creational Patterns, como o Factory Method, Builder, Prototype, entre outros, todos buscando solucionar problemas relacionados a criação de objetos.&lt;/p&gt;

&lt;p&gt;Os padrões estruturais, ou &lt;strong&gt;Structural Patterns&lt;/strong&gt;, envolvem como os objetos se conectam e se relacionam. Esses padrões são necessários porque quanto mais um sistema cresce, mas complexo tende a ficar. Com mais complexidade, precisamos encontrar uma maneira sustentável de fazer os objetos se relacionarem e que permita a criação de novas funcionalidades de forma mais simples. Por exemplo, digamos que criamos um hambúrguer e queremos adicionar itens dinamicamente, como queijo extra ou salada. Ao invés de criarmos uma classe hambúrguer e diversas subclasses com cada tipo de item adicional, poderíamos aplicar o padrão Decorator, que utiliza agregação para combinar comportamentos dinamicamente. Outros padrões conhecidos deste tipo incluem Adapter, Composite e Facade.&lt;/p&gt;

&lt;p&gt;Os padrões de comportamento, ou &lt;strong&gt;Behavioural Patterns&lt;/strong&gt;, lidam com a forma que os objetos distribuem o trabalho, como colaboram para atingir um objetivo comum. Se voltarmos para o caso do hambúrguer, e quisermos avisar nossos clientes sempre que um hambúrguer ficar pronto, poderíamos utilizar um padrão desse tipo, o Observer, no qual teríamos clientes observando e esperando serem notificados. Esse tipo de padrão inclui outros muito utilizados, como Command, Iterator e Strategy.&lt;/p&gt;

&lt;h3&gt; Como saber quais padrões utilizar? &lt;/h3&gt;

&lt;p&gt;Há um catálogo grande de Design Patterns e dificilmente vamos decorar todos depois de ler um livro sobre o assunto. O importante é, primeiramente, saber que esses padrões existem. Depois, entender qual problema estamos tentando resolver e, então, nos aprofundarmos nos padrões que buscam solucionar esses problemas. Entender melhor como o padrão é aplicado e olhar códigos de exemplo é um bom ponto de partida. É importante lembrar que não existe uma "resposta certa" quando se trata de Design Patterns, é uma escolha que deve ser tomada com base no contexto, nas necessidades e avaliando o trade-off.&lt;/p&gt;

&lt;h4&gt; Referências e Materiais de Estudo &lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Livro: Padrões de Projetos: Soluções Reutilizáveis de Software Orientados a Objetos&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sourcemaking.com/design_patterns"&gt;https://sourcemaking.com/design_patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://refactoring.guru/design-patterns"&gt;https://refactoring.guru/design-patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursera.org/learn/design-patterns/"&gt;https://www.coursera.org/learn/design-patterns/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/solid-principles"&gt;https://www.baeldung.com/solid-principles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;a href="https://dev.to/thayseonofrio/how-to-get-started-with-design-patterns-iai"&gt; English version of article &lt;/a&gt; &lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>codequality</category>
      <category>solid</category>
      <category>ptbr</category>
    </item>
  </channel>
</rss>
