Alguns princípios foram criados para ajudar desenvolvedores a criar sistemas que sejam fáceis de entender, manter e evoluir ao longo do tempo.

Princípios

  1. Single Responsibility Principle ou Princípio da Responsabilidade Única diz que uma classe deve ter apenas uma única responsabilidade e assim, um único motivo para mudar.
  2. Open-Closed Principle ou Princípio do Aberto-Fechado diz que uma classe deve estar aberta para novos cenários, mas fechada para modificação.
  3. Liskov Substitution Principle ou Princípio da Substituição de Liskov diz que os objetos de uma classe derivada devem ser substituíveis por objetos de sua classe base sem alterar o comportamento do software.
  4. Interface Segregation Principle ou Princípio da Segregação de Interface diz que interfaces devem ser separadas para que classes possam depender apenas dos métodos que utilizam.
  5. Dependency Inversion Principle ou Princípio da Inversão de Dependência diz que módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.

Ao seguir esses princípios, conseguimos criar sistemas mais flexíveis, robustos e fáceis de manter, alterar e evoluir ao longo do tempo.

Vamos mergulhar um pouco mais fundo.

Single Responsibility Principle ou Princípio da Responsabilidade Única

Ter uma responsabilidade única significa que uma classe deve ter apenas um motivo para mudar. Se uma classe tiver mais de uma responsabilidade, mudanças em uma responsabilidade podem afetar outras responsabilidades, o que pode levar a um código mais complexo e difícil de manter.

Darei um exemplo mais claro sobre o que podem ser consideradas responsabilidades diferentes.

Suponha que tenhamos uma classe chamada User que é responsável tanto pela autenticação do usuário quanto pelo envio de notificações por e-mail.digamos que você tenha uma classe chamada AuthStore, que tenha abstrações de persistência e implementações de estado.

abstract class User {
  abstract login(email: string, password: string): void
  abstract sendCode(email: string, code: string): void
}

Ela possui responsabilidades diferentes e não segue o princípo SRP. Podemos dividir as responsabilidades em duas classes diferentes.

abstract class Auth {
  abstract login(email: string, password: string): void
}

abstract class Email {
  abstract send(email: string, message: string): void
}

Assim, caso haja uma mudança em uma das responsabilidades, a outra não será afetada, o código estará mais organizado, fácil de entender, testar e manter. O que facilita sua reutilização, pois as classes que têm apenas uma responsabilidade podem ser usadas em diferentes partes.

Open-Closed Principle ou Princípio do Aberto-Fechado

Uma classe deve permitir ser estendida para atender a novos requisitos, sem necessidade de alteração, ou seja, deve permitir adicionar novas funcionalidades usando herança, sem afetar o comportamento existente. Por exemplo, temos uma classe abstrata contendo alguns métodos básicos para comunicação com alguma fonte de dados.

export interface FindOne<I, K extends keyof I, O = I> {
  findOne(key: I[K]): Promise<O>;
}