Arquitetura & escala
Como pensar um sistema web antes de sair codando: as camadas, os padrões de arquitetura, um plano de desenvolvimento e o caminho pra escalar quando o projeto crescer.
As camadas de um sistema web
Todo sistema web é o mesmo caminho de ida e volta. Entender esse fluxo é o que te diz onde cada problema (e cada solução) vive.
NAVEGADOR SERVIDOR WEB SUA APLICAÇÃO BANCO
(cliente) (Apache/Nginx) (PHP) (MariaDB)
| | | |
| --- requisição ---> | --- repassa ---> | --- query ---> |
| GET /post?id=5 | o .php | SELECT ... |
| | | <-- dados ---- |
| <---- HTML -------- | <--- resposta --- | (monta o HTML) |
| (a página) | | |
| Camada | Responsabilidade | No php.ref |
|---|---|---|
| Cliente | renderizar HTML/CSS/JS, enviar requisições | o navegador abrindo as páginas |
| Servidor web | receber HTTP, servir estáticos, repassar .php | Apache (XAMPP) / LiteSpeed (hospedagem) |
| Aplicação | regras de negócio, decidir o que fazer | pacientes.php, index.php do blog |
| Dados | guardar e devolver informação | banco dumo2258_php (tabelas) |
Padrões de arquitetura
Do mais simples ao mais complexo. A escolha não é "qual é o melhor", e sim "qual o mais simples que resolve o meu problema hoje".
| Padrão | Quando usar | Custo |
|---|---|---|
| Páginas soltas (scripts .php) | aprender, protótipo, site de 2-3 telas | vira bagunça quando cresce |
| Monolito MVC | a escolha padrão pra 95% dos projetos | baixo; organizado e fácil de manter |
| API + frontend (backend separado) | app mobile, SPA (React/Vue), vários clientes | médio; dois projetos pra manter |
| Microsserviços | time grande, partes que escalam diferente | alto; só com problema real de escala |
MVC e organização de pastas
MVC separa o código em três papéis, pra cada mudança mexer em um lugar só:
| Camada | Faz o quê | Exemplo |
|---|---|---|
| Model | fala com o banco, representa os dados | classe Post com buscarTodos() |
| View | só o HTML de saída, nada de lógica pesada | o <table> que lista os posts |
| Controller | recebe a requisição, chama o Model, escolhe a View | "listar posts" → busca → manda pra view |
Na prática, isso vira uma estrutura de pastas onde só uma pasta fica exposta na web:
projeto/
├── public/ <- ÚNICA pasta no web root
│ ├── index.php <- "front controller": toda requisição entra aqui
│ └── assets/ <- css, js, imagens
├── src/
│ ├── Controllers/ <- a lógica (PostController.php)
│ ├── Models/ <- acesso ao banco (Post.php)
│ └── Views/ <- os templates HTML
├── config/ <- FORA do public! conexao, .env, segredos
└── vendor/ <- bibliotecas (Composer)
public/ deve ficar acessível pela web. config/ (com a senha do banco) e src/ ficam fora do web root — assim ninguém abre seusite.com/config/conexao.php e lê suas credenciais.
O front controller é a ideia de ter uma porta de entrada só (public/index.php), que decide o que fazer pela rota:
<?php
// Toda requisição cai aqui; a "rota" decide o destino.
$rota = $_GET["rota"] ?? "home";
match ($rota) {
"home" => require "../src/Controllers/HomeController.php",
"post" => require "../src/Controllers/PostController.php",
default => http_response_code(404),
};
Como planejar antes de codar
A ordem importa: pular o planejamento é o que gera o retrabalho mais caro (descobrir no meio que a tabela está errada). O caminho prático:
| # | Passo | Pergunta que responde |
|---|---|---|
| 1 | Requisitos | "o que o sistema precisa fazer?" (em frases curtas) |
| 2 | Modelar os dados | "quais entidades existem e como se relacionam?" |
| 3 | Mapear rotas/telas | "quais URLs/páginas o usuário acessa?" |
| 4 | MVP | "qual o mínimo que já entrega valor?" |
| 5 | Iterar | "o que adicionar agora que o básico funciona?" |
Aplicando ao mini-blog que construímos:
1. REQUISITOS: listar posts | ler um post | publicar post
2. DADOS: entidade "post" = id, titulo, conteudo, criado_em
3. ROTAS: / -> lista
/?post=5 -> um post
POST / -> publica
4. MVP: os 3 itens acima, sem login, sem comentários
5. ITERAR: depois: excluir, editar, busca, categorias...
Escalabilidade
Escalar = aguentar mais carga. Há dois caminhos, e a ordem certa de atacar os gargalos:
| Tipo | O que é | Limite |
|---|---|---|
| Vertical | servidor maior (mais CPU/RAM) | simples, mas tem teto e custa caro |
| Horizontal | vários servidores dividindo a carga | quase ilimitado, mas exige app stateless |
Onde os gargalos aparecem, na ordem mais comum:
| Gargalo | Sintoma | Solução prática |
|---|---|---|
| Banco | query lenta com muitos registros | índice na coluna do WHERE/ORDER BY |
| Repetição | mesma query/cálculo toda hora | cache (página, resultado, OPcache) |
| Estáticos | imagens/css pesando no servidor | CDN servindo os arquivos |
| Tarefa pesada | envio de e-mail/relatório travando o request | fila (job assíncrono em background) |
O gargalo nº 1 quase sempre é o banco. A correção mais barata é um índice:
-- Sem índice, ORDER BY criado_em varre a tabela inteira.
-- Com índice, o banco "pula" direto pro lugar certo.
CREATE INDEX idx_posts_criado ON posts (criado_em);
-- Pra ver SE uma query usa índice, rode na frente dela:
EXPLAIN SELECT * FROM posts ORDER BY criado_em DESC;
Quando NÃO complicar
Mais projetos morrem de complexidade desnecessária do que de simplicidade. Cheiros de over-engineering:
| Cheiro | Realidade |
|---|---|
| "Vamos usar microsserviços" (com 1 dev e 100 usuários) | monolito resolve; microsserviço vira 5 problemas |
| "Preciso de cache/Redis" (sem ter medido lentidão) | otimização prematura; meça antes |
| "Abstração pra tudo" (camadas que ninguém usa) | código que ninguém entende; YAGNI |
| "Vou suportar 1 milhão de usuários" (tem 10) | resolva o problema de hoje, não o imaginário |