A maioria dos cursos de arquitetura Angular ensina teoria. Este não.
Aqui você aprende a detectar problemas reais, tomar decisões situadas e construir sistemas que perduram quando a equipe cresce, o produto muda e o tempo passa.
Vinte módulos. Orientado para a prática. Sem preenchimento.
INDEX — Arquitetura angular prática para a vida real
01 — Problemas arquitetônicos básicos
- Lógica de negócios em componentes
- Serviços de Deus
- Status duplicado ou disperso
- Acoplamento entre recursos
- Responsabilidades mistas
- Pastas que parecem organizadas, mas não escalonáveis
- Abstrações prematuras
- Excesso de engenharia desnecessária
- Arquitetura projetada para hoje, mas não para o crescimento
- Código difícil de excluir, mover ou refatorar
02 — Estrutura real do projeto
- Baseado em recursos versus baseado em camadas
- Quando usar cada abordagem
- Como detectar uma estrutura que não escala
- Como dividir por domínios ou contextos limitados
- Como organizar pastas para equipes reais
- Convenções de nomenclatura úteis
- O que colocar e o que NÃO colocar em
shared - Como verificar se sua estrutura atual suporta ×10
03 — Arquitetura de componentes
- Componentes muito grandes
- Componentes com muitas responsabilidades
- Componentes inteligentes versus burros
- Container/apresentação em Angular moderno
- Composição dos componentes
- Quando reutilizar e quando NÃO
- Como projetar APIs de componentes limpos
- Entradas/Saídas vs sinais vs serviços
- Problemas típicos em modelos
- Como detectar componentes que são difíceis de manter
04 — Estado imobiliário em Angular
- Que tipos de estado existem
- Como detectar o uso indevido de estado
- Estado local versus compartilhado versus global versus estado do servidor
- Sinais vs RxJS
- Colocação estadual
- Quando usar o estado de serviço
- Quando usar armazenamentos de sinal
- Quando usar NgRx
- Como detectar a supercentralização
- Como detectar o caos distribuído
- Erros típicos em efeitos colaterais
- Normalização do estado
- Lista de verificação de status
05 — Comunicação e fluxo de dados
- Dados inativos/eventos ativados
- Comunicação correta entre componentes
- Comunicação incorreta entre componentes
- Comunicação entre recursos
- Sinais de acoplamento oculto
- Usando serviços para se comunicar
- Usando sinais para se comunicar
- Quando um ônibus de evento é uma má ideia
- Como verificar endereços de dependência
- Como detectar fluxo de dados difícil de acompanhar
06 — Camada de dados e acesso à API
- Serviços vs repositórios
- DTOs versus modelos
- Transformações e mapeamento
- Onde colocar adaptadores
- Erros típicos ao consumir APIs
- Como dissociar o front-end do back-end
- Tentar novamente, armazenamento em cache, paginação
- Rolagem infinita
- REST vs GraphQL da arquitetura
- Como verificar se sua camada de dados está limpa ou mista
07 — Arquitetura de roteamento
- Projete rotas com intenção
- UX + SEO em rotas
- Rotas preguiçosas
- Guardas
- Resolver
- URL como fonte de status
- Links diretos
- Rotas acopladas
- Rotas mal pensadas
- Lista de verificação para revisar a navegação e escalabilidade
08 — Renderização e estratégia global
- SPA, SSR, SSG, ISR
- Como escolher de acordo com o contexto
- SEO vs complexidade
- Desempenho versus custo
- Arquitetura SSR angular
- Hidratação e impacto arquitetônico
- Quando NÃO usar SSR
- Como verificar se um aplicativo precisa de uma estratégia de renderização diferente
09 — Arquitetura de desempenho
- Detecção de alterações, OnPush, sinais e desempenho
- Carregamento lento real
- Divisão de código e estratégia de pacote
- Cache
- Rolagem virtual e memorização
- Orçamentos de desempenho
- Como detectar gargalos arquitetônicos
- O que verificar antes de “otimizar”
- Como distinguir problema de código versus problema de arquitetura
10 — Arquitetura de teste
- O que testar e o que não
- Unidade vs integração vs e2e
- Testabilidade por design
- Como detectar código difícil de testar
- Zombando com significado
- Fragilidade em testes e overtesting
- Frontend-backend de teste de contrato
- Checklist para verificar se uma arquitetura favorece ou quebra os testes
11 — Nx e monorepo real
- Quando vale a pena e quando não vale
- Apps vs libs, limites, gráfico de dependência
- Bibliotecas compartilhadas bem e mal feitas
- Afetado, cache, propriedade de código
- Como escalar para várias equipes
- Antipadrões Monorepo
- Lista de verificação de revisão
12 — Microfrontends e federação de módulos
- Quando sim e quando não
- Que problema real eles resolvem?
- Custos ocultos
- Host vs remotos, versionamento, comunicação entre MFEs
- Implantação independente e complexidade organizacional
- Checklist para decidir se vale a pena
13 — Sistemas de design úteis
- Que problema eles resolvem e quando um problema sério não é necessário?
- Bibliotecas de componentes, tokens, temas, variantes
- Consistência vs flexibilidade
- Livro de histórias, sincronização design-desenvolvimento
- Erros típicos
- Como verificar se o seu sistema de IU está aumentando ou travando
14 — Segurança de front-end
- XSS, CSRF, higienização
- Arquitetura de autenticação: JWT, tokens de atualização
- Guardas e acesso baseado em função
- Problemas de segurança em SSR
- Lista de verificação prática de revisão
15 — Observabilidade e manutenção
- Registro, rastreamento de erros, Sentry, métricas
- Rastreamento conceitual, sinalizadores de recursos, testes A/B
- Como detectar pontos cegos
- Como verificar se um aplicativo está funcionando em produção
16 — DevEx e pensamento de plataforma
- Experiência do desenvolvedor e ferramentas
- CI/CD, geradores, esquemas, automação
- Como detectar atrito desnecessário
- Como projetar arquitetura para equipes e não apenas código
17 — Compensações e tomada de decisão
- Como justificar decisões
- Custo x benefício, complexidade x escalabilidade, velocidade x facilidade de manutenção
- Construir vs comprar
- Como escrever ADRs
- Como defender uma decisão em uma entrevista ou em um emprego real
18 — Antipadrões de arquiteto angular
- Excesso de engenharia, camadas inúteis, abstrações prematuras
sharedestado global desnecessário e mal projetado- Dependências cruzadas, acoplamento silencioso
- Modularização ruim, ignore métricas reais
- lista de verificação de bandeiras vermelhas
19 — Auditoria prática de aplicativos Angular
- Como revisar um aplicativo existente
- O que olhar primeiro
- Que sinais indicam dívida grave
- Como priorizar problemas
- O que consertar primeiro e o que não mexer ainda
- Como fazer uma revisão arquitetônica útil
20 — Casos reais e treinamento
- Auditoria de comércio eletrônico
- Auditoria do painel SaaS
- Auditoria de backoffice empresarial
- Auditoria de aplicativos públicos com SEO
- Design de aplicativo do zero
- Redesenho caótico do aplicativo
- Perguntas da entrevista
- Exercícios de detecção, decisão e melhoria
Módulo 0 — Base do Sistema
O ponto 0 não é um módulo de conteúdo. É a forma de ver que você usará ao longo do roteiro.
Antes de falar sobre problemas específicos do Angular, você precisa responder a uma pergunta:
Como você olha para um aplicativo que você não conhece e decide se ele é bom ou ruim?
Existem quatro habilidades básicas para isso.
1. Analise um aplicativo sem tocar no código
A primeira leitura de um aplicativo não está no editor. Está na estrutura. Antes de abrir um único arquivo, você pode extrair informações:
- Como são chamadas as pastas? Os nomes dizem o que fazem?
- Existe alguma pasta
sharedque pesa mais que todo o resto? - Quantos níveis de aninhamento possui a estrutura?
- Os módulos ou funcionalidades possuem nomes de domínio ou nomes técnicos?
- Onde estão os serviços? Solto ou dentro dos recursos?
Isso já diz muito se quem fez o app pensou em termos de negócios ou em termos de camadas técnicas.
2. Revise a arquitetura de forma prática
Revisar não é ler o código de cima para baixo. É fazer perguntas com critérios:
- Onde mora a lógica de negócios?
- Quem sabe o que há em cada camada?
- Quantos sites você precisa alterar para adicionar um novo recurso?
- Existem dependências indo na direção errada?
Um arquiteto sênior não começa com o componente mais complexo. Comece pelos pontos de maior risco: serviços compartilhados, estado global e camada de acesso a dados.
3. Detecte problemas antes de programar
A maior parte dos danos arquitetônicos ocorre em decisões iniciais que parecem irrelevantes:
- "Estou colocando isso em um serviço compartilhado por enquanto"
- "O componente pai lida com este estado, então nós o movemos"
- "Usamos NgRx para tudo, então é consistente"
Estas decisões têm consequências reais meses depois. O critério arquitetônico é saber o que cada decisão está comprando e em que dívida está contraindo.
4. Converta a teoria em uma lista de verificação real
Cada conceito que veremos neste roteiro – componentes inteligentes/burros, posicionamento de estado, serviços divinos, etc. – deve terminar em uma pergunta que você pode fazer a si mesmo enquanto revisa o código real:
- Este componente sabe de onde vêm os dados?
- Este serviço tem mais de um motivo para mudar?
- Este estado existe em dois lugares diferentes?
Se você não consegue transformar um conceito em uma pergunta de revisão, você ainda não o internalizou.
Módulo 1 — Como analisar um aplicativo Angular sem mexer no código
A primeira revisão arquitetônica ocorre antes de abrir o editor. Apenas a partir da estrutura de pastas e dos nomes dos arquivos você já pode extrair sinais claros de qualidade. Isso é o que um arquiteto sênior faria nos primeiros 10 minutos com um aplicativo desconhecido.
Por que isso importa?
- Se você demorar muito para detectar problemas arquitetônicos, o custo de corrigi-los cresce exponencialmente.
- Uma estrutura mal desenhada desde o primeiro dia vira dívida técnica que bloqueia a equipe meses depois.
- Desenvolver um julgamento visual rápido permite que você tome decisões melhores antes de escrever uma única linha de código.
Passo 1 — Leia a estrutura de pastas como um mapa
A estrutura de pastas é a primeira decisão arquitetônica visível. Conta como a equipe organizou seu mundo mental: eles pensam em termos de tecnologia ou em termos de negócios?
O que é um recurso?
Um recurso é uma funcionalidade comercial completa. Não é um tipo de arquivo. Não é uma camada técnica.
Pense em um aplicativo de comércio eletrônico. Os recursos são:
- O catálogo de produtos
- O carrinho de compras
- O processo de checkout
- O perfil do usuário
- Gerenciamento de pedidos
Cada um deles é um negócio que faz sentido por si só. Um usuário entra, navega no catálogo, adiciona ao carrinho, finaliza a compra. Essas são características.
Modelo 1 — Organização por camadas técnicas (problemático em escala)
Isso é o que quase todo mundo faz quando começa, porque parece legal:
src/app/
components/
product-card.component.ts
product-list.component.ts
cart-item.component.ts
checkout-form.component.ts
user-profile.component.ts
services/
product.service.ts
cart.service.ts
checkout.service.ts
user.service.ts
models/
product.model.ts
cart.model.ts
user.model.ts
O verdadeiro problema: você precisa modificar o fluxo de checkout. Para entender o que está envolvido, você navega entre três pastas diferentes: procura o componente em components/, o serviço em services/, o modelo em models/. Se houver um canal de checkout específico, ele estará em pipes/ misturado com tubos de outros recursos.
Para alterar um único recurso, você navega por todo o aplicativo. Isso é acoplamento por estrutura. Quando a equipe cresce, duas pessoas trabalhando em recursos diferentes tocam constantemente nas mesmas pastas → conflitos no git, dificuldade de saber quem é dono do quê.
Modelo 2 — Organização por recursos (quais escalas)
src/app/
features/
catalog/
components/
product-card.component.ts
product-list.component.ts
services/
product.service.ts
models/
product.model.ts
catalog.routes.ts
cart/
components/
cart-item.component.ts
cart-summary.component.ts
services/
cart.service.ts
cart.routes.ts
checkout/
components/
checkout-form.component.ts
order-confirmation.component.ts
services/
checkout.service.ts
checkout.routes.ts
shared/
core/
Por que isso funciona: quando você toca em finalizar compra, tudo na finalização da compra fica junto. Um novo desenvolvedor sabe exatamente onde procurar. Uma pessoa pode possuir um recurso inteiro. Você pode excluir um recurso inteiro excluindo apenas sua pasta. Os conflitos do Git entre diferentes recursos desaparecem quase completamente.
A regra básica: se você excluir um recurso, poderá excluir a pasta inteira sem tocar em mais nada? Se a resposta for sim, o recurso está bem isolado. Se você tiver que procurar peças em todo o aplicativo, não é.
Passo 2 — Leia os nomes
Os nomes são documentação. Um nome ruim esconde a intenção e adiciona carga cognitiva a cada pessoa que lê o código.
shared/ — o que deve conter e o que não deve
shared/ é para coisas que vários recursos usam e que NÃO possuem sua própria lógica de negócios.
Correto em shared/:
shared/
components/
button/
modal/
spinner/
avatar/
pipes/
date-format.pipe.ts
truncate.pipe.ts
directives/
click-outside.directive.ts
validators/
email-validator.ts
Eles são peças de UI reutilizáveis ou utilitários puros. Eles não sabem nada sobre o negócio. Um ButtonComponent não sabe se é um botão de checkout ou de perfil de usuário. Ele só sabe ser um botão.
Incorreto em shared/:
shared/
services/
cart.service.ts ← lógica de negocio aquí
user-auth.service.ts ← pertenece a auth/core
product-filter.service.ts ← pertenece a catalog
report-generator.service.ts ← pertenece a reporting
Quando você vê serviços com lógica de negócios dentro de shared/, significa que alguém não sabia onde colocá-los e colocá-los lá. Com o tempo, shared/ se torna o elemento principal do aplicativo.
core/ — o que é e o que não é
core/ é para infraestrutura singleton que precisa do aplicativo inteiro, uma vez.
Correto em core/:
core/
services/
auth.service.ts
logger.service.ts
error-handler.service.ts
interceptors/
auth.interceptor.ts
error.interceptor.ts
guards/
auth.guard.ts
models/
user-session.model.ts
Incorreto em core/:
core/
components/
dashboard.component.ts ← eso es una feature
home.component.ts ← igual
services/
product.service.ts ← pertenece a catalog
report-generator.service.ts ← pertenece a reporting
São coisas que são instanciadas uma vez e afetam todo o aplicativo. O interceptador de autenticação intercepta todas as solicitações HTTP para todo o aplicativo, e é por isso que ele reside em core/.
Nomes vagos – sinais de alerta
Um nome vago é uma decisão adiada. Quando alguém cria data.service.ts, ainda não decidiu de quais dados esse serviço está falando.
| o que você vê | O que isso pode significar |
|---|---|
shared/ muito grande |
Tudo o que não cabia em nenhum outro lugar. Torna-se uma mistura. |
common/ |
O mesmo que shared/, mas com nome pior. Sem critérios do que entra. |
utils/ com serviços |
Lógica de negócios disfarçada de utilidade. Bandeira vermelha séria. |
helpers/ |
O mesmo que utils/. O nome não diz nada sobre responsabilidade. |
components/ na raiz |
Nenhuma organização por domínio. Todos os componentes juntos. |
core/ com 40 arquivos |
Núcleo mal definido. shared/ foi usado como o segundo. |
app.service.ts |
Um serviço divino esperando para crescer. Sinal de alarme máximo. |
data.service.ts |
Dados sobre o quê? Responsabilidade indefinida do nome. |
helper.service.ts |
Acaba sendo um serviço com métodos não relacionados. |
main.component.ts |
O que é "principal"? Nome genérico que esconde responsabilidades reais. |
Regra de nomes: Se o nome do arquivo não informar exatamente o que faz, o arquivo provavelmente faz muito ou está mal localizado.
Exemplos concretos de nomes vagos e o que escondem:
utils/format.tscom 800 linhas: mix de formatação de data + validação de formulário + transformação de API.helper.service.ts: acaba sendo um serviço divino com métodos não relacionados.app.service.ts: um serviço denominado aplicativo inteiro que tem responsabilidades por todo o aplicativo.
Passo 3 — Conte e meça sem abrir arquivos
Antes de ler o código, você pode fazer estas observações diretamente da estrutura:
Tamanho do componente como sinal
| Sinal | O que isso indica? |
|---|---|
| +300-400 linhas em um componente | Você quase sempre está fazendo demais. Não é uma regra absoluta, mas vale a pena investigar. |
| +10 entradas e saídas | API muito complexa. Candidato a ser dividido em vários componentes. |
| Chamadas HTTP diretas no componente | Misture apresentação com acesso a dados. Camada de serviço ausente. |
| 1-2 componentes por recurso | Eles provavelmente estão fazendo muito. Falta de divisão interna. |
| +20 fornecedores globais | Muito estado e lógica centralizada. Nem tudo precisa ser global. |
Serviços globais — o perigo de providedIn: 'root'
Um serviço global significa que qualquer componente de qualquer recurso pode injetá-lo e usá-lo. Isso cria dependências invisíveis entre recursos que deveriam ser independentes.
// Servicio que DEBERÍA ser local a la feature de catalog:
@Injectable({ providedIn: 'root' }) // ← señal de problema
export class ProductFilterService { ... }
// Ahora cualquier componente de cualquier feature puede usarlo.
// Si catalog cambia su lógica de filtrado, puede romper
// algo en una feature aparentemente no relacionada.
Etapa 4 — app.module.ts ou app.config.ts: o que procurar
Em aplicativos com módulos (Angular < 17 ou legado)
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
RouterModule,
AuthModule, // ← bien, infraestructura singleton
ProductModule, // ← señal de problema
CartModule, // ← señal de problema
CheckoutModule, // ← señal de problema
UserModule, // ← señal de problema
DashboardModule, // ← señal de problema
// Si hay 15+ módulos de features aquí,
// el lazy loading no está funcionando.
],
providers: [
ProductService, // ← si hay 20+ providers aquí,
CartService, // hay demasiada centralización
UserService,
AuthService,
]
})
Os módulos de recursos devem ser carregados lentamente (sob demanda), e não importados diretamente para o módulo raiz. Se estiverem todos aqui, todos serão carregados na inicialização, mesmo que o usuário nunca precise deles.
Em aplicativos independentes (Angular 17+)
// app.config.ts
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes, withLazyLoading()), // ← correcto
provideHttpClient(withInterceptors([authInterceptor])),
provideAnimations(),
ProductService, // ← esto NO debería estar aquí
CartService, // ← pertenece a la feature de cart
]
}
Regra de configuração global: A configuração global deve ter apenas infraestrutura que afete todo o aplicativo: roteador com carregamento lento,
HttpClientcom interceptores globais, animações, serviços singleton de infraestrutura (auth, logger, manipulador de erros). Se você vir feature services na configuração global, alguém está registrando coisas globalmente por conveniência, não por necessidade.
Lista de verificação completa — Primeira leitura de um aplicativo Angular
Estrutura
- A estrutura está organizada por funcionalidades (domínio de negócio) ou por camadas técnicas?
- Posso excluir um recurso inteiro excluindo apenas sua pasta sem tocar em mais nada?
- Os recursos possuem nomes de domínio comercial (
checkout,catalog) ou nomes técnicos (list,form,detail)? - Existem pastas com nomes vagos:
utils,helpers,common,misc,data?
shared/ e core/
- []
shared/contém apenas componentes e utilitários de UI sem lógica de negócios? - []
core/contém apenas infraestrutura singleton (interceptores, guardas, serviço de autenticação)? - Existem serviços com lógica de negócios em
shared/? - []
core/possui componentes de recursos ou serviços de domínio?
Serviços e provedores
- Os serviços empresariais estão dentro das suas características ou estão soltos globalmente?
- Existem mais de 20 fornecedores globais?
- [] O módulo raiz ou
app.config.tsimporta módulos de recursos diretamente (sem preguiça)? - [] Existem serviços com
providedIn: 'root'que deveriam ser locais para um recurso?
Nomes
- Os nomes dos arquivos dizem exatamente o que fazem?
- [] Existem arquivos cujo nome pode ser aplicado a qualquer parte do aplicativo?
- Existe um arquivo chamado
app.service.ts,data.service.tsouhelper.service.ts? - []
shared/pesa mais do que qualquer recurso individual?
Exercício
Pesquise qualquer projeto Angular público no GitHub - pode ser seu ou de código aberto. Sem abrir nenhum arquivo, apenas olhando a estrutura e os nomes das pastas:
- Qual modelo de organização você usa: recursos ou camadas técnicas?
- Que nomes lhe suscitam dúvidas ou suspeitas?
- Onde você suspeita que esteja a lógica de negócios?
- Qual pasta você acha que tem a maior combinação de responsabilidades?
- Você poderia excluir um recurso sem tocar em mais nada?
Compartilhe o que você observa na sessão e nós revisamos juntos como um arquiteto sênior faria.
Prompt: analise seu projeto com os 4 pontos
Copie este prompt e utilize-o com qualquer IA (ChatGPT, Claude, Copilot) passando para ele a árvore de pastas do seu projeto:
Analise a arquitetura do projeto aplicando estes 4 pontos do Pilar 1 e gere um relatório.
PONTO 1 — Estrutura de pastas
Analise apps/ e libs/ e responda:
- A organização é por funcionalidades (domínio de negócio) ou por camadas técnicas?
- Você pode excluir um recurso inteiro excluindo apenas sua pasta?
- Os recursos possuem nomes de domínio (
checkout,catalog) ou nomes técnicos (list,form,detail)? - Existem pastas com nomes vagos:
utils,helpers,common,misc,data? - Mostra a árvore real de pastas que você encontrou.
PONTO 2 — Nomes de arquivos e pastas
Pesquise todo o projeto e liste:
- Arquivos com nomes vagos:
data.service.ts,helper.service.ts,app.service.ts,main.component.ts,utilscom serviços dentro. - Serviços com lógica de negócio dentro de
shared/. - Componentes ou serviços de domínio em
core/. shared/pesa mais do que qualquer recurso individual? Contagem de arquivos.
PONTO 3 — Serviços globais
Pesquise todo o projeto:
- Todos os serviços com
providedIn: 'root'— lista quais são e se devem ser locais para um recurso. - Conta quantos provedores globais existem no total.
- Identifica serviços comerciais registrados globalmente quando eles deveriam estar em seu recurso.
- Pesquise serviços em
libs/services/que pertençam claramente a um domínio específico.
PONTO 4 — Configuração global (app.config.ts ou app.module.ts)
Encontre o arquivo de configuração raiz de cada aplicativo e analise:
- O que está registrado globalmente e não deveria estar?
- Os módulos de recursos são carregados com carregamento lento ou são importados diretamente?
- Existem serviços empresariais na configuração global?
- Quantos provedores estão registrados globalmente no total?
FORMATO DE RELATÓRIO
Para cada ponto use esta estrutura exata:
✅ O que é bom
(lista concreta com exemplos de código reais)
⚠️ Sinais para verificar
(lista concreta com caminho do arquivo e porque é um sinal)
❌ Eliminar problemas
(lista concreta com caminho do arquivo, problema e impacto real)
No final inclui:
Sumário executivo
Uma tabela com os 4 pontos, um emoji de status (✅ ⚠️ ❌) e uma linha de conclusão por ponto.
Próximas etapas priorizadas
Lista de no máximo 5 ações específicas ordenadas por impacto, com o caminho exato do arquivo ou pasta a ser tocado.
Seja direto. Não explique o que é uma característica ou teoria. Basta analisar este projeto específico e fornecer resultados reais.
