<?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>Forem: Raphael Silva</title>
    <description>The latest articles on Forem by Raphael Silva (@raphadeveloper).</description>
    <link>https://forem.com/raphadeveloper</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%2F272229%2Fde23fce6-ffa2-4e17-a4d2-1761bc560ef6.jpg</url>
      <title>Forem: Raphael Silva</title>
      <link>https://forem.com/raphadeveloper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/raphadeveloper"/>
    <language>en</language>
    <item>
      <title>Software design: its importance and tips for creating good designs.</title>
      <dc:creator>Raphael Silva</dc:creator>
      <pubDate>Mon, 26 Jun 2023 01:59:07 +0000</pubDate>
      <link>https://forem.com/raphadeveloper/software-design-its-importance-and-tips-for-creating-good-designs-mh3</link>
      <guid>https://forem.com/raphadeveloper/software-design-its-importance-and-tips-for-creating-good-designs-mh3</guid>
      <description>&lt;p&gt;Software design is the way we organize the elements that make up the code, the separation, the dependencies, and how these elements communicate with each other.&lt;/p&gt;

&lt;p&gt;Careful attention to software design is essential to enable application evolution with the least cost and effort possible. In addition to making development more enjoyable for everyone on the team and enabling the constant delivery of value, it accommodates changes in a natural way.&lt;/p&gt;

&lt;p&gt;A good design minimizes maintenance costs because its elements are clear and easily understandable, which impacts the ability to adapt to the inevitable and unexpected changes that occur during the lifecycle of a system.&lt;/p&gt;

&lt;p&gt;Investing in good design is extremely important, and all developers need to take on this responsibility. Therefore, in this article, I will provide some tips for creating good designs.&lt;/p&gt;

&lt;p&gt;The purpose of this article is to introduce the concepts, principles, patterns, and practices that are essential for creating good designs. I believe that each topic covered deserves a series of articles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accidental complexity x Inherited complexity
&lt;/h3&gt;

&lt;p&gt;One of the worst things in programming is complexity. It disrupts the team's workflow and compromises the quality of the product. To make matters worse, as programmers, we have a special knack for creating complex code and solutions. Making things simple is not an easy task, so it's worth starting by discussing the relationship between software design and complexity.&lt;/p&gt;

&lt;p&gt;We can consider two types of complexity: accidental and inherent. Accidental complexity is directly related to the solution we create for a specific problem. This type of complexity often occurs when we propose a solution that not only solves the current problem but also takes into account possible scenarios that may never happen, or when we create confusing code that doesn't reveal its intention. The code works, but it's difficult to identify what it does and why it performs a certain action. Therefore, we should avoid this type of complexity as it significantly increases the cost of maintaining the software.&lt;/p&gt;

&lt;p&gt;On the other hand, there is inherent complexity, which is related to the problem to be solved. Sometimes, the problem itself is complex and naturally requires a complex solution. We cannot avoid this type of complexity, but we should think of ways to minimize its impact.&lt;/p&gt;

&lt;p&gt;Knowing the difference between these two types of complexity is a good starting point for creating good designs and, consequently, good products.&lt;/p&gt;

&lt;p&gt;Computers are capable of "understanding" any code we write, whether it is complex or not, but it is people who modify and are responsible for evolving the software. Therefore, by caring about the complexity of the solutions we create, we are directly contributing to the ability to evolve the products we develop and to the quality of life of our colleagues.&lt;/p&gt;

&lt;p&gt;A good design eliminates accidental complexity and hides inherent complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple Design
&lt;/h3&gt;

&lt;p&gt;More than just a practice, Simple Design is a programming style that leads us to think and create simple solutions that meet current requirements without speculating about possible future changes. Instead of trying to predict how the software will change, we focus on what it needs to do today. We invest time and effort in creating code that reflects the requirements as clearly as possible, using practices that ensure its proper functioning. We see each change as an opportunity for learning and design evolution, preparing the software to accommodate these changes naturally. We rely on design principles that help us create code that meets current requirements and is also ready to evolve easily.&lt;/p&gt;

&lt;p&gt;This programming style distances us from accidental complexity and encourages us to think of solutions that hide inherent complexity, resulting in software that delivers the expected value and can be easily evolved. Moreover, these practices have an extremely positive psychological effect on programmers. We stop worrying about non-existent problems and focus on what needs to be done today. Anxiety decreases, allowing us to give our best to the things that truly matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean Code
&lt;/h3&gt;

&lt;p&gt;Clean Code represents the details of the code. It's about being aware that details matter and that code is the only valid representation of the software. We are communicators, and code is our primary communication tool. Therefore, we should care about the expressiveness, clarity, and intention of the code we create. We should strive to write code that is easy to read and not only functions correctly but also reveals its purpose in a simple and straightforward manner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Principles
&lt;/h3&gt;

&lt;p&gt;Design principles are the result of experiences lived by programmers who noticed common characteristics among software that evolved more easily. These characteristics were transformed into principles that help us in constructing software that meets current needs and is ready to evolve.&lt;/p&gt;

&lt;p&gt;We constantly have to make decisions that directly impact the design of the code. By understanding design principles, we can make informed decisions.&lt;/p&gt;

&lt;p&gt;In addition to enabling the creation of good designs, mastering these principles is crucial in the process of learning and using design patterns. Essentially, patterns are based on principles and provide a proven and documented way to apply them to solve a problem while ensuring the quality of the code design. Therefore, mastering design principles facilitates the learning and application of patterns, making us capable of devising patterns to solve specific problems in our software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Patterns
&lt;/h3&gt;

&lt;p&gt;Design patterns are documented and widely adopted solutions for solving problems in code development. Their purpose is to create flexible and expressive code. Understanding patterns, their intentions, and, most importantly, mastering the principles and values they are based on significantly elevates our ability to create good code.&lt;/p&gt;

&lt;p&gt;Furthermore, due to their widespread usage and documentation, applying patterns facilitates communication. Each pattern carries a wealth of information, and simply mentioning that a particular pattern was used allows others to envision the implementation details.&lt;/p&gt;

&lt;p&gt;On the other hand, misuse of patterns can increase application complexity. A common scenario is trying to use a pattern to solve an inappropriate problem, similar to using a screwdriver to hammer a nail. Patterns were not created to be used in such a manner. Hence, it is crucial to understand patterns, knowing when to use them and, more importantly, when not to use them.&lt;/p&gt;

&lt;p&gt;A good time to employ patterns is during refactoring. This is when we focus on improving the code design, which may already exhibit some issues. Thus, we can identify whether applying a pattern is appropriate to address the existing problems.&lt;/p&gt;

&lt;p&gt;We should know and master design patterns, understanding their intentions, and use refactoring to identify problems that can be resolved through the application of a pattern. It is important to remember that patterns were created to solve specific problems. Using them to solve problems they were not designed for can harm the application, increasing its complexity and reducing its ability to respond to changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  TDD
&lt;/h3&gt;

&lt;p&gt;Test Driven Development (TDD) is an excellent tool for code development, and I would like to delve into some of its details and explain why I consider this practice an instrument for creating good code.&lt;/p&gt;

&lt;p&gt;Most high-quality code that I have come across was written by individuals who divide the code-writing process into two phases. The first phase focuses on solving the problem, with little to no effort invested in refining the design. The second phase is dedicated to design refinement. This is because trying to create good design, think about the problem solution, and simultaneously build the code that materializes those thoughts is not always a trivial task. Therefore, it is a good strategy to focus on problem-solving first and then spend time refining the code's design. However, for this strategy to work, it is essential to ensure that changes made to improve the code's design do not affect its behavior. Additionally, this strategy tends to yield better results when there is frequent alternation between these phases during the code's evolution.&lt;/p&gt;

&lt;p&gt;We can use TDD to assist us in code writing, enabling us to focus on the problem to be solved and the design in separate phases through small iterative cycles that provide feedback. This feedback can be utilized to gradually improve the code, all with the guarantee that design improvements will not alter the application's behavior, as long as we have the discipline to follow the TDD rules.&lt;/p&gt;

&lt;p&gt;The 3 rules of TDD are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not write any production code unless there is a failing test.&lt;/li&gt;
&lt;li&gt;Write only enough test code to fail.&lt;/li&gt;
&lt;li&gt;Write the minimum amount of production code necessary to pass the test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The purpose of these 3 rules is to ensure that all written production code is adequately tested because each piece of production code is written to pass a test representing a specific scenario.&lt;/p&gt;

&lt;p&gt;In addition to these rules, TDD consists of the following stages that guide us in correctly applying the technique:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;RED: In this stage, we focus on the scenario we want to implement by creating a test that represents this scenario. The test should fail until the scenario is implemented. It is crucial to execute the test even though it is expected to fail and ensure that the reason for the failure is because the scenario has not yet been implemented.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GREEN: In this stage, we focus on making the test from the previous stage pass. In other words, we concentrate on implementing the scenario without much concern for the code's design. It is important to implement only the minimum necessary for the test to pass, thus avoiding creating code that is not covered by tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;REFACTORING: In this stage, we focus on the design of the code we created. We should analyze it and identify areas for improvement. This is the ideal moment to identify code smells and apply refactoring techniques, applying design principles and patterns to enhance the quality of the code we created.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These stages constitute an iterative cycle that repeats until the development is complete. This cycle provides constant feedback on the code's quality and enables us to take small, continuous steps toward the final goal. These small steps provide a sustainable rhythm and keep us in control of the code throughout the development process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refactoring
&lt;/h3&gt;

&lt;p&gt;Refactoring is the practice of changing the code's design without modifying the application's behavior. Through this practice, we can build software that not only meets the current needs but is also ready to evolve.&lt;/p&gt;

&lt;p&gt;Programming is an art, and like any other art, it requires a series of refinements until the result is truly satisfactory. We don't need to carry the burden of creating perfect code right from the start. Instead, we should commit to making these refinements to improve the code's design and prepare our applications to accommodate changes.&lt;/p&gt;

&lt;p&gt;Unfortunately, some people underutilize this practice. Perhaps because they cannot quickly ensure that refactoring will not impact the software's functionality, they give up on the idea of refactoring. After all, for them, functioning software is better than nothing. However, they may not realize that by doing so, they can negatively influence the software's ability to evolve. Changes that were once simple to make start to become more complex and consequently more costly.&lt;/p&gt;

&lt;p&gt;Knowing the importance of this practice, we need to have peace of mind and confidence when refactoring code. To achieve this, it is crucial to have automated tests that can be run constantly, helping to ensure that changes do not impact the application's behavior. The use of TDD allows us to refactor the code multiple times during its development. As a result, in the end, we have working code, reliable test coverage, and a design that enables the software to continue evolving with the lowest possible cost. Our team members will appreciate this care for the code, including ourselves in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pair Programming and Code Review
&lt;/h3&gt;

&lt;p&gt;We are good at finding issues in other people's code. Knowing this, we can leverage this skill to contribute to others' code and allow them to contribute to ours.&lt;/p&gt;

&lt;p&gt;There are two practices that are helpful for facilitating this exchange of feedback: Pair Programming and Code Review. One of the purposes of these practices is to have code built by more than one person.&lt;/p&gt;

&lt;p&gt;Code Review is a practice that typically occurs after completing the implementation. The code goes through a review stage where others evaluate its functionality, implementation impacts, and, most importantly, the quality of the design. It is a moment to assess the simplicity and intention of the code, as if the reviewers have difficulty understanding the implementation, it is likely that the code can be improved. When this happens, the reviewer should provide feedback to the code creator and help them improve the design.&lt;/p&gt;

&lt;p&gt;Although it is often used after implementation, I believe that Code Review can be better utilized during Pair Programming. Pair Programming is the practice where two people work together on the implementation, sharing the same keyboard. One person is responsible for writing the code while the other assists with research, decision-making, and, most importantly, code review. The great advantage is that during pairing, code review occurs continuously throughout the code-writing process, resulting in a shorter feedback cycle compared to code review conducted after implementation. This prevents the review from becoming a hindrance in the development flow.&lt;/p&gt;

&lt;p&gt;It may seem controversial that the use of Pair Programming can be effective. In theory, it would be more productive if each person worked on a separate task, and this would be true if our most challenging task were writing code. However, we know that's not the case. During software development, there are many factors that influence its success, such as the expected functionality, performance, and adaptability. The software needs to fulfill its intended purpose satisfactorily and be ready to evolve. With this in mind, when we work together towards a common goal, we significantly increase our chances of creating a product that possesses all the desired characteristics because two heads think better than one.&lt;/p&gt;

&lt;p&gt;We can use these practices as an opportunity to exchange feedback that will aid in constructing code that is easy to maintain while also sharing knowledge among team members.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;People expect us to develop software that meets their current needs but is also ready to evolve. Therefore, it is our responsibility to plan the design of our applications. To do so, it is essential to master the concepts, principles, patterns, and practices that assist us in building good designs. Lastly, we must adopt a professional mindset and have the discipline not to compromise the quality of the code we write. Our decisions should contribute to the quality of the software design, as this is the only way to build a product that satisfies customers, adapts to changes, and remains profitable throughout its lifecycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Extreme Programming Explained: Embrace Change, Kent Beck&lt;/li&gt;
&lt;li&gt;Clean Code, Uncle Bob&lt;/li&gt;
&lt;li&gt;TDD By Example, Kent Beck&lt;/li&gt;
&lt;li&gt;Refactoring, Improving the design of existing code, Martin Fowler&lt;/li&gt;
&lt;li&gt;Head First Design Patterns, Eric Freeman and Elisabeth Robson&lt;/li&gt;
&lt;li&gt;Practical Object-Oriented Design: An Agile Primer Using Ruby, Sandi Metz&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cleancode</category>
      <category>tdd</category>
      <category>refactoring</category>
      <category>softwaredesign</category>
    </item>
    <item>
      <title>Design de software: sua importância e dicas para a criação de bons designs</title>
      <dc:creator>Raphael Silva</dc:creator>
      <pubDate>Mon, 03 Oct 2022 11:37:54 +0000</pubDate>
      <link>https://forem.com/raphadeveloper/design-de-software-sua-importancia-e-dicas-para-a-criacao-de-bons-designs-2m26</link>
      <guid>https://forem.com/raphadeveloper/design-de-software-sua-importancia-e-dicas-para-a-criacao-de-bons-designs-2m26</guid>
      <description>&lt;p&gt;Design de software é o modo como organizamos os elementos que compõem o código, a separação, a dependência e a forma como esses elementos se comunicam.&lt;/p&gt;

&lt;p&gt;O cuidado com o design do software é fundamental para que seja possível evoluir a aplicação com o menor custo e esforço possível. Além de tornar o desenvolvimento mais agradável a todas as pessoas do time e possibilitar a entrega de valor constante, acomodando as mudanças de forma natural.&lt;/p&gt;

&lt;p&gt;Um bom design minimiza o custo de manutenção, pois seus elementos são claros e facilmente compreensíveis, o que impacta na capacidade de adaptação às inevitáveis e inesperadas mudanças que acontecem durante o ciclo de vida de um sistema.&lt;/p&gt;

&lt;p&gt;Investir em um bom design é de extrema importância e todas as pessoas desenvolvedoras precisam assumir essa responsabilidade. Portanto, nesse artigo eu trago algumas dicas para a criação de bons designs. &lt;/p&gt;

&lt;p&gt;O propósito deste artigo é introduzir os conceitos, princípios, padrões e práticas, que são fundamentais para a criação de bons designs e acredito que cada tópico abordado merece uma série de artigos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexidade acidental x Complexidade herdada
&lt;/h3&gt;

&lt;p&gt;Uma das piores coisas na programação é a complexidade. Ela atrapalha o ritmo do time e compromete a qualidade do produto. Para piorar, como programadores, temos uma habilidade especial para criar códigos e soluções complexas. Fazer o simples não é uma tarefa fácil, portanto, vale a pena começar falando sobre a relação entre design de software e complexidade.&lt;/p&gt;

&lt;p&gt;Podemos considerar dois tipos de complexidade: a acidental e a herdada. A complexidade acidental está diretamente relacionada com a solução que criamos para um determinado problema. Esse tipo de complexidade geralmente ocorre quando propomos uma solução que não apenas resolve o problema atual, mas também é criada pensando em possíveis cenários que podem nunca acontecer, ou quando criamos um código confuso, que não revela a sua intenção. O código funciona, mas é difícil identificar o que ele faz e porque ele faz determinada ação. Assim, devemos evitar esse tipo de complexidade, pois ela aumenta significativamente o custo de manter o software.&lt;/p&gt;

&lt;p&gt;Por outro lado, existe a complexidade herdada, que está relacionada com o problema a ser resolvido. Em alguns momentos, o problema por si só é complexo e naturalmente exige uma solução complexa. Não podemos evitar esse tipo de complexidade, mas devemos pensar em maneiras de minimizar o seu impacto. &lt;/p&gt;

&lt;p&gt;Saber a diferença entre esses dois tipos de complexidade é um bom começo para começarmos a criar bons designs e, consequentemente, bons produtos. &lt;/p&gt;

&lt;p&gt;O computador é capaz de "entender" qualquer código que escrevemos, seja ele complexo ou não, mas são as pessoas que alteram e são responsáveis por evoluir o software. Portanto, ao nos preocuparmos com a complexidade das soluções que criamos estaremos contribuindo diretamente com a capacidade de evolução dos produtos que desenvolvemos e com a qualidade de vida dos nossos colegas.&lt;/p&gt;

&lt;p&gt;Um bom design elimina a complexidade acidental e esconde a complexidade herdada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple Design
&lt;/h3&gt;

&lt;p&gt;Mais do que uma prática, o Simple Design é um estilo de programação que nos leva a pensar e criar soluções simples, que atendam os requisitos atuais, sem qualquer tipo de especulação sobre possíveis mudanças futuras. Ao invés de tentar prever como o software irá mudar, focamos no que ele precisa fazer hoje. Investimos tempo e esforço na criação de códigos que reflitam os requisitos com a maior clareza possível; utilizamos práticas que garantam o seu funcionamento correto, enxergamos cada mudança como uma oportunidade de aprendizado e evolução do design; preparamos o software para acomodar essas mudanças com naturalidade; nos apoiamos em princípios de design que nos ajudam a criar códigos que atendam os requisitos atuais e que também estejam prontos para evoluir com facilidade.&lt;/p&gt;

&lt;p&gt;Esse estilo de programação nos afasta da complexidade acidental e nos leva a pensar em soluções que escondem a complexidade herdada, tendo como resultado, um software que entrega o valor esperado e pode ser evoluído com facilidade. Além disso, essas práticas geram um efeito psicológico extremamente positivo para quem está programando. Paramos de nos preocupar com problemas que não existem e focamos no que deve ser feito hoje. A ansiedade diminui e com isso conseguimos dar o nosso melhor para as coisas que realmente importam.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean Code
&lt;/h3&gt;

&lt;p&gt;Clean Code representa os detalhes do código. É sobre ter consciência de que os detalhes importam e que o código é a única representação válida do software. Somos comunicadores e o código é a nossa principal ferramenta de comunicação. Desta forma, devemos nos preocupar com a expressividade, clareza e intenção do código que criamos. Devemos criar códigos que sejam fáceis de ler e que não apenas funcionem, mas que também revelem o seu propósito de forma simples e direta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Principles
&lt;/h3&gt;

&lt;p&gt;Os princípios de design são frutos de experiências vividas por programadores, que perceberam algumas características comuns entre softwares que evoluíam com mais facilidade. Essas características foram transformadas em princípios que servem para nos auxiliar na construção de softwares que atendam as necessidades hoje e que estejam prontos para evoluir.&lt;/p&gt;

&lt;p&gt;Constantemente temos que tomar decisões que afetam diretamente o design do código. Ao conhecer os princípios de design, podemos tomar as decisões de forma consciente.&lt;/p&gt;

&lt;p&gt;Além de possibilitar a construção de bons designs, dominar os princípios é fundamental no processo de aprendizagem e utilização de padrões de projeto. Basicamente, os padrões se baseiam nos princípios e é uma forma comprovada e documentada da aplicação deles para resolver um problema garantindo a qualidade do design do código. Portanto, dominar os princípios facilita o processo de aprendizagem e aplicação dos padrões e nos torna capazes de elaborar padrões para resolver problemas específicos do nosso software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Patterns
&lt;/h3&gt;

&lt;p&gt;Os padrões de projeto são soluções documentadas e amplamente adotadas de como resolver um problema no desenvolvimento de um código. Eles têm como propósito, criar um código flexível e expressivo. Conhecer os padrões, entender a intenção de cada um e principalmente dominar os princípios e valores em que eles se baseiam, eleva consideravelmente a nossa habilidade de criar bons códigos.&lt;/p&gt;

&lt;p&gt;Além disso, por se tratar de algo documentado e muito utilizado pelos programadores, a aplicação de padrões facilita a comunicação. Cada padrão possui uma bagagem carregada de informações e o simples fato de dizer a alguém que um determinado padrão foi utilizado, faz com que essa pessoa possa imaginar os detalhes da implementação.&lt;/p&gt;

&lt;p&gt;Em contrapartida, a má utilização dos padrões aumenta a complexidade da aplicação. Uma situação comum é tentar utilizar um padrão para resolver um problema inadequado, é como se tentássemos utilizar uma chave de fenda para bater em um prego. Eles não foram criados para serem usados dessa forma. Por isso, é muito importante conhecer os padrões, para saber quando utilizar e principalmente quando não utilizar.&lt;/p&gt;

&lt;p&gt;Um bom momento para utilizá-los é durante a refatoração. Neste momento estamos focados em melhorar o design do código, que pode já estar apresentando alguns problemas. Assim, podemos identificar se cabe ou não a aplicação de algum padrão para solucionar os problemas existentes.&lt;/p&gt;

&lt;p&gt;Devemos conhecer e dominar os padrões de projeto, entendendo a intenção de cada um e utilizar a refatoração para identificar problemas que podem ser resolvidos através da utilização de algum padrão. É importante lembrar que os padrões foram criados para resolver problemas específicos. Utilizá-los para resolver problemas que eles não foram projetados para solucionar pode prejudicar a aplicação, aumentando a sua complexidade e diminuindo a sua capacidade de responder às mudanças.&lt;/p&gt;

&lt;h3&gt;
  
  
  TDD
&lt;/h3&gt;

&lt;p&gt;Test Driven Development (TDD) é uma excelente ferramenta para a construção de código, dessa forma irei aprofundar em alguns de seus detalhes e no motivo pelo qual eu entendo essa prática como um instrumento para se criar bons códigos.&lt;/p&gt;

&lt;p&gt;A maioria dos códigos com boa qualidade que já li foram escritos por pessoas que dividem o processo da escrita de código em dois momentos. O primeiro momento é focado em resolver o problema, tendo pouco ou nenhum esforço investido no refinamento do design. O segundo momento é dedicado ao refinamento do design. Isso porque tentar criar um bom design, pensar na solução do problema e ainda construir o código que materializa esse pensamento, nem sempre é uma atividade trivial. Sendo assim, é uma boa estratégia focar na solução do problema e em seguida dedicar um tempo para refinar o design do código. Porém, para que essa estratégia funcione, é necessário garantir que alterações para melhorar o design do código não afetarão o seu comportamento. Além disso, essa estratégia tende a trazer melhores resultados quando a alternância entre os momentos acontece várias vezes durante a evolução do código.&lt;/p&gt;

&lt;p&gt;Podemos utilizar o TDD para nos auxiliar na escrita de código, possibilitando focar no problema a ser resolvido e no design em momentos separados, através de pequenos ciclos iterativos que geram feedbacks. Esses feedbacks podem ser utilizados para melhorar o código gradativamente, tudo isso com a garantia de que as melhorias de design não irão alterar o comportamento da aplicação, desde que tenhamos disciplina para aplicar as regras do TDD.&lt;/p&gt;

&lt;p&gt;As 3 regras do TDD:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Não escreva nenhum código de produção se não houver um teste falhando.&lt;/li&gt;
&lt;li&gt;Escreva apenas o código de teste suficiente para falhar.&lt;/li&gt;
&lt;li&gt;Escreva o mínimo necessário de código de produção para fazer o teste passar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O propósito dessas 3 regras é garantir que todo código de produção escrito está devidamente testado, isso porque cada código de produção foi escrito para fazer passar um teste que representa um cenário específico.&lt;/p&gt;

&lt;p&gt;Além dessas regras, o TDD é composto pelas etapas abaixo que nos orientam na aplicação correta da técnica:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;RED: Nessa etapa focamos no cenário que queremos implementar, fazemos isso através da criação de um teste que representa esse cenário, esse teste deve falhar até que o cenário seja implementado. É muito importante executar o teste mesmo sabendo que ele irá falhar e certificar que o motivo pelo qual ele falhou é porque o cenário ainda não foi implementado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GREEN: Nessa etapa focamos em fazer o teste da etapa anterior passar, ou seja, focamos na implementação do cenário sem muita preocupação com o design do código. É muito importante implementar apenas o mínimo necessário para que o teste passe, dessa forma evitamos criar código cujo comportamento não está coberto por teste.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;REFACTORING: Nessa etapa focamos no design do código que criamos, devemos analisá-lo e identificar se existe algo a melhorar, é o momento ideal para identificar os odores do código e através da refatoração aplicar princípios e padrões de design com o propósito de melhorar a qualidade do código que criamos.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Essas etapas constituem um ciclo iterativo que se repetirá até que finalizemos o desenvolvimento. Esse ciclo nos dá feedback constantemente sobre a qualidade do código e nos possibilita dar pequenos passos constantemente em direção ao objetivo final, esses pequenos passos nos proporcionam um ritmo sustentável e nos mantém sob controle do código durante todo desenvolvimento.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refactoring
&lt;/h3&gt;

&lt;p&gt;Refatoração é a prática de alterar o design do código sem modificar o comportamento da aplicação. Através dessa prática, podemos construir softwares que não apenas atendam às necessidades de hoje, mas que também estejam prontos para evoluir.&lt;/p&gt;

&lt;p&gt;Programação é uma arte, e assim como qualquer outra arte, é necessário uma série de refinamentos até que o resultado seja realmente satisfatório. Não precisamos carregar o peso de criar o código perfeito logo de cara. Devemos nos comprometer com a realização desses refinamentos, com o propósito de melhorar o design do código e preparar nossas aplicações para acomodar as mudanças.&lt;/p&gt;

&lt;p&gt;Infelizmente, algumas pessoas exploram pouco essa prática. Talvez por não conseguirem garantir de forma rápida que a refatoração não vai impactar no funcionamento do software, elas acabam desistindo da ideia de refatorar, afinal, para essas pessoas um software que funciona é melhor do que nada. Talvez elas não saibam que ao fazer isso, podem influenciar negativamente a capacidade de evolução do software. Mudanças que até então eram simples de serem feitas começam a ficar mais complexas e consequentemente mais caras.&lt;/p&gt;

&lt;p&gt;Sabendo da importância dessa prática, precisamos ter tranquilidade e segurança para refatorar um código. Para isso, é importante que existam testes automatizados que podem ser executados constantemente, ajudando a garantir que as mudanças não tenham impacto no comportamento da aplicação. A utilização do TDD nos possibilita refatorar o código várias vezes durante a sua escrita. Como resultado, no final temos um código que funciona, uma cobertura de testes confiável e um design que possibilitará ao software continuar evoluindo com o menor custo possível. As pessoas do nosso time irão nos agradecer por esse cuidado com o código, inclusive nós mesmos no futuro.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pair Programming e Code Review
&lt;/h3&gt;

&lt;p&gt;Somos bons para encontrar problemas no código dos outros. Sabendo disso, podemos explorar essa habilidade para contribuir com o código das outras pessoas e permitir que elas contribuam com o nosso.&lt;/p&gt;

&lt;p&gt;Existem duas práticas que são úteis para que essa troca de feedback aconteça: Pair Programming e Code Review. Um dos propósitos dessas duas práticas é fazer com que o código seja construído por mais de uma pessoa.&lt;/p&gt;

&lt;p&gt;Code Review é uma prática que geralmente acontece após concluir a implementação. O código é submetido a uma etapa de revisão, onde outras pessoas devem avaliar o funcionamento, os impactos da implementação e principalmente a qualidade do design criado. É um momento para avaliar a simplicidade e a intenção do código, uma vez que se os revisores tiverem dificuldades para compreender a implementação realizada é provável que o código possa ser melhorado. Quando isso acontece, o revisor deve dar feedback ao criador do código e ajudá-lo a melhorar o design criado.&lt;/p&gt;

&lt;p&gt;Apesar de ser muito utilizado após a conclusão da implementação, acredito que o Code Review pode ser melhor utilizado durante o Pair Programming, que é a prática onde duas pessoas trabalham juntas na implementação, dividindo o mesmo teclado. Uma pessoa é responsável por escrever o código enquanto a outra deve ajudar em pesquisas, tomadas de decisão e principalmente na revisão de código. A grande vantagem é que durante o pareamento, a revisão de código acontece de forma contínua, durante todo o processo de escrita de código, o que faz com que o ciclo de feedback seja mais curto em relação à revisão de código realizada após a implementação e impede que a revisão se torne um bloqueio no fluxo de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Parece controverso que a utilização de Pair Programming possa funcionar, teoricamente seria mais produtivo se cada pessoa estivesse trabalhando em uma atividade separada e isso seria verdade se a nossa tarefa mais difícil fosse escrever código, mas sabemos que não é o caso. Durante o desenvolvimento de um software, existem muitos fatores que influenciam no seu sucesso, como o funcionamento esperado, o desempenho esperado e a sua capacidade de mudança. O software precisa fazer o que se propõe de maneira satisfatória e precisa estar pronto para evoluir. Sabendo disso, quando trabalhamos juntos em um mesmo objetivo aumentamos significativamente as nossas chances de criar um produto que possua todas as características desejadas, pois duas cabeças pensam melhor do que uma.&lt;/p&gt;

&lt;p&gt;Podemos utilizar essas práticas como oportunidade de trocar feedbacks que ajudarão na construção de um código que seja fácil de manter, além de compartilhar conhecimento entre as pessoas do time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;As pessoas esperam que possamos desenvolver softwares que atendam as necessidades delas hoje, mas que estejam prontas para evoluir. Portanto, temos como responsabilidade planejar o design das nossas aplicações. Para isso, é muito importante dominar os conceitos, princípios, padrões e práticas, que nos auxiliam na construção de bons designs. Por fim, devemos assumir uma postura profissional e ter disciplina para não abrir mão da qualidade do código que escrevemos. Nossas decisões devem contribuir com a qualidade do design do software, pois essa é a única forma de construir um produto que atenda aos clientes, se adapte às mudanças e que seja lucrativo ao longo do seu ciclo de vida.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Extreme Programming Explained: Embrace Change, Kent Beck&lt;/li&gt;
&lt;li&gt;Clean Code, Uncle Bob&lt;/li&gt;
&lt;li&gt;TDD By Example, Kent Beck&lt;/li&gt;
&lt;li&gt;Refactoring, Improving the design of existing code, Martin Fowler&lt;/li&gt;
&lt;li&gt;Head First Design Patterns, Eric Freeman and Elisabeth Robson&lt;/li&gt;
&lt;li&gt;Practical Object-Oriented Design: An Agile Primer Using Ruby, Sandi Metz&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cleancode</category>
      <category>tdd</category>
      <category>refactoring</category>
      <category>softwaredesign</category>
    </item>
  </channel>
</rss>
