Até 50% OFF

A maior oferta do ano está chegando ao fim

61%

A maior oferta do ano está acabando

61%

Últimos 12 dias
Vai ficar de fora?

Alura > Cursos de Programação > Cursos de Node.JS > Conteúdos de Node.JS > Primeiras aulas do curso Node.js: clean code, arquitetura limpa e boas práticas

Node.js: clean code, arquitetura limpa e boas práticas

Os princípios de clean code - Apresentação

Apresentando o instrutor e o curso

Olá! Boas-vindas ao nosso curso de Clean Code na Alura. Meu nome é Anderson Mello, sou engenheiro de software sênior, líder técnico e arquiteto de soluções. Sou especialista em JavaScript e TypeScript de Alta Performance. Vamos iniciar nossa jornada para explorar o Clean Code.

Audiodescrição: Anderson é um homem branco, com cabelos e barba loiros, e usa óculos redondos.

Introduzindo os conceitos de Clean Code

Vamos entender o que aprenderemos no curso sobre Clean Code. Começaremos discutindo os fundamentos do Clean Code, sua origem e a razão de sua utilização. Também abordaremos como construir um código legível e, mais importante, fácil de manter ao longo do tempo. Além disso, exploraremos onde e como aplicar arquitetura limpa em nossos projetos.

Refatoraremos o código e implementaremos melhorias para compreender como trabalhar com aplicações legadas. Utilizaremos o Dash.js, o framework mais popular de JavaScript atualmente, para construir uma aplicação verdadeiramente limpa.

Explorando as APIs e projetos do curso

No curso, trabalharemos com duas APIs, em dois projetos, para aprofundar nossos temas. O primeiro será uma API de cadastro de usuários e endereços. Começaremos com uma aplicação express simples, mas repleta de defeitos e desafios para nós.

Nós vamos abordar os conceitos de Clean Code e iniciar a refatoração na prática. Vamos entender como aplicamos o que estamos vendo na teoria em nosso dia a dia enquanto pessoas engenheiras de código. Em seguida, partiremos para uma API de e-commerce com usuários, produtos e carrinhos. Vamos compreender como, dentro do universo do Dash.js, aplicamos arquitetura limpa, Clean Code e também arquitetura hexagonal, entendendo como esses conceitos se interligam.

Estabelecendo os pré-requisitos para o curso

Para aproveitar melhor este curso, há alguns pré-requisitos. Algumas bases são necessárias para um bom andamento no aprendizado. Primeiramente, é importante ter conhecimento em JavaScript e TypeScript. Precisamos entender a linguagem, sua sintaxe, o uso de constantes, variáveis e let. Também é necessário saber como utilizamos algumas propriedades, como arrays e objetos, e como construímos códigos simples em JavaScript.

Além disso, é importante ter uma noção do que é o Next.js. Não é necessário um conhecimento aprofundado ou decorar toda a documentação, mas uma leitura básica sobre seu funcionamento será de grande ajuda em nossa jornada. Também vale a pena ter conhecimento sobre Express, entender como ele funciona, por que é usado e em que momento é utilizado. Uma olhada na documentação será útil, pois há muito código legado escrito em Express, o que será valioso no dia a dia.

Concluindo a introdução ao curso

Portanto, há muito para aprender e muito conteúdo interessante em nosso curso sobre Clean Code. Estamos ansiosos para começar a prática. Nos vemos na próxima aula.

Os princípios de clean code - O que é código limpo?

Introduzindo o conceito de Clean Code

Agora, vamos dar sequência ao nosso curso de Clean Code. Para começar esta aula, vamos analisar o que realmente faz sentido em termos de Clean Code no dia a dia. Trouxemos um pequeno spoiler da aplicação que desenvolveremos nos próximos vídeos. A ideia é demonstrar a importância de nos preocuparmos com Clean Code.

Vamos analisar dois tipos de práticas, com duas imagens lado a lado no slide. Do lado esquerdo, focamos nas práticas ruins, e do lado direito, nas boas práticas. Ao entrar em um projeto e se deparar com um cenário como o do lado esquerdo, pode ser complicado entender a que entidades de domínio esses tipos se referem. Isso torna as coisas mais difíceis do que deveriam ser.

Comparando práticas de codificação

No lado esquerdo, temos o tipo TP e o tipo TU. Vamos ver como esses tipos são definidos:

type TP = {
    id: number;
    nc: string;
    uf: string;
};

type TU = {
    id: number;
    nc: string;
    d: string;
    end: {
        r: string;
        n: number;
        c_id: number;
    };
};

Se destrincharmos esses dois tipos, veremos que o ID é comum entre eles. O ID é uma nomenclatura comum para identidade, mas se não renomearmos esses tipos adequadamente, fica complicado saber a que esse ID se refere no futuro, especialmente quando distanciamos um objeto ou uma classe.

No tipo TP, ao olhar para NC, não temos ideia do que esse campo representa no negócio, mesmo sabendo que é uma string. O F pode ter um contexto claro para brasileiros, mas é importante evitar suposições no código, pois isso pode introduzir bugs e problemas.

Melhorando a clareza do código

No tipo TU, temos o mesmo cenário com ID e NC, além de outros atributos que não são claros. Por exemplo, AND é um objeto com propriedades R, N e CID. Podemos assumir que CID se refere à identidade de algo, mas sem saber o relacionamento, é complicado entender o código.

Agora, ao olhar para o lado direito, apenas pelo nome do tipo, ganhamos em leitura, manutenibilidade e entendimento. A primeira entidade refere-se claramente a uma cidade. Não deixamos dúvidas ao nomear as propriedades. No contexto de cidade, temos o ID, o nome da cidade e a unidade federativa, que pode ser abreviada para UF.

Exemplificando boas práticas de nomenclatura

Vamos ver como isso é representado no código:

type cidade = {
    id: number;
    nome_cidade: string;
    uf: string;
};

No tipo usuário, temos algo semelhante. No exemplo anterior, ambos os tipos tinham NC. Sem contexto, poderíamos assumir que se referem à mesma coisa. No exemplo limpo, em cidade é nome cidade e em usuário é nome completo. Deixar isso explícito faz total diferença na leitura do código.

type usuario = {
    id: number;
    nome_completo: string;
    doc: string;
    end: {
        rua: string;
        num: number;
        cidade_id: number;
    };
};

Ao falar de usuário, doc refere-se a documento e endereço é claro pelo contexto e nomenclatura, facilitando o entendimento de rua, número e o ID da cidade referenciada no outro tipo.

Explorando o conceito de código limpo

Com isso em mente, surge a pergunta: o que é código limpo? Este termo vem de um material, um livro publicado por Robert C. Martin, também conhecido como Uncle Bob na comunidade, é um engenheiro de software norte-americano extremamente famoso, com mais de quarenta ou cinquenta anos de experiência. Ele possui vasta experiência e já passou por muitas situações. O termo "código limpo" refere-se a maneiras, padrões e sugestões para manter um código simples, coeso, uniforme e, o mais importante, fácil de manter.

Quando falamos de código, é essencial entender que, no dia a dia, não escrevemos código apenas para a máquina, ou seja, não escrevemos código exclusivamente para ser compilado em uns e zeros. A escrita de código é feita para nossos pares, colegas e para nós mesmos no futuro, como uma referência para manutenção. Com o passar do tempo, percebemos que é difícil lembrar o que um código escrito anteriormente faz. Portanto, ter um código autodeclarativo, que carrega consigo os entendimentos sobre as regras e domínios a que se refere, facilita muito a vida.

Discutindo a importância da simplicidade e eficiência

Podemos falar em DNA de código limpo. O primeiro ponto é que o código precisa ser simples, o que traz uma elegância natural. Além disso, o código precisa ser eficiente. As linguagens estão muito otimizadas, então muitas vezes precisamos balancear, mas um código bem escrito, que considera os conceitos de Clean Code (Código Limpo) e Clean Architecture (Arquitetura Limpa), será mais performático.

A legibilidade é crucial e afeta a manutenibilidade do código limpo. Manter um código bem escrito é muito mais simples do que manter um código desorganizado e problemático. Talvez a parte mais importante do código limpo seja ele ser centrado no ser humano. Escrevemos código de maneira colaborativa e precisamos considerar isso sempre que escrevemos para outras pessoas.

Abordando os custos de um código mal escrito

Se não escrevermos um código minimamente limpo, enfrentaremos problemas. Todo código mal escrito tem custo. Para o cliente, o que importa são os atrasos na entrega. No mercado de trabalho, muitas coisas podem acontecer, pois dependemos de fatores externos, mas, no final, o cliente sempre observa os atrasos. Essa é apenas a ponta do iceberg.

Nos bastidores, quem trabalha com o código percebe um aumento na complexidade. Introduzimos, infelizmente, dependências difíceis de rastrear, o que aumenta o risco de bugs (erros). É fácil confundir exemplos e achar que são intercambiáveis, o que inevitavelmente traz bugs para o código. Além disso, depurar o código se torna mais complicado, pois precisamos descobrir a causa dos erros e obter contexto, o que é difícil no dia a dia.

Concluindo com a aplicação prática do Clean Code

Tudo isso culmina nos atrasos nas entregas, mas há uma série de fatores ocultos que dificultam a vida de quem desenvolve o código. Até aqui, entendemos a teoria do código limpo e os custos de um código ruim. Agora, começaremos a ver na prática como isso afeta o desenvolvimento. Vamos colocar a mão no código, trabalhar na aplicação e entender como isso se aplica no dia a dia de quem desenvolve. Nos vemos em breve.

Os princípios de clean code - Nomeação significativa e padrões de nomenclatura

Introduzindo o projeto de refatoração

Estamos de volta com mais um vídeo do nosso curso de clean code (código limpo) e, desta vez, começamos a colocar a mão na massa. Preparamos uma aplicação em Express para refatorarmos juntos. Atualmente, ela implementa padrões extremamente ruins, e a ideia é que nós refatoremos essa aplicação, tanto na maneira como está estruturada quanto na nomeação dos tipos, variáveis e funções. Esta é uma API que traz funcionalidades de cidades e usuários.

Atualmente, a aplicação está em um único arquivo, index.ts, com tudo agrupado da pior maneira possível. Nosso objetivo é criar a estrutura necessária, nomeá-la adequadamente e implementar as melhores práticas. Temos o padrão de uma aplicação e um conjunto de dependências simples, mas suficientes para começarmos a entender e navegar no mundo do código limpo.

Executando a aplicação pela primeira vez

Antes de prosseguirmos, vamos mostrar como rodar essa aplicação. Para quem está utilizando qualquer editor, a primeira coisa a fazer é abrir o terminal. No terminal, ao rodar pela primeira vez, é necessário executar o comando npm install. Isso analisará todas as dependências listadas no package.json e as instalará, permitindo que rodemos a aplicação localmente.

npm install

Após o npm install, ainda no terminal, executamos npm run. No terminal, veremos que a aplicação está rodando, com um servidor de exemplo operando na porta 3000. Assim, nossa aplicação já está funcionando.

npm run dev

Desafiando a análise do código

Antes de começarmos a refatorar, queremos deixar um desafio para vocês. Pausem o vídeo, analisem o código, observem os comentários que fornecem contexto sobre a aplicação, mas notem que o código está longe do que pretendemos alcançar. Analisem, identifiquem problemas e tentem melhorar o código por conta própria. Vamos aguardar vocês.

Conseguiram identificar problemas? Espero que sim, pois esta aplicação está cheia deles. Mas, se não encontraram, não se preocupem. Vamos começar agora, juntos, a entender essa aplicação e ver como melhorá-la.

Refatorando o tipo de cidade

A primeira coisa que vamos analisar no código é o tipo definido na linha 25, o tipo TP. Ele serviu de exemplo para introdução ao que é código limpo e já é um excelente ponto de partida para colocarmos as coisas em prática. Acima dele, há algumas linhas de comentário. Este tipo representa uma cidade, com propriedades como ID, nome da cidade e unidade federativa, representada por UF.

type TP = {
    id: number;
    nome_cidade: string;
    uf: string;
};

Como este tipo modela uma entidade relacionada a cidade em nosso domínio, faz sentido chamá-lo de ModeloCidade.

type ModeloCidade = {
    id: number;
    nome_cidade: string;
    uf: string;
};

Para facilitar, as IDEs possuem uma ferramenta de renomeação que podemos utilizar. Se estivermos utilizando o atalho Shift + F6, podemos pressionar F2 para renomear todas as ocorrências de um termo no nosso código. Assim, não precisamos fazer isso manualmente, uma a uma. No meu caso, vou usar Shift + F6 para renomear para modeloCidade.

Refatorando o tipo de usuário

De maneira similar, ao observarmos a linha 36 do nosso código, encontramos o tipo que representa um usuário. Esse tipo possui algumas propriedades: um ID, o nome completo, um documento e um endereço. Idealmente, essas informações viriam de uma documentação externa, mas aqui utilizamos comentários para nos guiar. O endereço, por sua vez, é um objeto que contém rua, número e o ID da cidade, o que gera um relacionamento.

type TU = {
    id: number;
    nome_completo: string;
    doc: string;
    end: {
        rua: string;
        num: number;
        cidade_id: number;
    };
};

Assim como no modeloCidade, na linha 36, podemos usar a ferramenta de refatoração para renomear para algo mais significativo. Nesse caso, modeloUsuario seria uma nomenclatura adequada.

type ModeloUsuario = {
    id: number;
    nome_completo: string;
    doc: string;
    end: {
        rua: string;
        num: number;
        cidade_id: number;
    };
};

Explorando padrões de nomenclatura

Tanto na linha 25 quanto na linha 36, renomeamos cada um desses tipos para um nome com duas palavras, mas poderiam ser mais. Cada uma dessas palavras começa com letra maiúscula. Para quem está começando na programação, isso pode não parecer importante, mas para quem já tem experiência, entende a relevância. Existem padrões de nomenclatura de código que são boas práticas e variam de linguagem para linguagem. Ao nomear um tipo, preferimos que as primeiras palavras tenham a primeira letra maiúscula. Esse padrão tem um nome e facilita a comunicação sobre esses padrões com outras pessoas, seja em artigos ou discussões sobre o comportamento do nosso código.

O modelo que usamos na tipagem é conhecido como PascalCase. Vamos explorar mais informações sobre esses modelos e como eles funcionam ao nomear tipos, variáveis, classes e afins no nosso código. Os tipos que renomeamos para modeloCidade e modeloUsuario seguem o padrão PascalCase, onde a primeira letra de cada palavra é maiúscula.

Em JavaScript, ao tratar variáveis, funções e métodos, é comum usar o padrão camelCase, onde a primeira palavra é toda em minúsculo e as subsequentes têm a primeira letra maiúscula. No Python e SQL, utilizamos o padrão snake_case, principalmente ao nomear constantes que serão reutilizadas no código. Para nomenclatura de arquivos, usamos o padrão kebab-case, onde cada palavra é separada por um hífen.

Esses são os padrões mais comumente utilizados e farão parte do nosso dia a dia enquanto pessoas desenvolvedoras. É importante se familiarizar com eles, pois serão bastante utilizados daqui para frente. Nos vemos na próxima aula.

Sobre o curso Node.js: clean code, arquitetura limpa e boas práticas

O curso Node.js: clean code, arquitetura limpa e boas práticas possui 181 minutos de vídeos, em um total de 58 atividades. Gostou? Conheça nossos outros cursos de Node.JS em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Node.JS acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas