Melhores Práticas de Angular para Seniors
Guia técnico para manter código limpo, escalável e sustentável em grandes bases de Angular
1) Arquitetura e Organização do Projeto
- Organizo o projeto por domínio/feature utilizando módulos de funcionalidades com lazy loading (carregamento sob demanda) para reduzir o bundle inicial.
- Separação clara de CoreModule, SharedModule e Feature Modules:
- CoreModule: serviços singleton, config de autenticação, provedores globais.
- SharedModule: componentes, diretivas e pipes reutilizáveis.
- Feature Modules: encapsulam domínio, roteamento, e dependências específicas.
- Uso de barrel files (index.ts) para reexportar entidades relevantes, simplificando imports.
- Nomenclatura coesa e organização de pastas: apps/, apps/feature/, libs/, com roteamento autônomo onde fizer sentido.
- Defino boundaries entre UI, domínio e dados para evitar vazamento de responsabilidades entre camadas.
2) Desempenho e Gerenciamento de Estado
- ChangeDetectionStrategy.OnPush como padrão nos componentes, aliado a dados imutáveis para minimizar re-renderizações.
- Utilizo AsyncPipe para subscrever Observables diretamente no template, reduzindo subscriptions manuais e evitando memory leaks.
- TrackBy em listas com
*ngForpara evitar reconciliação desnecessária de DOM em listas grandes. - Estratégias de pré-carregamento de módulos (PreloadAllModules) quando apropriado, para equilibrar performance inicial e tempo de resposta.
- Gerenciamento de subscribes com padrões de cancelamento (takeUntil) para evitar leaks ao desmontar componentes.
- Evito subscriptions aninhadas; prefiro encadear operadores RxJS (switchMap, map, combineLatest) para manter composição de streams clara.
- Quando trabalhar com listas grandes, avalio uso de técnicas de virtual scrolling (CDK) para manter a performance de renderização.
3) Testes, Qualidade e Manutenção
- Escrevo testes de unidade bem isolados com TestBed, simulando dependências externas com mocks simples (spyObj) e stubs confiáveis.
- Testes de integração focados em interações entre componentes e serviços, mantendo dependências externas sob controle.
- Uso de pipes puras onde possível e verificação de comportamento do
asyncpipe para estados assíncronos. - Valido comportamentos de entrada/saída com tipagem explícita e cenários de falha para aumentar a robustez do código.
- Checklist de qualidade no PR: arquitetura, performance, acessibilidade, testabilidade e compatibilidade com SSR (quando aplicável).
4) Padrões de Código, Revisões e Tooling
- Adoto tipagem forte em toda a base: interfaces, DTOs, tipos e enums ajudam a manter contratos estáveis.
- Componentes e serviços com responsabilidade única; uso de composição sobre herança para maior flexibilidade.
- Pipes personalizados “pure” por padrão para evitar side effects e garantir pureza de renderização.
- Arquitetura de dados clara: entrada (Input), saída (Output) com tipos explícitos; evita passing de objetos mutáveis sem controle.
- Uso consciente do Angular CLI para geração de código, mantendo consistência com schematics e padrões internalizados pela equipe.
- Ferramentas de qualidade de código (linters e formatadores) para manter padronização e legibilidade ao longo do tempo.
- Revisões de código com checklists que abracem design, performance, acessibilidade, testabilidade e documentação.
// Exemplo de componente seguindo OnPush com trackBy
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { Observable } from 'rxjs';
interface Item {
id: number;
name: string;
}
@Component({
selector: 'app-list',
template: `
- {{ item.name }}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListComponent {
@Input() items$: Observable<Item[]>;
trackById(index: number, item: Item) {
return item.id;
}
}