"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Compreendendo o Código Limpo: Sistemas ⚡️

Compreendendo o Código Limpo: Sistemas ⚡️

Publicado em 2024-11-02
Navegar:923

Understanding Clean Code: Systems ⚡️

Ao construir sistemas de software, é crucial gerenciar a complexidade da base de código.

O Capítulo 11 do Clean Code discute o projeto de sistemas modulares que são mais fáceis de manter e adaptar ao longo do tempo.

Podemos usar exemplos de JavaScript para ilustrar esses conceitos.


? O problema com grandes sistemas

À medida que os sistemas crescem, eles naturalmente se tornam mais complexos. Essa complexidade pode dificultar:

  • Entenda o sistema como um todo.
  • Faça alterações sem causar efeitos colaterais indesejados.
  • Amplie o sistema com novos recursos ou requisitos.

Um sistema bem projetado deve ser fácil de modificar, testável e escalonável. O segredo para conseguir isso está na modularidade e na separação cuidadosa de interesses.


? Modularidade: Dividir e Conquistar

No cerne do design de sistemas limpos está o princípio da modularidade. Você torna o sistema mais gerenciável dividindo um sistema grande em módulos menores e independentes, cada um com uma responsabilidade clara.

Cada módulo deve encapsular uma funcionalidade específica, tornando o sistema geral mais fácil de entender e mudar.

Exemplo: organizando um sistema de carrinho de compras

Vamos imaginar um sistema de carrinho de compras em JavaScript. Em vez de agrupar toda a lógica em um único arquivo, você pode dividir o sistema em vários módulos:

// cart.js
export class Cart {
    constructor() {
        this.items = [];
    }

    addItem(item) {
        this.items.push(item);
    }

    getTotal() {
        return this.items.reduce((total, item) => total   item.price, 0);
    }
}

// item.js
export class Item {
    constructor(name, price) {
        this.name = name;
        this.price = price;
    }
}

// order.js
import { Cart } from './cart.js';
import { Item } from './item.js';

const cart = new Cart();
cart.addItem(new Item('Laptop', 1000));
cart.addItem(new Item('Mouse', 25));

console.log(`Total: $${cart.getTotal()}`);

As responsabilidades são divididas aqui: Cart gerencia os itens, Item representa um produto e order.js orquestra as interações.

Essa separação garante que cada módulo seja independente e mais fácil de testar e alterar de forma independente.


? Encapsulamento: ocultar detalhes de implementação

Um dos objetivos da modularidade é o encapsulamento – ocultar o funcionamento interno de um módulo do resto do sistema.

O código externo só deve interagir com um módulo por meio de sua interface bem definida.

Isso facilita a alteração da implementação interna do módulo sem afetar outras partes do sistema.

Exemplo: encapsulando a lógica do carrinho

Digamos que queremos mudar a forma como calculamos o total no carrinho. Talvez agora precisemos contabilizar o imposto sobre vendas. Podemos encapsular essa lógica dentro da classe Cart:

// cart.js
export class Cart {
    constructor(taxRate) {
        this.items = [];
        this.taxRate = taxRate;
    }

    addItem(item) {
        this.items.push(item);
    }

    getTotal() {
        const total = this.items.reduce((sum, item) => sum   item.price, 0);
        return total   total * this.taxRate;
    }
}

// Now, the rest of the system does not need to know about tax calculations.

Outras partes do sistema (como order.js) não são afetadas por alterações na forma como o total é calculado. Isso torna seu sistema mais flexível e mais fácil de manter.


? Separação de preocupações: mantenha as responsabilidades claras

Um problema comum em grandes sistemas é que diferentes partes do sistema ficam emaranhadas.

Quando um módulo começa a assumir muitas responsabilidades, fica mais difícil alterá-lo ou reutilizá-lo em diferentes contextos.

O princípio da separação de interesses garante que cada módulo tenha uma responsabilidade específica.

Exemplo: tratamento do pagamento separadamente

No exemplo do carrinho de compras, o processamento do pagamento deve ser feito em um módulo separado:

// payment.js
export class Payment {
    static process(cart) {
        const total = cart.getTotal();
        console.log(`Processing payment of $${total}`);
        // Payment logic goes here
    }
}

// order.js
import { Cart } from './cart.js';
import { Payment } from './payment.js';

const cart = new Cart(0.07); // 7% tax rate
cart.addItem(new Item('Laptop', 1000));
cart.addItem(new Item('Mouse', 25));

Payment.process(cart);

Agora, a lógica de pagamento está separada do gerenciamento do carrinho. Isso facilita a modificação posterior do processo de pagamento (por exemplo, integração com um provedor de pagamento diferente) sem afetar o restante do sistema.


? Testando Módulos Independentemente

Um dos maiores benefícios da modularidade é que você pode testar cada módulo de forma independente.

No exemplo acima, você poderia escrever testes de unidade para a classe Carrinho sem precisar se preocupar com como os pagamentos são processados.

Exemplo: teste unitário do carrinho

// cart.test.js
import { Cart } from './cart.js';
import { Item } from './item.js';

test('calculates total with tax', () => {
    const cart = new Cart(0.05); // 5% tax
    cart.addItem(new Item('Book', 20));

    expect(cart.getTotal()).toBe(21);
});

Com uma separação clara de preocupações, cada módulo pode ser testado isoladamente, tornando a depuração mais fácil e o desenvolvimento mais rápido.


? Lidando com dependências: evite acoplamentos rígidos

Quando os módulos dependem muito uns dos outros, as alterações em uma parte do sistema podem ter consequências inesperadas em outros lugares.

Para minimizar isso, procure um acoplamento fraco entre os módulos.

Isso permite que cada módulo evolua de forma independente.

Exemplo: injeção de dependências

Em vez de codificar dependências dentro de um módulo, passe-as como argumentos:

// cart.js
export class Cart {
    constructor(taxRateCalculator) {
        this.items = [];
        this.taxRateCalculator = taxRateCalculator;
    }

    addItem(item) {
        this.items.push(item);
    }

    getTotal() {
        const total = this.items.reduce((sum, item) => sum   item.price, 0);
        return total   this.taxRateCalculator(total);
    }
}

Essa abordagem torna a classe Carrinho mais flexível e mais fácil de testar com diferentes cálculos de impostos.


Conclusão: mantenha os sistemas modulares, flexíveis e fáceis de alterar

Boa codificação! ?

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/alisamir/understanding-clean-code-systems-53da?1 Se houver alguma violação, entre em contato com [email protected] para excluí-la
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3