<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Desenvolvimento de Software - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Desenvolvimento de Software - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 28 May 2026 20:37:48 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/tag/desenvolvimento-de-software/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ O que é SOLID? Princípios para um design de software melhor ]]>
                </title>
                <description>
                    <![CDATA[ Os princípios SOLID são um conjunto de diretrizes para escrever software de alta qualidade, manutenível e escalável. Eles foram introduzidos por Robert C. Martin em seu artigo de 2000, "Design Principles and Design Patterns [https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf]" (Princípios de padrões de design, em português – texto do link em inglês), para ajudar ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/o-que-e-solid-principios-para-um-design-de-software-melhor/</link>
                <guid isPermaLink="false">6685eb7c23266d03fc8b81c8</guid>
                
                    <category>
                        <![CDATA[ Desenvolvimento de Software ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kris Lagerström ]]>
                </dc:creator>
                <pubDate>Thu, 11 Jul 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/solid-principles.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/solid-principles-for-better-software-design/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">What is SOLID? Principles for Better Software Design</a>
      </p><p>Os princípios SOLID são um conjunto de diretrizes para escrever software de alta qualidade, manutenível e escalável.</p><p>Eles foram introduzidos por Robert C. Martin em seu artigo de 2000, "<a href="https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf"><em>Design Principles and Design Patterns</em></a>" (Princípios de padrões de design, em português – texto do link em inglês), para ajudar desenvolvedores a escrever software que seja fácil de entender, modificar e estender.</p><p>Esses conceitos foram posteriormente desenvolvidos por Michael Feathers, que nos apresentou a abreviação SOLID.</p><p>SOLID tem a ver com:</p><ul><li><em><strong>S</strong>ingle Responsibility Principle</em> (Princípio da responsabilidade única - SRP)</li><li><em><strong>O</strong>pen-Closed Principle</em> (Princípio aberto-fechado - OCP)</li><li><em><strong>L</strong>iskov Substitution Principle</em> (Princípio da substituição de Liskov - LSP)</li><li><em><strong>I</strong>nterface Segregation Principle</em> (Princípio da segregação de interface - ISP)</li><li><em><strong>D</strong>ependency Inversion Principle</em> (Princípio da inversão de dependência - DIP)</li></ul><p>Esses princípios fornecem uma maneira para os desenvolvedores organizarem seu código e criarem software flexível, fácil de alterar e testável. A aplicação dos princípios SOLID pode levar a um código mais modular, manutenível e extensível, além de poder facilitar a colaboração entre desenvolvedores em uma base de código.</p><p>Neste tutorial, exploraremos cada um dos princípios SOLID em detalhes. Explicaremos por que eles são importantes e forneceremos exemplos de como você pode aplicá-los na prática. Ao final deste tutorial, você deverá ter um bom entendimento dos princípios SOLID e de como aplicá-los aos seus projetos de desenvolvimento de software.</p><h2 id="o-que-o-princ-pio-da-responsabilidade-nica"><strong>O que é o princípio da responsabilidade única?</strong></h2><p>O princípio da responsabilidade única (SRP) afirma que <strong>uma classe deve ter apenas um motivo para mudar</strong>, ou, em outras palavras, <strong>ela deve ter apenas uma responsabilidade</strong>. Isso significa que uma classe deve ter apenas um trabalho a fazer e deve fazê-lo bem.</p><p>Se uma classe tiver muitas responsabilidades, ela pode se tornar difícil de entender, manter e modificar. Mudanças em uma responsabilidade podem afetar inadvertidamente outra responsabilidade, levando a consequências indesejadas e <em>bugs</em>. Ao seguir o SRP, podemos criar código mais modular, fácil de entender e menos propenso a erros.</p><p>Vejamos um exemplo que viola o SRP:</p><pre><code class="language-java">class Marcador {
    String nome;
    String cor;
    int preco;

    public Marcador(String nome, String cor, int preco) {
        this.nome = nome;
        this.cor = cor;
        this.preco = preco;
    }
}</code></pre><p>O código acima define uma classe <code>Marcador</code> simples com três variáveis de instância – <code>nome</code>, <code>cor</code> e <code>preco</code>.</p><pre><code class="language-java">class Fatura {
    private Marcador marcador;
    private int quantidade;

    public Fatura(Marcador marcador, int quantidade) {
        this.marcador = marcador;
        this.quantidade = quantidade;
    }

    public int calcularTotal() {
        return marcador.preco * this.quantidade;
    }

    public void imprimirFatura() {
        // implementação de impressão
    }

    public void salvarNoBancoDeDados() {
        // implementação de salvamento no banco de dados
    }
}</code></pre><p>A classe <code>Fatura</code> acima viola o SRP porque tem várias responsabilidades – é responsável por calcular o valor total, imprimir a fatura e salvar a fatura no banco de dados. Como resultado, se a lógica de cálculo mudar, como a adição de impostos, o método <code>calcularTotal()</code> precisaria ser modificado. Do mesmo modo, se a implementação de impressão ou salvamento no banco de dados mudar em algum momento, a classe precisaria ser alterada.</p><p>Existem vários motivos para a classe ser modificada, o que pode levar ao aumento dos custos de manutenção e complexidade.</p><p>Veja como você pode modificar o código para seguir o SRP:</p><pre><code class="language-java">class Fatura {
    private Marcador marcador;
    private int quantidade;

    public Fatura(Marcador marcador, int quantidade) {
        this.marcador = marcador;
        this.quantidade = quantidade;
    }

    public int calcularTotal() {
        return marcador.preco * this.quantidade;
    }
}</code></pre><pre><code class="language-java">class FaturaDao {
    private Fatura fatura;

    public FaturaDao(Fatura fatura) {
        this.fatura = fatura;
    }

    public void salvarNoBancoDeDados() {
        // implementação de salvamento no banco de dados
    }
}</code></pre><pre><code class="language-java">class ImpressoraDeFatura {
    private Fatura fatura;

    public ImpressoraDeFatura(Fatura fatura) {
        this.fatura = fatura;
    }

    public void imprimirFatura() {
        // implementação de impressão
    }
}</code></pre><p>Neste exemplo refatorado, dividimos as responsabilidades da classe <code>Fatura</code> em três classes separadas: <code>Fatura</code>, <code>FaturaDao</code> e <code>ImpressoraDeFatura</code>.</p><p>A classe <code>Fatura</code> é responsável apenas por calcular o valor total, e as responsabilidades de impressão e salvamento foram delegadas a classes separadas. Isso torna o código mais modular, fácil de entender e menos propenso a erros.</p><h2 id="o-que-o-princ-pio-aberto-fechado"><strong>O que é o princípio aberto-fechado?</strong></h2><p>O princípio aberto-fechado (OCP) afirma que <strong>entidades de software (classes, módulos, funções e assim por diante) devem ser abertas para extensão, mas fechadas para modificação</strong>. Isso significa que o comportamento de uma entidade de software pode ser estendido sem modificar seu código-fonte.</p><p>O OCP é essencial porque promove a extensibilidade e a manutenibilidade do software. Ao permitir que entidades de software sejam estendidas sem modificação, os desenvolvedores podem adicionar novas funcionalidades sem o risco de quebrar o código existente. Isso resulta em código mais fácil de manter, estender e reutilizar.</p><p>Vejamos o exemplo anterior novamente.</p><pre><code class="language-java">class FaturaDao {
    private Fatura fatura;

    public FaturaDao(Fatura fatura) {
        this.fatura = fatura;
    }

    public void salvarNoBancoDeDados() {
        // implementação de salvamento no banco de dados
    }
}</code></pre><p>A classe <code>FaturaDao</code> tem a responsabilidade única de salvar a fatura no banco de dados. Suponha, no entanto, que haja um novo requisito para salvar a fatura em um arquivo também. Uma maneira de implementar esse requisito seria modificar a classe <code>FaturaDao</code> existente adicionando um método <code>salvarEmArquivo()</code>. Isso, contudo, viola o princípio aberto-fechado porque modifica o código existente que já foi testado e está em produção.</p><p>Para seguir o OCP, uma solução melhor seria criar uma interface <code>FaturaDao</code> e implementá-la separadamente para salvamento em banco de dados e arquivo, conforme mostrado abaixo:</p><pre><code class="language-java">interface FaturaDao {
    public void salvar(Fatura fatura);
}

class FaturaDaoBancoDeDados implements FaturaDao {
    @Override
    public void salvar(Fatura fatura) {
        // implementação de salvamento no banco de dados
    }
}

class FaturaDaoArquivo implements FaturaDao {
    @Override
    public void salvar(Fatura fatura) {
        // implementação de salvamento em arquivo
    }
}</code></pre><p>Desse modo, se houver um novo requisito para salvar a fatura em outro armazenamento de dados, você pode implementar uma nova implementação de <code>FaturaDao</code> sem modificar o código existente. Agora, a interface <code>FaturaDao</code> está aberta para extensão e fechada para modificação, o que segue o OCP.</p><h2 id="o-que-o-princ-pio-da-substitui-o-de-liskov"><strong>O que é o princípio da substituição de Liskov?</strong></h2><p>O princípio da substituição de Liskov (LSP) afirma que <strong>qualquer instância de uma classe derivada deve ser substituível por uma instância de sua classe base sem afetar a correção do programa</strong>.</p><p>Em outras palavras, uma classe derivada deve se comportar como sua classe base em todos os contextos. Em termos mais simples, se a classe A é um subtipo da classe B, você deve ser capaz de substituir B por A sem quebrar o comportamento do seu programa.</p><p>A importância do LSP reside em sua capacidade de garantir que o comportamento de um programa permaneça consistente e previsível ao substituir objetos de classes diferentes. Violar o LSP pode levar a comportamento inesperado, <em>bugs</em> e problemas de manutenibilidade.</p><p>Vejamos um exemplo.</p><pre><code class="language-java">interface VeiculoDeDuasRodas {
    void ligarMotor();

    void acelerar();
}</code></pre><p>No exemplo dado, a interface <code>VeiculoDeDuasRodas</code> tem dois métodos, <code>ligarMotor()</code> e <code>acelerar()</code>. Duas classes implementam essa interface, <code>Motocicleta</code> e <code>Bicicleta</code>.</p><pre><code class="language-java">class Motocicleta implements VeiculoDeDuasRodas {

    boolean motorLigado;
    int velocidade;

    @Override
    public void ligarMotor() {
        motorLigado = true;
    }

    @Override
    public void acelerar() {
        velocidade += 5;
    }
}</code></pre><p><code>Motocicleta</code> implementa corretamente o método <code>ligarMotor()</code>, pois define o booleano <code>motorLigado</code> como verdadeiro. Ele também implementa corretamente o método <code>acelerar()</code> aumentando a <code>velocidade</code> em 5.</p><pre><code class="language-java">class Bicicleta implements VeiculoDeDuasRodas {

    boolean motorLigado;
    int velocidade;

    @Override
    public void ligarMotor() {
        throw new AssertionError("Não há motor!");
    }

    @Override
    public void acelerar() {
        velocidade += 5;
    }
}</code></pre><p>No entanto, a classe <code>Bicicleta</code> lança um <code>AssertionError</code> no método <code>ligarMotor()</code> porque não tem motor. Isso significa que uma instância de <code>VeiculoDeDuasRodas</code> não pode ser substituída por uma instância de <code>Bicicleta</code> sem quebrar o comportamento do programa.</p><p>Em outras palavras, se a classe <code>Bicicleta</code> for considerada um subtipo da interface <code>VeiculoDeDuasRodas</code>, de acordo com o LSP, qualquer instância de <code>VeiculoDeDuasRodas</code> deve ser substituível por uma instância de <code>Bicicleta</code> sem alterar a correção do programa.</p><p>Neste caso, porém, isso não é verdade, porque <code>Bicicleta</code> lança um <code>AssertionError</code> ao tentar ligar o motor. Portanto, o código viola o LSP.</p><h2 id="o-que-o-princ-pio-da-segrega-o-de-interface"><strong>O que é o princípio da segregação de interface?</strong></h2><p>O princípio da segregação de interface (ISP) se concentra no design de interfaces que são específicas para as necessidades de seus clientes. Ele afirma que nenhum cliente deve ser forçado a depender de métodos que não usa.</p><p>O princípio sugere que <strong>em vez de criar uma interface grande, que cubra todos os métodos possíveis, é melhor criar interfaces menores e mais focadas para casos de uso específicos</strong>. Essa abordagem resulta em interfaces mais coesas e menos acopladas.</p><p>Considere uma interface <code>Veiculo</code> como abaixo:</p><pre><code class="language-java">interface Veiculo {
    void ligarMotor();
    void desligarMotor();
    void dirigir();
    void voar();
}</code></pre><p>E então você tem uma classe chamada <code>Carro</code> que implementa a interface <code>Veiculo</code>:</p><pre><code class="language-java">class Carro implements Veiculo {

    @Override
    public void ligarMotor() {
        // implementação
    }

    @Override
    public void desligarMotor() {
        // implementação
    }

    @Override
    public void dirigir() {
        // implementação
    }

    @Override
    public void voar() {
        throw new UnsupportedOperationException("Este veículo não pode voar.");
    }
}</code></pre><p>Neste exemplo, a interface <code>Veiculo</code> tem muitos métodos. A classe <code>Carro</code> é forçada a implementar todos eles, embora não possa voar. Isso viola o ISP porque a interface <code>Veiculo</code> não é segregada adequadamente em interfaces menores com base na funcionalidade relacionada.</p><p>Vamos entender como você pode seguir o ISP aqui. Suponha que você refatore a interface <code>Veiculo</code> em interfaces menores e mais focadas:</p><pre><code class="language-java">interface Dirigivel {
    void ligarMotor();
    void desligarMotor();
    void dirigir();
}

interface Voador {
    void voar();
}</code></pre><p>Agora, você pode ter uma classe chamada <code>Carro</code>, que implementa apenas a interface <code>Dirigivel</code>:</p><pre><code class="language-java">class Carro implements Dirigivel {

    @Override
    public void ligarMotor() {
        // implementação
    }

    @Override
    public void desligarMotor() {
        // implementação
    }

    @Override
    public void dirigir() {
        // implementação
    }
}</code></pre><p>Graças à segregação de interface, você pode ter outra classe chamada <code>Aviao</code>, que implementa as interfaces <code>Dirigivel</code> e <code>Voador</code>:</p><pre><code class="language-java">class Aviao implements Dirigivel, Voador {

    @Override
    public void ligarMotor() {
        // implementação
    }

    @Override
    public void desligarMotor() {
        // implementação
    }

    @Override
    public void dirigir() {
        // implementação
    }

    @Override
    public void voar() {
        // implementação
    }
}</code></pre><p>Neste exemplo, você segregou adequadamente a interface <code>Veiculo</code> em interfaces menores com base na funcionalidade relacionada. Isso adere ao ISP e torna seu código mais flexível e manutenível.</p><h2 id="o-que-o-princ-pio-da-invers-o-de-depend-ncia"><strong>O que é o princípio da inversão de dependência?</strong></h2><p>O princípio da inversão de dependência (DIP) afirma que <strong>módulos de alto nível não devem depender de módulos de baixo nível, mas ambos devem depender de abstrações</strong>. Abstrações não devem depender de detalhes – detalhes devem depender de abstrações.</p><p>Esse princípio visa reduzir o acoplamento entre módulos, aumentar a modularidade e tornar o código mais fácil de manter, testar e estender.</p><p>Por exemplo, considere um cenário em que você tem uma classe que precisa usar uma instância de outra classe. Na abordagem tradicional, a primeira classe criaria diretamente uma instância da segunda classe, levando a um acoplamento forte entre elas. Isso torna difícil alterar a implementação da segunda classe ou testar a primeira classe independentemente.</p><p>Se, contudo, você aplicar o DIP, a primeira classe dependeria de uma abstração da segunda classe em vez da implementação. Isso tornaria possível alterar facilmente a implementação e testar a primeira classe independentemente.</p><p>Aqui está um exemplo que viola o DIP:</p><pre><code class="language-java">class CondicoesDoTempo {
    private String condicoesAtuais;
    private EnviadorDeEmail enviadorDeEmail;

    public CondicoesDoTempo() {
        this.enviadorDeEmail = new EnviadorDeEmail();
    }

    public void setCondicoesAtuais(String descricaoDoTempo) {
        this.condicoesAtuais = descricaoDoTempo;
        if (descricaoDoTempo == "chuvoso") {
            enviadorDeEmail.enviarEmail("Está chuvoso");
        }
    }
}

class EnviadorDeEmail {
    public void enviarEmail(String mensagem) {
        System.out.println("Email enviado: " + mensagem);
    }
}</code></pre><p>Neste exemplo, a classe <code>CondicoesDoTempo</code> cria diretamente uma instância da classe <code>EnviadorDeEmail</code>, tornando-a fortemente acoplada à implementação. Isso torna difícil alterar a implementação da classe <code>EnviadorDeEmail</code> ou testar a classe <code>CondicoesDoTempo</code> independentemente.</p><p>Aqui está um exemplo de como aplicar o DIP ao código acima:</p><pre><code class="language-java">interface Notificador {
    public void alertarCondicoesDoTempo(String descricaoDoTempo);
}

class CondicoesDoTempo {
    private String condicoesAtuais;
    private Notificador notificador;

    public CondicoesDoTempo(Notificador notificador) {
        this.notificador = notificador;
    }

    public void setCondicoesAtuais(String descricaoDoTempo) {
        this.condicoesAtuais = descricaoDoTempo;
        if (descricaoDoTempo == "chuvoso") {
            notificador.alertarCondicoesDoTempo("Está chuvoso");
        }
    }
}

class EnviadorDeEmail implements Notificador {
    public void alertarCondicoesDoTempo(String descricaoDoTempo) {
        System.out.println("Email enviado: " + descricaoDoTempo);
    }
}

class SMS implements Notificador {
    public void alertarCondicoesDoTempo(String descricaoDoTempo) {
        System.out.println("SMS enviado: " + descricaoDoTempo);
    }
}</code></pre><p>Neste exemplo, criamos uma interface <code>Notificador</code> que define o método <code>alertarCondicoesDoTempo</code>. A classe <code>CondicoesDoTempo</code> agora depende dessa interface em vez da classe <code>EnviadorDeEmail</code>, tornando possível alterar facilmente a implementação e testar a classe <code>CondicoesDoTempo</code> independentemente.</p><p>Também criamos duas implementações da interface <code>Notificador</code>, <code>EnviadorDeEmail</code> e <code>SMS</code>, para demonstrar como você pode alterar a implementação da classe <code>CondicoesDoTempo</code> sem afetar seu comportamento.</p><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>Neste artigo, você aprendeu sobre os princípios SOLID, que são uma parte muito importante dos princípios de design em geral.</p><p>Ao aplicar esses princípios em seus projetos de desenvolvimento de software, você pode criar código mais fácil de manter, estender e modificar, levando a um software mais robusto, flexível e reutilizável. Isso também levará a uma colaboração melhor entre os membros da equipe, à medida que o código se torna mais modular e fácil de trabalhar.</p><blockquote>Para mais tutoriais como este, acompanhe o <a href="https://www.freecodecamp.org/portuguese/news/">editorial do freeCodeCamp em português</a>.</blockquote> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como aprender design e arquitetura de software – um guia ]]>
                </title>
                <description>
                    <![CDATA[ > Tradução em português europeu > Este artigo é um resumo do que estou a escrever no meu projeto mais recente,  solidbook.io - The Handbook to Software Design and Architecture with TypeScript [https://solidbook.io/] (link em inglês). Dá uma vista de olhos por lá se gostares desta publicação. É uma ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-aprender-design-e-arquitetura-de-software-um-guia/</link>
                <guid isPermaLink="false">655f0a8b13a65603e6501c42</guid>
                
                    <category>
                        <![CDATA[ Desenvolvimento de Software ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Afonso Branco ]]>
                </dc:creator>
                <pubDate>Tue, 21 May 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/banner-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/software-design/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Learn Software Design and Architecture - a Roadmap</a>
      </p><blockquote>Tradução em português europeu</blockquote><blockquote><em>Este artigo é um resumo do que estou a escrever no meu projeto mais recente<em>, </em></em><a href="https://solidbook.io/"><em><em>solidbook.io - The Handbook to Software Design and Architecture with TypeScript</em></em></a><em> (</em>link em inglês<em>)<em>. </em>Dá uma vista de olhos por lá se gostares desta publicação<em>.</em></em></blockquote><p>É uma loucura para mim considerar o facto do Facebook ter sido em tempos um ficheiro de texto vazio no computador de alguém. 🤣</p><p>Neste último ano, tenho-me esforçado muito em design e arquitetura de software, <a href="https://khalilstemmler.com/articles/domain-driven-design-intro/">Design Orientado a Domínio</a> (link em inglês) e a <a href="https://solidbook.io/">escrever um livro</a> sobre isso, e queria tirar um tempo para tentar juntar as peças todas em algo útil que pudesse partilhar com a comunidade.</p><p>Aqui está o meu roteiro para como aprender design e arquitetura de software.</p><p>Dividi-o em duas partes: o <em>stack </em>(pilha) e o <em>map </em>(mapa).</p><h2 id="o-stack"><strong>O <em>stack</em></strong></h2><p>De modo semelhante ao <a href="https://pt.wikipedia.org/wiki/Modelo_OSI">modelo OSI</a> em redes, cada camada é construída sobre a base da camada anterior.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/e727h5b9nozcuo4za2yw.png" class="kg-image" alt="e727h5b9nozcuo4za2yw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/e727h5b9nozcuo4za2yw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/05/e727h5b9nozcuo4za2yw.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2024/05/e727h5b9nozcuo4za2yw.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/e727h5b9nozcuo4za2yw.png 2130w" sizes="(min-width: 720px) 720px" width="2130" height="1844" loading="lazy"></figure><h2 id="o-map"><strong>O <em>map</em></strong></h2><p>Embora eu ache que a pilha é boa para ver o panorama geral de como tudo funciona em conjunto, o mapa é um pouco mais detalhado (e inspirado pelo <a href="https://github.com/kamranahmedse/developer-roadmap">roteiro do programador web</a> – link em inglês) e, como resultado, penso que seja mais útil.</p><p>Aqui está ele! Para <a href="https://khalilstemmler.com/articles/software-design-architecture/full-stack-software-design/">duplicar o repositório, ler a minha redação detalhada e fazer o download em alta resolução, clica aqui</a>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/65834517-bb39f980-e2a9-11e9-8a75-0e1559c5ed56.png" class="kg-image" alt="65834517-bb39f980-e2a9-11e9-8a75-0e1559c5ed56" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/65834517-bb39f980-e2a9-11e9-8a75-0e1559c5ed56.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/05/65834517-bb39f980-e2a9-11e9-8a75-0e1559c5ed56.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2024/05/65834517-bb39f980-e2a9-11e9-8a75-0e1559c5ed56.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w2400/2024/05/65834517-bb39f980-e2a9-11e9-8a75-0e1559c5ed56.png 2400w" sizes="(min-width: 720px) 720px" width="2000" height="7869" loading="lazy"></figure><blockquote>Nota da tradução: houve uma revisão do conteúdo em março deste ano. Caso deseje acessar o conteúdo mais recente (em inglês) acesse <a href="https://khalilstemmler.com/articles/software-design-architecture/full-stack-software-design/">aqui</a>.</blockquote><h2 id="fase-1-c-digo-limpo"><strong>Fase 1: código limpo</strong></h2><p>O primeiro passo em direção à criação de software duradouro é descobrir como escrever <strong>código limpo</strong>.</p><p>Código limpo é código que é fácil de compreender e alterar. Logo no início, isto manifesta-se em algumas escolhas de design como:</p><ul><li>Ser consistente</li><li>Dar preferência a nomes significativos de variáveis, métodos e classes em vez de explicar em comentários</li><li>Garantir que o código está corretamente indentado e espaçado</li><li>Garantir que todos os testes possam ser executados</li><li>Escrever funções puras sem efeitos secundários</li><li>Não passar nulos</li></ul><p>Escrever código limpo é incrivelmente importante</p><p>Pensa nisso como se fosse o jogo do Jenga.</p><p>De modo a manter a estrutura do nosso projeto estável ao longo do tempo, coisas como indentação, pequenas classes e métodos, e nomes significativos, compensam bastante a longo termo.</p><p>O melhor recurso para aprender como escrever código limpo é livro de <em>Uncle Bob</em>, "<a href="https://www.amazon.ca/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882">Código Limpo</a>" (link em inglês).</p><h2 id="fase-2-paradigmas-de-programa-o"><strong>Fase 2: paradigmas de programação</strong></h2><p>Agora que estamos a escrever código legível que é fácil de fazer a manutenção, seria uma boa ideia compreender realmente os 3 maiores paradigmas da programação e a maneira como influenciam o nosso modo de escrever código.</p><p>No livro de <em>Uncle Bob</em>, "<a href="https://www.amazon.ca/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=asc_df_0132350882/?tag=googleshopc0c-20&amp;linkCode=df0&amp;hvadid=292982483438&amp;hvpos=1o2&amp;hvnetw=g&amp;hvrand=13521899336201370454&amp;hvpone=&amp;hvptwo=&amp;hvqmt=&amp;hvdev=c&amp;hvdvcmdl=&amp;hvlocint=&amp;hvlocphy=9000834&amp;hvtargid=pla-435472505264&amp;psc=1">Arquitetura Limpa</a>" (link em inglês), ele destaca que:</p><ul><li>Programação Orientada a Objetos é a ferramenta mais adequada para definir como passamos limites arquitetónicos com polimorfismo e plugins</li><li>Programação funcional é a ferramenta que utilizamos para enviar dados para os limites das nossas aplicações</li><li>E programação estruturada é a ferramenta que utilizamos para escrever algoritmos</li></ul><p>Isso implica que o software eficiente utiliza uma mistura de todos estes 3 estilos de paradigmas de programação em alturas diferentes.</p><p>Embora <em>possas</em> adotar uma abordagem estritamente funcional ou estritamente orientada a objetos para escrever código, compreender onde cada um deles se destaca melhorará a qualidade dos teus designs.</p><blockquote><em>Se tudo o que tiveres for um martelo<em>, </em>tudo se parece com um prego<em>.</em></em></blockquote><h3 id="recursos"><strong>Recursos</strong></h3><p>Para <strong>programação</strong> <strong><strong>funcional</strong></strong>, dá uma vista de olhos:</p><ul><li><a href="https://mostly-adequate.gitbooks.io/mostly-adequate-guide/">Guia Maioritariamente Adequado do Professor Frisby para Programação Funcional</a> (link em inglês)</li><li><a href="https://pragprog.com/book/swdddf/domain-modeling-made-functional?fbclid=IwAR0NHoyVrMoSRIE-EJMUOdsb3bhivow6JXKyUeg4FPHE8QmeOQG4L77HzMo">Modelação de Domínio Tornada Funcional</a> (link em inglês)</li></ul><h2 id="fase-3-programa-o-orientada-a-objetos"><strong>Fase 3: programação orientada a objetos</strong></h2><p>É importante saber como cada um dos paradigmas funciona e como te incentivam a estruturar o código dentro deles, mas no que diz respeito à arquitetura, Programação Orientada a Objetos é claramente a <em>ferramenta ideal para o trabalho</em>.</p><p>A programação Orientada a Objetos não só nos permite criar uma <strong>arquitetura de</strong> <strong><strong>plugin</strong></strong> e criar flexibilidade nos nossos projetos; Programação Orientada a Objetos vem com 4 princípios de Programação Orientada a Objetos (encapsulamento, herança, polimorfismo e abstração) que nos ajudam a criar <strong>modelos de domínio ricos</strong>.</p><p>A maior parte dos programadores a aprender Programação Orientada a Objetos nunca chega a essa parte: aprender como criar uma <strong>implementação de software para o domínio do problema</strong>, e localizá-la no centro de uma aplicação web <strong>com</strong> <strong>camadas</strong>.</p><p>Programação funcional pode parecer a solução para todos os problemas nesse cenário, mas eu recomendo familiarizar-te com o design orientado a modelos e <a href="https://khalilstemmler.com/articles/domain-driven-design-intro/">Design Orientado a Domínio</a> para compreender o panorama de como os modeladores de objetos são capazes de encapsular um negócio completo com um modelo de domínio com zero dependências.</p><blockquote><em>Por que é que isso é importante<em>?</em></em></blockquote><p>É muito importante porque, se podes criar um modelo mental de um negócio, podes criar uma implementação de software desse negócio.</p><h2 id="fase-4-princ-pios-de-design"><strong>Fase 4: princípios de design</strong></h2><p>Neste momento, a tua compreensão de que a Programação Orientada a Objetos é muito útil para encapsular modelos de domínio ricos e para resolver o <a href="https://khalilstemmler.com/wiki/3-categories-of-hard-software-problems/">terceiro tipo de "Problemas de Software Difíceis"– Domínios Complexos</a> (link em inglês).</p><p>No entanto, a Programação Orientada a Objetos pode introduzir alguns desafios de design.</p><p>Onde devo utilizar composição?</p><p>Quando devo utilizar herança?</p><p>Quando devo utilizar uma classe abstrata?</p><p>Princípios de design são boas práticas muito bem estabelecidas e testadas que podes utilizar como segurança.</p><p>Alguns exemplos de princípios de design comuns com que te deves familiarizar são:</p><ul><li>Composição sobre herança</li><li>Encapsular o que varia</li><li>Programar contra abstrações, não concreções</li><li>O princípio de <em>Hollywood</em>: "Não nos chames, nós chamamos-te"</li><li>Os <a href="https://khalilstemmler.com/articles/solid-principles/solid-typescript/">princípios SOLID</a>, especialmente o <a href="https://khalilstemmler.com/articles/solid-principles/single-responsibility/">princípio de responsabilidade singular</a></li><li>DRY (Do Not Repeat Yourself – Não te Repitas, em português)</li><li><a href="https://khalilstemmler.com/wiki/yagni/">YAGNI (You Aren't Gonna Need It, Não Vais Precisar Disso, em português)</a></li></ul><p>Certifica-te de que alcanças as <em>tuas</em> próprias conclusões, no entanto. Não te limites a seguir o que outra pessoa diga que deves fazer. Certifica-te que faz sentido para ti.</p><h2 id="fase-5-padr-es-de-design"><strong>Fase 5: padrões de design</strong></h2><p>Praticamente todos os problemas de software já foram categorizados e resolvidos em algum momento. Chamamos a esses padrões: padrões de design, na verdade.</p><p>Existem 3 categorias de padrões de design: <strong>criativo</strong>, <strong>estrutural</strong> e <strong>comportamental</strong>.</p><h3 id="criativo"><strong>Criativo</strong></h3><p>Padrões criativos são padrões que controlam como os objetos são criados.</p><p>Exemplos de padrões criativos incluem:</p><ul><li>O <strong>padrão</strong> <strong><strong>Singleton</strong></strong>, para garantir que existe uma única instância de uma classe.</li><li>O <strong>padrão</strong> <strong><strong>Abstract Factory</strong></strong>, para criar uma instância de várias famílias de classes.</li><li>O <strong>padrão</strong> <strong><strong>Prototype</strong></strong>, para começar com uma instância que é clonada a partir de uma já existente.</li></ul><h3 id="estrutural"><strong>Estrutural</strong></h3><p>Padrões estruturais que simplificam como definimos relações entre componentes.</p><p>Exemplos de padrões de design estruturais incluem:</p><ul><li>O <strong>padrão</strong> <strong><strong>Adapter</strong></strong>, para criar uma interface para acionar classes que normalmente não funcionam em conjunto, para funcionarem em conjunto.</li><li>O <strong>padrão</strong> <strong><strong>Bridge</strong></strong>, para dividir uma classe que deve ser um ou mais, num conjunto de classes que pertencem a uma hierarquia, permitindo que as implementações sejam desenvolvidas de forma independente umas das outras.</li><li>O <strong>padrão</strong> <strong><strong>Decorator</strong></strong>, para adicionar responsabilidades a objetos dinamicamente.</li></ul><h3 id="comportamental"><strong>Comportamental</strong></h3><p>Padrões comportamentais são padrões comuns para facilitar comunicações elegantes entre objetos.</p><p>Exemplos de padrões comportamentais são:</p><ul><li>O <strong>padrão</strong> <strong><strong>Template</strong></strong>, para diferir os passos exatos de um algoritmo para uma subclasse.</li><li>O <strong>padrão</strong> <strong><strong>Mediator</strong></strong>, para definir os canais de comunicação exatos permitidos entre classes.</li><li>O <strong>padrão</strong> <strong><strong>Observer</strong></strong>, para habilitar classes para descrever algo de interesse e para notificar quando ocorrer uma alteração.</li></ul><h3 id="criticas-sobre-o-padr-o-de-design"><strong>Criticas sobre o padrão de design</strong></h3><p>Padrões de design são bons, mas por vezes podem trazer complexidade extra aos nossos designs. É importante lembrar o YAGNI e tentar manter os nossos designs tão simples quanto possível. Utiliza apenas padrões de design quando tiveres mesmo a certeza que precisas deles. Saberás quando for o momento.</p><p>Se soubermos o que cada um destes padrões faz, quando utilizá-los, e quando nem sequer <em>nos preocuparmos</em> em utilizá-los, estaremos em boa forma para começar a compreender como fazer a arquitetura de sistemas complexos.</p><p>A razão por trás disso é que <strong>padrões arquitetónicos</strong> <strong>são simplesmente padrões de design com a escala elevada para alto nível</strong>, enquanto que os padrões de design são implementações de baixo nível (mais próximas a classes e funções).</p><h3 id="recursos-1"><strong>Recursos</strong></h3><p><a href="https://refactoring.guru/design-patterns">Refactoring Guru - Padrões de Design</a> (link em inglês)</p><h2 id="fase-6-princ-pios-arquitet-nicos"><strong>Fase 6: princípios arquitetónicos</strong></h2><p>Agora estás num nível de pensamento mais elevado do que o nível de classe.</p><p>Compreendemos que as decisões que tomamos para organizar e criar relações entre componentes, a nível elevado e a nível baixo, vão ter um impacto significativo na facilidade de manutenção, flexibilidade e capacidade de testagem do nosso projeto.</p><p>Aprende os princípios orientadores que te ajudam a criar a flexibilidade que o teu código-base necessita para ser capaz de reagir a novas funcionalidades e exigências, com o mínimo esforço possível.</p><p>Aqui está o que eu recomendo que aprendas logo à partida:</p><ul><li>Princípios de design de componentes: <a href="https://khalilstemmler.com/wiki/stable-abstraction-principle/">o Princípio de Abstração Estável</a> (link em inglês), <a href="https://khalilstemmler.com/wiki/stable-dependency-principle/">o Princípio de Dependência Estável</a> (link em inglês), e o Princípio de Dependência Acíclica, para como organizar componentes, as suas dependências, quando juntá-las, e as implicações de criar acidentalmente ciclos de dependência e depender de componentes instáveis.</li><li><a href="https://khalilstemmler.com/articles/enterprise-typescript-nodejs/clean-nodejs-architecture/">Política x Detalhe</a> (Link em inglês), para compreender como separar as regras da tua aplicação a partir dos detalhes de implementação.</li><li>Limites e como identificar os <a href="https://khalilstemmler.com/articles/enterprise-typescript-nodejs/application-layer-use-cases/">subdomínios</a> a que as funcionalidades da tua aplicação pertencem.</li></ul><p>O <em>Uncle Bob</em> descobriu e documentou originalmente muitos destes princípios. Então, o melhor recurso para aprender isto é, novamente, "<a href="https://www.amazon.ca/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=asc_df_0132350882/?tag=googleshopc0c-20&amp;linkCode=df0&amp;hvadid=292982483438&amp;hvpos=1o2&amp;hvnetw=g&amp;hvrand=13521899336201370454&amp;hvpone=&amp;hvptwo=&amp;hvqmt=&amp;hvdev=c&amp;hvdvcmdl=&amp;hvlocint=&amp;hvlocphy=9000834&amp;hvtargid=pla-435472505264&amp;psc=1">Arquitetura Limpa</a>" (link em inglês).</p><h2 id="fase-7-estilos-arquitet-nicos"><strong>Fase 7: estilos arquitetónicos</strong></h2><p>Arquitetura é sobre as coisas que importam.</p><p>É sobre identificar as necessidades do sistema de maneira a que este seja bem-sucedido e de seguida <strong>aumentar as hipóteses de sucesso</strong> ao escolher a arquitetura que melhor se adequa aos requisitos.</p><p>Por exemplo, um sistema que tem muita <strong>complexidade de lógica de negócio </strong> beneficiaria da utilização de uma <strong>arquitetura por camadas</strong> para encapsular essa complexidade.</p><p>Um sistema como a Uber precisa de ser capaz de lidar com muitos <strong>eventos em tempo real</strong> de uma só vez e atualizar a localização do condutor, então, um estilo de arquitetura <strong><strong>p</strong>u<strong>bli</strong>car<strong>-subscr</strong>ever</strong> poderia ser o mais eficaz.</p><p>Vou-me repetir a mim mesmo aqui porque é importante observar que as 3 categorias de estilos arquitetónicos são semelhantes às 3 categorias de padrões de design, porque <strong>estilos arquitetónicos são padrões de design de alto nível</strong>.</p><h3 id="estrutural-1"><strong>Estrutural</strong></h3><p>Projetos com <em>níveis variantes</em> de componentes e grande intervalo de funcionalidades beneficiarão ou serão prejudicados pela adopção de uma arquitetura estrutural.</p><p>Aqui estão alguns exemplos:</p><ul><li>Arquiteturas<strong> c<strong>om</strong> base em componentes</strong> enfatizam <strong>separação de preocupações</strong> entre os <em>componentes individuais</em> dentro de um sistema. Imagina a <strong><strong>Google</strong></strong> por um segundo. Considera quantas aplicações eles têm dentro da empresa (Google Docs, Google Drive, Google Maps, etc). Para plataformas com muitas funcionalidades, arquiteturas com base em componentes dividem as preocupações em componentes independentes vagamente agrupados. Isto é uma separação <em><em>horizontal</em></em>.</li><li><strong><strong>Mono</strong>lítico</strong> significa que a aplicação é combinada numa única plataforma ou programa, implementada completamente. <em>Observação<em>: </em>podes ter uma arquitetura com base em componentes<em> </em>E<em> monolí</em>tica<em> </em>se separares as tuas aplicações adequadamente<em>, </em>enquanto implementas tudo em conjunto</em>.</li><li>Arquiteturas<strong> por camadas</strong> separam <em>verticalmente</em> as preocupações ao dividir o software em camadas de infraestrutura, aplicação e domínio.</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/app-logic-layers.svg" class="kg-image" alt="app-logic-layers" width="921" height="549" loading="lazy"></figure><blockquote><em>Um exemplo de corte das responsabilidades/preocupações de uma aplicação de modo vertical<em> </em>usando uma arquitetura de camadas<em>. </em>Lê<em> </em></em><a href="https://khalilstemmler.com/articles/software-design-architecture/organizing-app-logic/"><em>aqui</em></a><em><em> </em>(texto em inglês) para obter mais informações sobre como fazer isso<em>.</em></em></blockquote><h3 id="mensagens"><strong>Mensagens</strong></h3><p>Dependendo do teu projeto, enviar mensagens pode ser um componente realmente importante para o sucesso do sistema. Para projetos como esse, arquiteturas com base em mensagens criadas sobre princípios de programação funcional e padrões de design comportamental como o padrão <em>observer</em>.</p><p>Aqui estão alguns exemplos de estilos de arquiteturas com base em mensagens:</p><ul><li>Arquiteturas<strong> Orientadas por Eventos</strong> vêm todas as alterações significativas a estados como eventos. Por exemplo, numa <a href="https://github.com/stemmlerjs/white-label">aplicação de venda de discos de vinil</a>, o estado de uma oferta pode alterar de "pendente" para "aceite" quando ambas as partes concordam com a troca.</li><li>Arquiteturas<strong> <strong>Publi</strong>car<strong>-subscr</strong>ever</strong> são criadas sobre o padrão de design <em>Observer</em> ao fazer com que seja o método de comunicação principal entre o próprio sistema, utilizadores finais/clientes, e outros sistemas e componentes.</li></ul><h3 id="distributivo"><strong>Distributivo</strong></h3><p>Uma arquitetura distributiva significa simplesmente que os componentes do sistema são implementados separadamente e operam ao comunicar num protocolo de rede. Sistemas distributivos podem ser muito eficazes para escalar a taxa de transferência, escalar equipas e delegar (tarefas potencialmente caras) responsabilidades a outros componentes.</p><p>Alguns exemplos de estilos de arquiteturas distributivas são:</p><ul><li>Arquitetura<strong> <em>c</em><strong><em>lient</em>-serv</strong>idor</strong>. Uma das arquiteturas mais comuns, onde dividimos o trabalho a ser feito entre o <em>client</em> (apresentação) e o servidor (lógica de negócio).</li><li>Arquiteturas<strong> ponto-a-ponto</strong> distribuem tarefas de camada de aplicação entre participantes igualmente privilegiados, formando uma rede ponto-a-ponto.</li></ul><h2 id="fase-8-padr-es-arquitet-nicos"><strong>Fase 8: padrões arquitetónicos</strong></h2><p><em>Padrões</em> arquitetónicos explicam em grande detalhe tático como realmente implementar um destes <em>estilos</em> arquitetónicos.</p><p>Aqui estão alguns exemplos de padrões arquitetónicos e os estilos que estes herdam:</p><ul><li><strong><strong><a href="https://khalilstemmler.com/articles/domain-driven-design-intro/">D</a></strong><a href="https://khalilstemmler.com/articles/domain-driven-design-intro/">esign Orientado a Domínio</a></strong> é uma abordagem ao desenvolvimento de software para problemas de domínio realmente complexos. Para que o design orientado a domínio seja bem-sucedido, precisamos de implementar uma <strong>arquitetura de camadas</strong> de maneira a separar as preocupações de um modelo de domínio dos detalhes infra-estruturais que fazem a aplicação realmente executar, como bases de dados, servidores web, caches etc.</li><li><strong>Controlador <strong>Model</strong>o<strong>-Vi</strong>sta</strong> é provavelmente o padrão arquitetónico <strong>mais conhecido</strong> para desenvolver aplicações baseadas na interface de utilizador. Funciona ao dividir a aplicação em 3 componentes: modelo, vista e controlador. O controlador modelo-vista é incrivelmente útil quando estás no início e ajuda-te a aproveitar outras arquiteturas, mas existe uma altura em que percebemos que o <a href="https://khalilstemmler.com/articles/enterprise-typescript-nodejs/when-crud-mvc-isnt-enough/">controlador Modelo-Vista não é suficiente</a> para problemas com muita lógica de negócio.</li><li><strong>Fornecimento de eventos</strong> é uma abordagem funcional onde armazenamos apenas as transações e nunca o estado. Se alguma vez precisarmos do estado, podemos aplicar todas as transações desde o início.</li></ul><h2 id="fase-9-padr-es-empresariais"><strong>Fase 9: padrões empresariais</strong></h2><p>Qualquer padrão arquitetónico que escolhas introduzirá um número de construções e linguagem especializada para te familiarizares e decidir se vale a pena o esforço ou não.</p><p>Ao pegar num exemplo que muitos de nós conhecemos, no <strong>Controlador Modelo-Vista</strong>, a <em><em>vi</em>sta</em> armazena todo o código da camada de apresentação, o <em><em>control</em>ador</em> é comandos de tradução e consultas da <em><em>vi</em>sta</em> para pedidos que são tratados pelo <em><em>model</em>o</em> e retornados pelo <em><em>control</em>ador</em>.</p><p>Em que parte do Modelo (M) lidamos com estas coisas?:</p><ul><li>Lógica de validação</li><li>Regras invariáveis</li><li>Eventos de domínio</li><li>Casos de utilização</li><li>Consultas complexas</li><li>E lógica empresarial</li></ul><p>Se simplesmente utilizarmos um ORM (<em>object-relational mapper</em>) como <a href="https://www.freecodecamp.org/news/software-design/">Sequelize</a> ou <a href="https://www.freecodecamp.org/news/software-design/">TypeORM</a> como o <em><em>model</em>o</em>, todas essas coisas importantes são deixadas para interpretação onde devem estar, e acabam por ficar numa capada não especificada entre o (que deveria ser um rico) <em><em>model</em>o</em> e o <em><em>control</em>ador</em>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/mvc-2.svg" class="kg-image" alt="mvc-2" width="365" height="275" loading="lazy"></figure><blockquote><em>Retirado de<em> "3.1 - Slim (Logic-less) models" </em>em<em> </em></em><a href="https://solidbook.io/"><em><em>solidbook.io</em></em></a><em> (link em inglês)<em>.</em></em></blockquote><p>Se existe alguma coisa que eu tenha aprendido até agora na minha jornada para lá do controlador modelo-vista, é que <strong>existe uma construção para tudo</strong>.</p><p>Para cada uma destas coisas em que o Controlador Modelo-Vista falha em abordar, existem outros <strong>padrões empresariais</strong> para resolvê-las. Por exemplo:</p><ul><li><strong><strong><a href="https://khalilstemmler.com/articles/typescript-domain-driven-design/entities/">Enti</a></strong><a href="https://khalilstemmler.com/articles/typescript-domain-driven-design/entities/">dades</a> </strong>(link em inglês) descrevem modelos que têm uma identidade.</li><li><a href="https://khalilstemmler.com/articles/typescript-value-object/"><strong><strong>Obje</strong>tos de valor</strong></a><strong> </strong>(link em inglês) são modelos que não têm identidade e podem ser utilizados de modo a encapsular a lógica de validação.</li><li><strong><a href="https://khalilstemmler.com/articles/typescript-domain-driven-design/chain-business-logic-domain-events/">Eventos de domínio</a> </strong>(link em inglês) são eventos que significam algum evento empresarial relevante a acontecer e podem ser subscritos de outros componentes.</li></ul><p>Com base no estilo arquitetónico que tiveres escolhido, vão existir muitos outros padrões empresariais para aprenderes de maneira a implementar esse padrão no seu potencial máximo.</p><h3 id="padr-es-de-integra-o"><strong>Padrões de integração</strong></h3><p>Assim que a tua aplicação estiver operacional, à medida que recebes mais e mais utilizadores, podes obter alguns problemas de desempenho. Chamadas de API podem demorar muito tempo, os servidores podem quebrar por estares sobrecarregados de pedidos etc. Para resolver esses problemas, podes ler sobre a integração de coisas como <strong>consulta de mensagens</strong> ou <strong><strong>caches</strong></strong> de modo a melhorar o desempenho.</p><p>Estas são provavelmente as coisas mais desafiantes: <em>escalar<em>, audit</em>ar e desempenho</em>.</p><p>Desenhar um sistema para <em>escala</em> pode ser incrivelmente desafiante. Isto requer uma compreensão profunda sobre as limitações de cada componente dentro da arquitetura e um plano de ação para como mitigar o <em>stress</em> na tua arquitetura e continuar a servir pedidos em situações de grande tráfego.</p><p>Existe também a necessidade de <em><em>audit</em>ar</em> o que está a acontecer na tua aplicação. Grandes empresas precisam de ser capazes de fazer auditorias de modo a identificar potenciais problemas de segurança, compreender como os utilizadores estão a utilizar as suas aplicações, e ter um registo de tudo o que aconteceu até agora.</p><p>Isso pode ser desafiante de implementar, mas as arquiteturas comuns acabam por parecer <strong>baseadas em eventos</strong> e são criadas sobre uma grande variedade de conceitos de design de software e sistemas, princípios e práticas como <em>Event Storming</em>, <em>DDD</em>, <em>CQRS</em> (<em>command query response segregation</em>) e <em>Event Sourcing</em>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Dicas úteis que você pode não saber sobre o Git stash ]]>
                </title>
                <description>
                    <![CDATA[ > O autor do artigo original criou o boletim informativo Git Better [https://gitbetter.substack.com/] para ajudar a aprender novos truques e tópicos avançados do Git. Se você está interessado em melhorar no Git, você deve definitivamente dar uma olhada nisso. Se você usa o Git há algum tempo, pode já ter ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/dicas-uteis-que-voce-pode-nao-saber-sobre-o-git-stash/</link>
                <guid isPermaLink="false">635aa48e191d0905ea41a285</guid>
                
                    <category>
                        <![CDATA[ Desenvolvimento de Software ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rafael Fontenelle ]]>
                </dc:creator>
                <pubDate>Thu, 12 Jan 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/1-KDah4xyJW5PtPuN6LOlFiQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/useful-tricks-you-might-not-know-about-git-stash-e8a9490f0a1a/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Useful tricks you might not know about Git stash</a>
      </p><blockquote><strong>O autor do artigo original criou o boletim informativo <a href="https://gitbetter.substack.com/">Git Better</a> para ajudar a aprender novos truques e tópicos avançados do Git. Se você está interessado em melhorar no Git, você deve definitivamente dar uma olhada nisso.</strong></blockquote><p>Se você usa o Git há algum tempo, pode já ter usado o <em>Git stash</em>. É um dos recursos úteis do Git.</p><p>Aqui estão alguns dos truques úteis que aprendi sobre o <em>Git stash</em> na semana passada.</p><ol><li>Git stash save</li><li>Git stash list</li><li>Git stash apply</li><li>Git stash pop</li><li>Git stash show</li><li>Git stash branch &lt;nome&gt;</li><li>Git stash clear</li><li>Git stash drop</li></ol><h4 id="git-stash-save"><strong><strong><strong>Git stash save</strong></strong></strong></h4><p>Este comando é como o <em>Git stash</em>. Porém, ele vem com várias opções. Vou discutir algumas opções importantes neste artigo.</p><p><strong><strong>Git stash </strong>com mensagem</strong></p><pre><code class="language-bash">git stash save "Sua mensagem para o stash".</code></pre><p>O comando acima armazena (<em>stash</em>, em inglês) e deixa uma mensagem. Veremos como isso é útil em instantes.</p><p><strong>Armazenando arquivos não rastreados</strong></p><p>Você também pode armazenar arquivos não rastreados.</p><pre><code class="language-bash">git stash save -u

ou

git stash save --include-untracked</code></pre><h4 id="git-stash-list"><strong><strong><strong>Git stash list</strong></strong></strong></h4><p>Antes de discutir este comando, deixe-me dizer algo sobre como o <em>stash </em>funciona.</p><p>Quando você usa <em>Git stash</em> ou <em>Git stash save</em>, o Git, de fato, criará um objeto <em>Git commit</em> com algum nome e o salvará em seu repositório.</p><p>Isso significa que você pode visualizar a lista de <em>stashes </em>que fez a qualquer momento.</p><pre><code class="language-bash">git stash list</code></pre><p>Veja o exemplo abaixo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/757jZHhanVirv5F5ZBeTXi2XNVPyAhOmDgwV.png" class="kg-image" alt="757jZHhanVirv5F5ZBeTXi2XNVPyAhOmDgwV" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/01/757jZHhanVirv5F5ZBeTXi2XNVPyAhOmDgwV.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/01/757jZHhanVirv5F5ZBeTXi2XNVPyAhOmDgwV.png 733w" sizes="(min-width: 720px) 720px" width="733" height="188" loading="lazy"><figcaption>Exemplo de git stash list</figcaption></figure><p>Você pode ver a lista de <em>stashes</em> feitos. O <em>stash </em>mais recente feito está no topo.</p><p>Você pode ver que o <em>stash </em>superior recebe uma mensagem personalizada (usando Git stash save "mensagem").</p><h4 id="git-stash-apply"><strong><strong><strong>Git stash apply</strong></strong></strong></h4><p>Este comando pega o <em>stash </em>mais alto na pilha e o aplica ao repositório. No nosso caso, é <strong>stash@{0}</strong>.</p><p>Se você deseja aplicar algum outro <em>stash</em>, pode especificar o ID desse <em>stash</em>.<br>Aqui está o exemplo:</p><pre><code class="language-bash">git stash apply stash@{1}</code></pre><h4 id="git-stash-pop"><strong><strong><strong>Git stash pop</strong></strong></strong></h4><p>Este comando é muito semelhante ao <em>stash apply</em>, mas exclui o <em>stash </em>da pilha depois de aplicado.</p><p>Aqui está o exemplo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/NrqQy5PTwIBRxvQ2WnlY09EV3ayd7DTbr2k9.png" class="kg-image" alt="NrqQy5PTwIBRxvQ2WnlY09EV3ayd7DTbr2k9" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/01/NrqQy5PTwIBRxvQ2WnlY09EV3ayd7DTbr2k9.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/01/NrqQy5PTwIBRxvQ2WnlY09EV3ayd7DTbr2k9.png 730w" sizes="(min-width: 720px) 720px" width="730" height="118" loading="lazy"><figcaption>Exemplo de git stash pop</figcaption></figure><p>Como você pode ver, o <em>stash </em>superior foi excluído e o <strong>stash@{0}</strong> foi atualizado com o <em>stash </em>mais antigo.</p><p>Do mesmo modo, se você deseja que um <em>stash </em>específico apareça, você pode especificar o id do <em>stash</em></p><pre><code class="language-bash">git stash pop stash@{1}</code></pre><h4 id="git-stash-show"><strong><strong><strong>Git stash show</strong></strong></strong></h4><p>Este comando mostra o resumo das diferenças dos <em>stashes</em>. O comando acima considera apenas o <em>stash </em>mais recente.</p><p>Aqui está o exemplo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/W6tFM8O0xrUfFznYg9O-mvAND4zNDX2R-RFc.png" class="kg-image" alt="W6tFM8O0xrUfFznYg9O-mvAND4zNDX2R-RFc" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/01/W6tFM8O0xrUfFznYg9O-mvAND4zNDX2R-RFc.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/01/W6tFM8O0xrUfFznYg9O-mvAND4zNDX2R-RFc.png 728w" sizes="(min-width: 720px) 720px" width="728" height="159" loading="lazy"><figcaption>Exemplo de Git stash show</figcaption></figure><p>Se você quiser ver a diferença completa, pode usar o seguinte:</p><pre><code class="language-bash">git stash show -p</code></pre><p>Da mesma forma como ocorre com outros comandos, você também pode especificar o <em>stash id </em>para obter o resumo das diferenças.</p><pre><code class="language-bash">git stash show stash@{1}</code></pre><h4 id="git-stash-branch-nome"><strong><strong><strong>Git stash branch &lt;</strong></strong>nome&gt;</strong></h4><p>Este comando cria uma branch (em português, ramificação) com o <em>stash </em>mais recente e, em seguida, exclui o <em>stash </em>mais recente (como <em>stash pop</em>).</p><p>Se você precisar de um <em>stash </em>específico, poderá especificar o <em>ID </em>do <em>stash</em>.</p><pre><code class="language-bash">git stash branch &lt;nome&gt; stash@{1}</code></pre><p>Isso será útil quando você se deparar com conflitos depois de aplicar o <em>stash </em>à versão mais recente da sua<em> branch</em>.</p><h4 id="git-stash-clear"><strong><strong><strong>Git stash clear</strong></strong></strong></h4><p>Este comando exclui todos os <em>stashes </em>feitos no repositório. Talvez seja impossível revertê-lo.</p><h4 id="git-stash-drop"><strong><strong><strong>Git stash drop</strong></strong></strong></h4><p>Este comando exclui o <em>stash </em>mais recente da pilha. Use-o com cautela, pois pode ser difícil revertê-lo.</p><p>Você também pode especificar o <em>ID </em>do <em>stash</em>.</p><pre><code class="language-bash">git stash drop stash@{1}</code></pre><p>Espero que você tenha aprendido alguns truques úteis sobre o <em>Git stash</em>.</p><blockquote>Se você chegou até aqui, imagino que esteja bem interessado no Git. Confira o boletim informativo <a href="https://gitbetter.substack.com/" rel="noopener">Git Better</a> do autor para aprender novos truques e tópicos avançados do Git. :)</blockquote><p>Se você gostou do artigo, compartilhe-o. 😀</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como escrever um bom documento de design de software ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Angela Zhang Como engenheira de software, eu passo muito tempo lendo e escrevendo documentos de design. Após ter passado por centenas desses documentos, vi em primeira mão uma forte correlação entre bons documentos de design e o sucesso final do projeto. Este artigo é minha tentativa de descrever ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-escrever-um-bom-documento-de-design-de-software/</link>
                <guid isPermaLink="false">633d3e5affecac05daeb752c</guid>
                
                    <category>
                        <![CDATA[ Desenvolvimento de Software ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Sun, 13 Nov 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/img-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-write-a-good-software-design-document-66fcf019569c/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to write a good software design doc</a>
      </p><p>Escrito por: Angela Zhang</p><p>Como engenheira de software, eu passo muito tempo lendo e escrevendo documentos de design. Após ter passado por centenas desses documentos, vi em primeira mão uma forte correlação entre bons documentos de design e o sucesso final do projeto.</p><p>Este artigo é minha tentativa de descrever <strong>o que torna ótimo um documento de design.</strong></p><p>O artigo é dividido em 4 seções:</p><ul><li><strong>Por que</strong> escrever um documento de design</li><li><strong>O que</strong> incluir em um documento de design</li><li><strong>Como</strong> escrevê-lo</li><li>O <strong>processo</strong> que o envolve</li></ul><h3 id="por-que-escrever-um-documento-de-design"><strong>Por que escrever um documento de design?</strong></h3><p>Um documento de design – também conhecido como especificação técnica – é uma descrição de como você planeja resolver um problema.</p><p>Já existem <a href="https://www.joelonsoftware.com/2000/10/02/painless-functional-specifications-part-1-why-bother/">muitos escritos</a> (textos em inglês) sobre a importância de escrever um documento de design antes de começar a programar. Portanto, tudo o que vou dizer aqui é:</p><p><strong>Um documento de design é a ferramenta mais útil para garantir que o trabalho certo seja feito.</strong></p><p>O principal objetivo de um documento de design é torná-lo mais eficaz, forçando você a pensar no design e a obter feedback dos outros. As pessoas frequentemente pensam que o objetivo de um documento de design é ensinar aos outros sobre algum sistema ou servir como documentação mais tarde. Embora esses possam ser efeitos colaterais benéficos, eles <strong>não</strong> são o objetivo em si.</p><p>Como regra geral, se você estiver trabalhando em um projeto que pode levar um mês ou mais de engenharia, você deve escrever um documento de design. Porém, não pare por aí – muitos projetos menores também poderiam se beneficiar de um minidocumento de design.</p><p>Ótimo! Se você ainda está lendo, você acredita na importância dos documentos de design. Entretanto, equipes de engenharia diferentes e até mesmo engenheiros dentro de uma mesma equipe, muitas vezes, escrevem documentos de design de modos muito diferentes. Portanto, vamos falar sobre o conteúdo, estilo e processo de um bom documento de design.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/gj8fgseDg1J1gal9FQHJFTkKAMMGZN8XznjK.jpg" class="kg-image" alt="gj8fgseDg1J1gal9FQHJFTkKAMMGZN8XznjK" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/gj8fgseDg1J1gal9FQHJFTkKAMMGZN8XznjK.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/gj8fgseDg1J1gal9FQHJFTkKAMMGZN8XznjK.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="528" loading="lazy"><figcaption>Imagem de <a href="https://unsplash.com/photos/x5SRhkFajrA?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener">Todd Quackenbush</a>, extraída do <a href="https://unsplash.com/search/photos/ingredients?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener">Unsplash</a></figcaption></figure><h3 id="o-que-incluir-em-um-documento-de-design"><strong>O que incluir em um documento de design?</strong></h3><p>Um documento de design descreve a solução para um problema. Como a natureza de cada problema é diferente, naturalmente, você gostaria de estruturar seu documento de design de modos diferentes.</p><p>Para começar, a seguir está uma lista de seções que você deve pelo menos considerar incluir em seu próximo documento de design:</p><h3 id="t-tulo-e-pessoas"><strong>Título e pessoas</strong></h3><p>O título de seu documento de design, os autores (que devem ser os mesmos da lista de pessoas que planejam trabalhar neste projeto), os revisores do documento (falaremos mais sobre isso na seção Processo, abaixo), e a data em que este documento foi atualizado pela última vez.</p><h3 id="vis-o-geral"><strong>Visão geral</strong></h3><p>Um resumo de alto nível que todo engenheiro da empresa deve entender e usar para decidir se é útil para eles ler o resto do documento. Deve ter, no máximo, 3 parágrafos.</p><h3 id="contexto"><strong>Contexto</strong></h3><p>Uma descrição do problema em questão, por que este projeto é necessário, o que as pessoas precisam saber para avaliar este projeto e como ele se encaixa na estratégia técnica, na estratégia do produto ou nas metas trimestrais da equipe.</p><h3 id="objetivos-e-n-o-objetivos"><strong>Objetivos e não objetivos</strong></h3><p>A seção Objetivos deve:</p><ul><li>descrever o impacto de seu projeto – onde seu usuário pode ser outra equipe de engenharia ou mesmo outro sistema técnico</li><li>especificar como medir o sucesso usando métricas – com ainda maior valor se você puder conectar a seção a um painel que rastreie essas métricas</li></ul><p>"Não objetivos" são igualmente importantes para descrever quais problemas você <strong>não estará</strong> resolvendo para que todos saibam do que se está falando.</p><h3 id="marcos"><strong>Marcos</strong></h3><p>Uma lista de pontos notáveis mensuráveis para que seu gerente de projeto e para que o gerente dele possam olhar a lista e saber aproximadamente quando diferentes partes do projeto estarão concluídas. Eu o encorajo a quebrar o projeto em marcos importantes para o usuário, se o projeto tiver mais de um mês de duração.</p><p>Use datas no calendário para levar em conta atrasos não relacionados, férias, reuniões e assim por diante. Deve ser algo parecido com isto:</p><p><code>Data de início: 7 de junho de 2022</code><br><code>Marco nº 1 — Novo MVP do sistema em funcionamento em modo escuro: 28 de junho de 2022</code><br><code>Marco nº 2 - Aposentar o sistema antigo: 4 de julho de 2022</code><br><code>Encerramento: Adicionar os recursos X, Y e Z ao novo sistema: 14 de julho de 2022</code></p><p>Adicione uma subseção <code>[Atualização]</code> se a data final de entrega de alguns desses marcos mudar, para que as partes interessadas possam facilmente ver as estimativas mais atualizadas.</p><h3 id="solu-o-existente"><strong>Solução existente</strong></h3><p>Além de descrever a implementação atual, você também deve percorrer um fluxo de exemplo de alto nível para ilustrar como os usuários interagem com esse sistema e/ou como os dados fluem através dele.</p><p>Uma <strong>história de usuário</strong> é uma ótima maneira de enquadrar isto. Tenha em mente que seu sistema pode ter diferentes tipos de usuários com diferentes casos de uso.</p><h3 id="solu-o-proposta"><strong>Solução proposta</strong></h3><p>Algumas pessoas chamam isso de seção de <strong>Arquitetura técnica</strong>. Mais uma vez, percorra uma história de usuário para tornar isso concreto. Sinta-se à vontade para incluir muitas subseções e diagramas.</p><p>Forneça um quadro geral primeiro, depois preencha com <em>muitos</em> detalhes. Busque um mundo ideal onde você possa escrever essa seção e depois tirar férias em alguma ilha deserta, enquanto outro engenheiro da equipe pode simplesmente ler e implementar a solução do jeito que você a descreveu.</p><h3 id="solu-es-alternativas"><strong>Soluções alternativas</strong></h3><p>O que mais você considerou quando chegou à solução acima? Quais são os prós e contras das alternativas? Você já considerou comprar uma solução de terceiros – ou usar uma solução de código aberto – que resolva esse problema em vez de criar sua própria solução?</p><h3 id="testabilidade-monitoramento-e-alerta"><strong>Testabilidade, monitoramento e alerta</strong></h3><p>Gosto de incluir esta seção, porque as pessoas muitas vezes tratam essa parte como algo a se pensar depois ou simplesmente a ignoram. Quase sempre, isso volta para incomodar mais tarde, quando as coisas se quebram e eles não têm ideia de como ou por quê.</p><h3 id="impacto-entre-equipes"><strong>Impacto entre equipes</strong></h3><p>Como isso aumentará a carga de chamadas de solução de problemas e qual o impacto disso para a equipe de dev-ops?‌‌<br>Quanto dinheiro vai custar? ‌<br>‌Causa alguma regressão de latência para o sistema? ‌<br>Expõe alguma vulnerabilidade de segurança?<br>Quais são algumas das consequências negativas e dos efeitos colaterais? ‌<br>Como a equipe de suporte poderia comunicar isso aos clientes?</p><h3 id="perguntas-abertas"><strong>Perguntas abertas</strong></h3><p>Qualquer assunto em aberto sobre o qual você não tenha certeza, decisões controversas que você gostaria que os leitores ponderassem a respeito, sugestões de trabalho futuro e assim por diante. Um nome, de certo modo, irônica para esta seção são as "incógnitas conhecidas".</p><h3 id="escopo-detalhado-e-linha-de-tempo"><strong>Escopo detalhado e linha de tempo</strong></h3><p>Esta seção será lida, em geral, apenas pelos engenheiros que trabalham neste projeto, seus líderes técnicos e seus gerentes. Portanto, esta seção pode ficar ao final do documento.</p><p>Essencialmente, esta é a divisão de como e quando você planeja executar cada parte do projeto. Há muita coisa que entra na delimitação precisa do escopo. Então, você pode ler <a href="https://www.freecodecamp.org/news/how-to-effectively-scope-your-software-projects-from-planning-to-execution-e96cbcac54b9">este artigo</a> (texto em inglês) para saber mais sobre a delimitação do escopo.</p><p>Também tenho a tendência de tratar esta seção do documento de design como um rastreador das tarefas em andamento. Portanto, eu a atualizo sempre que minha estimativa de escopo muda. Isso, porém, é mais uma preferência pessoal.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/sGfVXpLpPjAP4aeejy0Sul3KviBKiX6kojUO.jpg" class="kg-image" alt="sGfVXpLpPjAP4aeejy0Sul3KviBKiX6kojUO" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/sGfVXpLpPjAP4aeejy0Sul3KviBKiX6kojUO.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/sGfVXpLpPjAP4aeejy0Sul3KviBKiX6kojUO.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="549" loading="lazy"><figcaption>Imagem de <a href="https://unsplash.com/photos/EF8Jr-uPS2Y?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener">rawpixel</a>, extraída do <a href="https://unsplash.com/search/photos/writing?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener">Unsplash</a></figcaption></figure><h3 id="como-escrev-lo"><strong>Como escrevê-lo</strong></h3><p>Agora que falamos sobre o <strong>que</strong> entra em um bom documento de design, vamos falar sobre o estilo de escrita. Prometo que será diferente de sua aula de inglês do ensino médio.</p><h3 id="escreva-da-maneira-mais-simples-poss-vel"><strong>Escreva da maneira mais simples possível</strong></h3><p>Não tente escrever como os trabalhos acadêmicos que você leu. Eles são escritos para impressionar os revisores dos periódicos. Seu documento é escrito para descrever a sua solução e obter feedback de seus colegas de equipe. Você pode obter clareza ao usar:</p><ul><li>Palavras simples</li><li>Frases curtas</li><li>Listas com pontos e/ou listas numeradas</li><li>Exemplos concretos, como "Usuário Alice conecta sua conta bancária, então ..."</li></ul><h3 id="adicione-muitos-gr-ficos-e-diagramas"><strong>Adicione muitos gráficos e diagramas</strong></h3><p>Os gráficos podem muitas vezes ser úteis para comparar várias opções potenciais. Os diagramas são, geralmente, mais fáceis de analisar do que o texto. Tive sorte com o aplicativo de Desenhos do Google para criar diagramas.</p><p><strong>Dica profissional</strong>: lembre-se de adicionar um link para a versão editável do diagrama sob a captura de tela para que você possa facilmente atualizá-lo mais tarde quando as coisas mudarem inevitavelmente.</p><h3 id="inclua-n-meros"><strong>Inclua números</strong></h3><p>A escala do problema, muitas vezes, determina a solução. Para ajudar os revisores a ter uma noção do estado das coisas, inclua números reais como nº de linhas de bancos de dados, nº de erros de usuários, latência – e como isso é escalável com o uso. Lembra-se das suas notações de Big-O?</p><h3 id="tente-ser-engra-ado"><strong>Tente ser engraçado</strong></h3><p>Uma especificação não é um trabalho acadêmico. Além disso, as pessoas gostam de ler coisas engraçadas. Então, essa é uma boa maneira de manter o leitor engajado. Não exagere, porém, a ponto de tirar o foco da ideia principal.</p><p>Se você, como eu, tem dificuldade em ser engraçado, <a href="https://en.wikipedia.org/wiki/Joel_Spolsky">Joel Spolsky</a> (obviamente conhecido por seus talentos cômicos...) tem esta dica:</p><blockquote><em>Uma das maneiras mais fáceis de ser engraçado é ser específico quando não é chamado para [Exemplo:] Em vez de dizer "pessoas com interesses especiais", dizer "cultivadores de abacate canhotos".</em></blockquote><h3 id="fa-a-o-teste-do-c-tico"><strong>Faça o teste do cético</strong></h3><p>Antes de enviar seu documento de design a outras pessoas para revisão, examine-o fingindo ser o revisor. Quais perguntas e dúvidas você pode ter sobre este design? Então, trate-as de antemão.</p><h3 id="fa-a-o-teste-das-f-rias"><strong>Faça o teste das férias</strong></h3><p>Se você passar um tempo maior em férias e sem acesso à internet, alguém de sua equipe pode ler o documento e implementar as coisas do modo como você pretendia?</p><p>O principal objetivo de um documento de design não é o compartilhamento de conhecimento, mas é uma boa maneira de avaliar a clareza para que outros possam realmente dar a você um feedback útil.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/vqucQKHbe0zhgV9DZiEwWmogFhFzZTROdxAc.jpg" class="kg-image" alt="vqucQKHbe0zhgV9DZiEwWmogFhFzZTROdxAc" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/vqucQKHbe0zhgV9DZiEwWmogFhFzZTROdxAc.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/vqucQKHbe0zhgV9DZiEwWmogFhFzZTROdxAc.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="533" loading="lazy"><figcaption>Imagem da <a href="https://unsplash.com/photos/IuE715vJo2I?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener">SpaceX</a> extraída da <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener">Unsplash</a></figcaption></figure><h3 id="processo"><strong>Processo</strong></h3><p>Ah, sim, a temida <em>palavra começando com P</em>. Os documentos de design ajudam a obter feedback antes que você gaste muito tempo implementando a solução errada ou a solução para o problema errado. Há muita coisa envolvida em se obter um bom feedback, mas isso é para um artigo posterior. Por enquanto, vamos apenas falar especificamente sobre como escrever o documento de design e obter feedback para ele.</p><p>Antes de mais nada, todos que trabalham no projeto devem fazer parte do processo de design. Não é problema se a liderança tecnológica acabar impulsionando muitas das decisões, mas todos devem estar envolvidos na discussão e aderir ao design. Portanto, quando falamos "você" ao longo deste artigo, lembre-se de que ele se aplica a todas as pessoas no projeto.</p><p>Em segundo lugar, o processo de design não significa que você está olhando para as ideias teóricas do quadro branco. Sinta-se à vontade para colocar as mãos à obra e fazer um protótipo de soluções potenciais. Isso não é a mesma coisa que começar a escrever o código de produção para o projeto antes de escrever um documento de design. Não faça isso. Você <em>deve</em>, no entanto, se sentir absolutamente livre para escrever algum código enjambrado e que você possa descartar depois apenas para validar uma ideia. Para garantir que você só escreva código exploratório, faça com que seja uma regra que <strong>nenhum código desse protótipo seja inserido na branch master/main</strong>.</p><p>Depois disso, ao começar a ter alguma ideia de como realizar seu projeto, faça o seguinte:</p><ol><li>Peça a um engenheiro ou líder técnico experiente em sua equipe para ser seu revisor. O ideal seria que fosse alguém bem respeitado e/ou familiarizado com os casos de ponta do problema. Convença-os com algum presentinho, se necessário.</li><li>Vá com o colega a uma sala de conferências com um quadro branco.</li><li>Descreva o <strong>problema</strong> que você está enfrentando para este engenheiro (este é um passo muito importante, não o pule!).</li><li>Explique a <strong>implementação</strong> que você tem em mente e convença o engenheiro de que esta é a coisa certa a ser construída.</li></ol><p>Fazer tudo isso <strong>antes</strong> mesmo de começar a escrever seu documento de design permite que você receba feedback o mais rápido possível, antes de investir mais tempo e se apegar a qualquer solução específica. Muitas vezes, mesmo que a implementação permaneça a mesma, seu revisor é capaz de apontar os casos limite que você precisa cobrir, indicar quaisquer áreas potenciais de confusão e antecipar dificuldades que você possa encontrar mais tarde.</p><p>Então, depois de escrever um rascunho do seu documento de design, peça ao mesmo revisor que o leia novamente, e carimbe-o adicionando o seu nome como revisor na seção <strong>Título e Pessoas</strong> do documento de design. Isto cria um incentivo adicional e responsabilidade para o revisor.</p><p>Sobre essa nota, considere a adição de revisores especializados (tais como SREs e engenheiros de segurança) para aspectos específicos do design.</p><p>Assim que você e os revisores assinarem, sinta-se à vontade para enviar o documento de design à sua equipe para feedback adicional e compartilhamento de conhecimento. Sugiro que este processo de coleta de feedback seja limitado no tempo a cerca de 1 semana para evitar atrasos prolongados. Comprometa-se a responder a todas as perguntas e comentários que as pessoas deixarem durante essa semana. <strong>Deixar comentários pendentes = muito azar.</strong></p><p>Finalmente, se houver muito conflito entre você, seu revisor e outros engenheiros que leem o documento, recomendo fortemente a consolidação de todos os pontos de conflito na seção <strong>Discussão</strong> do seu documento. Então, marque uma reunião com as diferentes partes para falar pessoalmente sobre essas discordâncias.</p><p>Sempre que um tópico de discussão tiver mais de 5 comentários, passar para uma discussão presencial tenderá a ser muito mais eficiente. Tenha em mente que você ainda é responsável por fazer a chamada final, mesmo que nem todos consigam chegar a um consenso.</p><p>Ao falar com um colega recentemente sobre isso, soube que ele tem um processo semelhante, exceto pelo fato de que, além de ter um engenheiro experiente ou líder técnico em sua equipe como revisor, eles também sugerem ter um engenheiro de uma equipe <em>diferente</em> para revisar o documento. Eu não tentei isso, mas certamente posso ver o quanto ajuda obter feedback de pessoas com perspectivas diferentes e melhorar a legibilidade geral do documento.</p><p>Uma vez que você tenha feito tudo o que vemos acima, é hora de começar a implementação! Para ganhar uns pontos a mais, <strong>trate este documento de projeto como um documento vivo à medida que você implementa o design</strong>. Atualize o documento toda vez que aprender algo que o leve a fazer mudanças na solução original ou atualizar seu escopo. Você vai me agradecer mais tarde quando não tiver que explicar as coisas repetidas vezes a todas as partes interessadas.</p><p>Por fim, vamos <em>realmente</em> fazer um metadiscurso por um segundo: Como avaliamos o sucesso de um documento de design?</p><p>Meu colega de trabalho, <a href="https://www.linkedin.com/in/krakip/">Kent Rakip</a>, tem uma boa resposta para isso: <strong>Um documento de design é bem-sucedido se o ROI correto de trabalho for feito</strong>. Isso significa que um documento de design bem-sucedido pode realmente levar a um resultado como este:</p><ol><li>Você gasta 5 dias escrevendo o documento de projeto, o que força você a pensar em diferentes partes da arquitetura técnica</li><li>Você recebe o feedback de revisores de que <code>X</code> é a parte mais arriscada da arquitetura proposta</li><li>Você decide implementar <code>X</code> primeiro para reduzir o risco do projeto</li><li>3 dias depois, você descobre que <code>X</code> não é possível ou é muito mais difícil do que você pretendia originalmente</li><li>Você decide parar de trabalhar neste projeto e prioriza outros trabalhos em seu lugar</li></ol><p>No início deste artigo, dissemos que o objetivo de um documento de design <strong>é garantir que o trabalho certo seja feito.</strong> No exemplo acima, graças a este documento de design, em vez de desperdiçar potencialmente meses apenas para abandonar este projeto mais tarde, você gastou apenas 8 dias. Parece-me um resultado muito bem-sucedido.</p><p>Para creditar aqueles que merecem, eu aprendi muito do que mostro acima ao trabalhar ao lado de alguns engenheiros incríveis na <a href="https://plaid.com/">Plaid</a> e na <a href="https://www.quora.com/careers">Quora</a>.</p><p>Se você gostou deste artigo, <a href="https://www.twitter.com/zhangelaz">siga a autora no Twitter</a> para mais artigos sobre engenharia, processos e sistemas de back-end.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como instalar as ferramentas de linha de comando do Xcode no Mac ]]>
                </title>
                <description>
                    <![CDATA[ Os desenvolvedores precisam instalar as ferramentas de linha de comando do Xcode antes de começar a desenvolver software no Mac. A Apple fornece um ambiente de desenvolvimento completo para os programadores, chamado de Xcode. Se estiver desenvolvendo software para o macOS, o iOS, o tvOS e o watchOS, deve instalar ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-instalar-as-ferramentas-de-linha-de-comando-do-xcode-no-mac/</link>
                <guid isPermaLink="false">61f7bfcd53557304fa19d7bd</guid>
                
                    <category>
                        <![CDATA[ Desenvolvimento de Software ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Mon, 31 Jan 2022 11:50:09 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/Terminal_Mac.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/install-xcode-command-line-tools/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Install Xcode Command Line Tools on a Mac</a>
      </p><p>Os desenvolvedores precisam instalar as ferramentas de linha de comando do Xcode antes de começar a desenvolver software no Mac.</p><p>A Apple fornece um ambiente de desenvolvimento completo para os programadores, chamado de Xcode. Se estiver desenvolvendo software para o macOS, o iOS, o tvOS e o watchOS, deve instalar a aplicação completa do Xcode.</p><p>Se já não estiver pré-instalada, você pode instalá-la a partir do <a href="https://developer.apple.com/download/">site do desenvolvedor da Apple</a> ou da App Store no Mac.</p><h2 id="o-que-s-o-as-ferramentas-de-linha-de-comando-do-xcode"><strong>O que são as </strong>ferramentas de linha de comando do Xcode<strong><strong>?</strong></strong></h2><p>Se não estiver desenvolvendo software para um dispositivo da Apple, você não precisa da aplicação completa do Xcode (são necessários 40GB de espaço em disco!).</p><p>Em vez disso, você pode instalar as ferramentas de linha de comando do Xcode. É um pacote pequeno para desenvolvedores de software com ferramentas que rodam na linha de comando, ou seja, na aplicação do Terminal.</p><p>Os programadores já usavam essas ferramentas nos sistemas operacionais do Unix desde o início da computação. Elas servem como base de quase todo o desenvolvimento de software.</p><p>Por sorte, o pacote das ferramentas de linha de comando do Xcode precisam apenas de 1,2 GB de espaço em disco.</p><p>Você tem três escolhas de instalação das ferramentas de linha de comando do Xcode no Mac:</p><ul><li>instalar o pacote completo do Xcode</li><li>instalar as ferramentas de linha de comando do Xcode quando sugerido por um comando</li><li>instalar as ferramentas de linha de comando do Xcode como parte de uma instalação do Homebrew.</li></ul><p>Eu não recomendo instalar o pacote completo do Xcode a menos que você esteja desenvolvendo software para um dispositivo da Apple. O download demora muito e consome espaço em disco desnecessário. Em vez disso, tente um dos outros dois métodos, que são mais rápidos.</p><h2 id="como-instalar-as-ferramentas-de-linha-de-comando-do-xcode-a-partir-de-um-prompt-de-comando"><strong>Como instalar as </strong>ferramentas de linha de comando do Xcode<strong> a partir de um prompt de comando</strong></h2><p>A Apple facilitou a instalação das ferramentas de linha de comando do Xcode, pois alguns comandos solicitarão que você comece a instalação.</p><p>Aqui temos exemplos de comandos que sugerirão a instalação das ferramentas de linha de comando do Xcode:</p><ul><li><code>clang</code> – um compilador que transforma código fonte em um programa executável</li><li><code>gcc</code> – o compilador GNU</li><li><code>git</code> – o sistema de controle de versão que salva arquivos em processo</li></ul><p>Ao rodar qualquer um desses comandos no Terminal, será solicitada a instalação das ferramentas de linha de comando do Xcode. Já fiz um artigo sobre <a href="https://mac.install.guide/terminal/index.html">como abrir o Terminal no MacOS</a> (texto em inglês) – basta clicar no ícone do Spotlight, na barra de menu, e digitar “terminal.”</p><p>Você também pode inserir o comando <code>xcode-select --install</code> no terminal para começar o processo de instalação. Você verá um painel que pede que você instale as ferramentas de linha de comando do Xcode.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/install-Xcode-CLT.png" class="kg-image" alt="install-Xcode-CLT" width="573" height="307" loading="lazy"></figure><p>Clique em 'Install' para começar o download e o processo de instalação.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/install-Xcode-CLT-progress.png" class="kg-image" alt="install-Xcode-CLT-progress" width="566" height="230" loading="lazy"></figure><p>A instalação leva 8 minutos em um Mac M1 Mini de 2021, com uma conexão com a internet de 100Mbps. Ela é significativamente mais lenta no Mac Intel em uma conexão lenta com a internet.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/install-Xcode-CLT-done.png" class="kg-image" alt="install-Xcode-CLT-done" width="566" height="200" loading="lazy"></figure><p>Você verá uma mensagem de confirmação quando a instalação estiver concluída.</p><p>Verifique se você instalou com sucesso as ferramentas de linha de comando do Xcode:</p><pre><code class="language-bash">$ xcode-select -p
</code></pre><p>Você verá o seguinte:</p><pre><code class="language-bash">/Library/Developer/CommandLineTools
</code></pre><h2 id="como-usar-o-homebrew-para-instalar-as-ferramentas-de-linha-de-comando-do-xcode"><strong>Como usar o <strong>Homebrew </strong>para instalar as<strong> </strong></strong>ferramentas de linha de comando do Xcode</h2><p>Por mais fácil que possa ser usar o prompt de comando para instalar as ferramentas de linha de comando do Xcode, eu recomendo um método ainda mais fácil: usar o Homebrew.</p><p>Essa opção foi adicionada ao Homebrew recentemente. Por isso, muitos desenvolvedores ainda não sabem sobre ela.</p><p>O Homebrew é um conhecido gerenciador de pacotes para o Mac. A maioria dos desenvolvedores precisa de linguagens de programação e programas utilitários que não vêm instalados no macOS e que não estão incluídos no pacote das ferramentas de linha de comando do Xcode. O Homebrew pode instalar quase toda ferramenta de código aberto para os desenvolvedores.</p><p>Como você provavelmente precisará do Homebrew em algum momento, pode ser interessante deixar que o Homebrew instale as ferramentas de linha de comando do Xcode para você.</p><p>Primeiro, verifique se o Homebrew já está instalado.</p><pre><code class="language-bash">$ brew
</code></pre><p>Se o Homebrew não estiver instalado, você verá uma mensagem assim:</p><pre><code class="language-bash">zsh: command not found: brew
</code></pre><p>O Homebrew fornece um script de instalação que você pode executar em um único comando (verifique se ele não mudou no <a href="https://brew.sh/">site do Homebrew</a>).</p><pre><code class="language-bash">$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
</code></pre><p>O script de instalação do Homebrew pedirá que você insira sua senha do Mac. Essa é a senha que você usa para entrar no Mac.</p><pre><code class="language-bash">Password:
</code></pre><p>Você não verá os caracteres enquanto digita. Pressione Enter quando tiver concluído.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/homebrew-enter-password.png" class="kg-image" alt="homebrew-enter-password" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/01/homebrew-enter-password.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/01/homebrew-enter-password.png 697w" width="697" height="245" loading="lazy"></figure><p>Se você ainda não instalou as ferramentas de linha de comando do Xcode, verá a seguinte mensagem: "The Xcode Command Line Tools will be installed." Pressione Return para continuar quando isso for pedido pelo script de instalação do Homebrew.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/install-homebrew.png" class="kg-image" alt="install-homebrew" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/01/install-homebrew.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/01/install-homebrew.png 697w" width="697" height="525" loading="lazy"></figure><p>Você verá mensagens de diagnóstico e de andamento da instalação. A instalação do Homebrew leva de 2 a 15 minutos em um Mac M1 Mini de 2021, com uma conexão com a internet de 100Mbps. Ela é significativamente mais lenta em um Mac Intel com uma conexão lenta com a internet.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/homebrew-complete.png" class="kg-image" alt="homebrew-complete" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/01/homebrew-complete.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/01/homebrew-complete.png 653w" width="653" height="355" loading="lazy"></figure><p>Nas máquina Mac Intel, isso é tudo o que você precisa fazer – o Homebrew está pronto para ser utilizado. No Mac Intel, o Homebrew é instalado no diretório <code>/usr/local/bin</code>, que já está configurado para o acesso pelo shell como o <code>$PATH</code> padrão do macOS.</p><p>Nas máquinas Silicon da Apple, é preciso mais uma etapa. Os arquivos do Homebrew são instalados na pasta <code>/opt/homebrew</code>. Mas a pasta não é parte do <code>$PATH</code> padrão. Siga o conselho do Homebrew e crie um arquivo <code>~/.zprofile</code> que contenha um comando que configura o Homebrew. O Homebrew mostra as instruções ao final do processo de instalação:</p><pre><code class="language-bash">- Add Homebrew to your PATH in ~/.zprofile:
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' &gt;&gt; ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
</code></pre><p>Após instalar o Homebrew, verifique se o Homebrew está instalado adequadamente.</p><pre><code class="language-bash">$ brew doctor
</code></pre><p>Você verá o seguinte:</p><pre><code class="language-bash">Your system is ready to brew.
</code></pre><p>O Homebrew está instalado com sucesso. Os arquivos do Homebrew estarão em <code>/usr/local</code> (para os macOS Intel) ou em <code>/opt/homebrew</code> (para os Silicon da Apple).</p><p>Agora, você já tem instalados as ferramentas de linha de comando do Xcode e o Homebrew. Se quiser saber mais sobre como adicionar pacotes do Homebrew para configurar seu ambiente de desenvolvimento, consulte <a href="https://mac.install.guide/homebrew/6.html">Install a Homebrew Package</a> (em inglês).</p><h2 id="mais-informa-es"><strong><strong>M</strong>ais informações</strong></h2><p>Eu também escrevi um guia detalhado sobre como <a href="https://mac.install.guide/commandlinetools/index.html">instalar as ferramentas de linha de comando do Xcode</a> (em inglês) que vai além do básico descrito aqui.</p><p>No guia, eu explico como verificar se as <a href="https://mac.install.guide/commandlinetools/2.html">ferramentas de linha de comando do Xcode já estão instaladas</a>. Entro em mais detalhes sobre como <a href="https://mac.install.guide/commandlinetools/3.html">instalar as ferramentas de linha de comando do Xcode com o Homebrew</a>. Por fim, explico como <a href="https://mac.install.guide/commandlinetools/6.html">desinstalar as ferramentas de linha de comando do Xcode</a>, <a href="https://mac.install.guide/commandlinetools/7.html">reinstalar as ferramentas de linha de comando do Xcode</a> e dou uma <a href="https://mac.install.guide/commandlinetools/8.html">lista das ferramentas de linha de comando do Xcode</a> que você pode usar (textos em inglês).</p><p>Também existe um guia completo de como <a href="https://mac.install.guide/homebrew/index.html">instalar o Homebrew para o Mac</a> que explica como <a href="https://mac.install.guide/homebrew/4.html">atualizar o Homebrew</a>, <a href="https://mac.install.guide/homebrew/5.html">desinstalar o Homebrew</a> e se manter atualizado na <a href="https://mac.install.guide/homebrew/8.html">manutenção do Homebrew</a> (textos em inglês).</p><h2 id="seu-ambiente-de-desenvolvimento"><strong>Seu ambiente de desenvolvimento</strong></h2><p>O MacOS é a plataforma mais popular de desenvolvimento de software pelo fato de o sistema operacional ter como base o Unix, o sistema padrão para o desenvolvimento de software já há bastante tempo.</p><p>Com as ferramentas de linha de comando do Xcode instaladas, você terá uma base sólida para adicionar praticamente qualquer ferramenta de desenvolvimento de código aberto.</p><p>Adicione o Homebrew e você terá um gerenciador de pacotes que pode instalar gerenciadores de versão, linguagens de programação e quase todas as outras ferramentas de que você precisa.</p><p>Combinados com um editor de texto e uma aplicação de terminal, você estará preparado para qualquer tutorial que encontrar no freeCodeCamp.</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
