Quando se fala em desenvolvimento de software é comum ouvirmos sobre design patterns, ou padrão de projeto, que nada mais é do que uma solução geral para um problema que ocorre com frequência dentro de um determinado contexto no projeto de software. Assim, um anti-padrão é:
[...] um padrão de projeto de software que pode ser comumente usado, mas é ineficiente e/ou contra-produtivo em prática.
Desenvolver software legível, reutilizável, e refatorável é essencial para ter um código limpo. Desse modo:
Clean Code é um estilo de desenvolvimento que tem por foco a facilidade para escrever, ler e manter o código.
- Organizacionais
- Gerência de projeto
- Análise
- Design
- Desenvolvimento
- Metodológicos
- Barraca de bicicleta: Dedicar grande esforço a questões triviais
- Ex.: Indicadores, previsão do tempo
- Vaca do dinheiro: Um produto legado que às vezes leva à complacência sobre novos produtos
- Ex.: Repetir erros históricos
- Projeto por submissão: O resultado de ter vários contribuintes para o projeto, mas nenhuma visão unificada
- Ex.: Querys
- Agravamento de compromisso: Falhar em revogar uma decisão quando provada errada
- Pensar em grupo: Um estado coletivo onde membros de um grupo começam a (comumente sem saber) pensar semelhantemente e passam a rejeitar pontos de vista diferentes
- Gerência por objetivos: Gestão por números, focando exclusivamente em critério de gerência quantitativo, quando estes não são essenciais ou custam muito para alcançar
- Ex.: Escopo inicial do projeto (Árvore Lógica, Planta Gráfica, Indicadores)
- 'Microgerência': Ineficácia da observação e supervisão excessivas, ou outros excessos do envolvimento da gerência na prática
- Ex.: Envolvimento dos stakeholders com o time, UX
- Risco moral: Isolar alguém das consequências da sua decisão
- Ex.: O time não foi envolvido nas reuniões de definição do projeto
- Gerência cogumelo: Manter funcionários desinformados e mal-informados
- Gerência gaivota: Gerência onde os gerentes só interagem com os empregados quando um problema aparece, ocasião na qual eles "pousam, fazem muito barulho, culpam todos, não resolvem o problema e então voltam a voar"
- Ex.: Aspectos levantados na reunião geral de retrospectiva
- Marcha da morte: Todos sabem que o software será um desastre - exceto o CEO - então a verdade é escondida
- Fumaça e espelhos: Demonstrar funções não implementadas como se já tivessem sido implementadas
- Apatia do espectador: Quando uma decisão de análise é errada, mas quem percebe não faz nada pois afeta um número maior de pessoas
- Gold plating: Continuar a trabalhar em uma tarefa ou projeto passando do ponto em que esforço extra adiciona valor
- Sistema chaminé: Um sistema montado difícil de ser mantido pelos componentes mal-relacionados
- Complexidade acidental: Introdução de complexidade desnecessária em uma solução
- Âncora do barco: Manter uma parte de um sistema que não tem mais uso
- Culto de programação: Usar padrões sem saber o motivo
- Fluxo de lava: Manter código indesejável (redundante ou de baixa qualidade) porque removê-lo é caro ou tem consequências imprevisíveis
- Números mágicos: Incluir números inexplicados em algoritmos
- Ex.: Acesso por índices
- Strings mágicas: Incluir literais no código para comparações inexplicadas
- Don't repeat yourself: Escrever código que contém padrões repetitivos, a serem evitados com o princípio da abstração
- Ex.:
For
dentro deFor
- Ex.:
- Código espaguete: Programas que têm a estrutura pouco compreensível, especialmente por mal uso das estruturas de código
- Ex.: Classe de ordem de serviço
- Programação por copiar/colar: Copiar (e modificar) código existente ao invés de criar soluções genéricas
- Ex.:
O sistema inteiro?
- Ex.:
- Martelo de ouro: Assumir que uma solução favorita é aplicável universalmente
- Fator de improbabilidade: Assumir que é improvável que um erro conhecido ocorra
- Otimização prematura: Preocupar cedo com eficiência, sacrificando um bom desenho, manutenabilidade e, às vezes, até a eficiência
- Reinventar a roda: Falhar em adotar uma solução adequada e existente
- Ex.: Desenvolver uma funcionalidade quando seria possível utilizar uma lib estável
- Reinventar a roda quadrada: Falhar em adotar uma solução existente e no lugar adotar uma customizada que é bem pior
- Variáveis
- Funções
- Objetos e Estruturas de Dados
- Classes
- Tratamento de Erros
- Testes
- Use nomes pronunciáveis e com significado
❌
const mntv003 = await this.mntv003(equipmentCode)
const mntv002 = await this.mntv002(equipmentCode)
✔️
const mntv003 = await this.mntv003(equipmentCode)
const mntv002 = await this.mntv002(equipmentCode)
- Seja consistente na nomenclatura
❌
function getExistingEquipment(): IEquipment
...
const existentEquipment = getExistingEquipment()
✔️
function getExistingEquipment(): IEquipment
...
const existingEquipment = getExistingEquipment()
- Evite mapas mentais
❌
const u = getUser()
const s = getSubscription()
const t = charge(u, s)
✔️
const user = getUser()
const subscription = getSubscription()
const transaction = charge(user, subscription)
- Não adicione contexto desnecessário
❌
type Equipment = {
equipmentCode: string
equipmentDescription: string
equipmentTag: string
}
✔️
type Equipment = {
code: string
description: string
tag: string
}
- Evite muitos argumentos
❌
mountInputUpd(
protheusBranch: string,
serviceOrder: ServiceOrder,
taskCode: string,
input: ESTInputReturn | PTInputReturn,
taskSequence: string
) {
...
}
✔️
async update(userId: string, fields: AreaInput) {
...
}
- Use doc-comments
/**
* Updates a branch for a given user id
*
* @param userId user id
* @param fields fields to update, only `name` is allowed currently
* @returns the updated branch
* @throws {AuthorizationError} if the user is not an admin
*/
- Funções devem fazer uma coisa (funções da classe de ordem de serviço)
- Nomes das funções devem dizer o que fazem
❌
async mntv003(equipment: string) {
...
}
✔️
async totalHoursToRepair(equipment: string) {
...
}
- Funções devem ter apenas um nível de abstração (não faça
for
dentro defor
) - Evite código duplicado
- Evite flags em funções
❌
getTreeQuery(isForeseen: boolean) {
...
}
✔️
getTreeQuery() {
...
}
getForeseenTreeQuery(isForeseen: boolean) {
...
}
- Evite condicionais, no geral
- Configure a visibilidade dos membros
❌
async update(...params) {
...
}
✔️
private async update(...params) {
...
}
- Classes devem ser pequenas
- Ex.: Classe de ordem de serviço
- Alta coesão e baixo acoplamento
- Coesão define o grau de relação entre uma classe e seus membros. Uma classe altamente coesa faz uso máximo de seus membros em todos os métodos.
- Acoplamento define o relacionamento entre classes e entidades. Quanto mais independente ela for, menos acoplada se torna. Classes com baixo acoplamento podem ser refatoradas sem implicar problemas em outras partes do programa que não deveriam ser relacionadas.
- Prefira composição a herança
- Não ignore erros
❌
async removeChecklistBySO(...params) {
...
await repository.delete(query).catch(() => undefined)
}
✔️
async removeChecklistBySO(...params) {
...
await repository.delete(query)
}
- Testes devem ser determinísticos
- Cada teste deve testar uma coisa
- Clean Code TypeScript (https://github.com/labs42io/clean-code-typescript)
- Anti-patterns (https://en.wikipedia.org/wiki/Anti-pattern)