Mentor dos Nerds Home Se o site é estático, por que ele precisa sobreviver ao meu cluster?
Post

Artigo Engenharia de Software

Se o site é estático, por que ele precisa sobreviver ao meu cluster?

Uma página web pronta se separa de uma malha densa de servidores e segue para poucos pontos de distribuição conectados
Uma página web pronta se separa de uma malha densa de servidores e segue para poucos pontos de distribuição conectados

Às vezes, aumentar a disponibilidade não exige acrescentar outra camada de infraestrutura. Exige perguntar por que aquela página dependia de tantas camadas para começar.

TL;DR

Numa migração recente, eu revi sites estáticos que haviam sido publicados no mesmo cluster — um conjunto de servidores operando de forma coordenada — já usado para serviços mais complexos. Não se construiu um cluster para servir uma página institucional: aproveitou-se uma infraestrutura que já existia. O custo dessa conveniência apareceu quando a indisponibilidade causada por um dos servidores atingiu o conjunto e levou junto páginas simples que poderiam ser distribuídas por uma hospedagem estática, como a camada gratuita do Cloudflare Pages. Em um dos casos, havia até renderização no servidor (server-side rendering, ou SSR), em que o servidor prepara o HTML da página durante o acesso. Na versão 0.1.46 instalada e nas três execuções que observei, essa capacidade foi herdada da arquitetura padrão do recurso de criação de sites do Codex, embora a interface não precisasse gerar conteúdo novo a cada visita. Cluster e SSR são capacidades úteis, não certificados automáticos de maturidade. Se o resultado pode ser produzido antes da requisição e distribuído como HTML para estruturar o conteúdo, CSS para apresentá-lo e JavaScript para acrescentar comportamento, retirar o servidor do caminho crítico — o conjunto de componentes que precisa funcionar para responder a cada acesso pode diminuir pontos de falha, trabalho operacional e acoplamento — a força com que os componentes dependem uns dos outros. Isso não torna toda aplicação candidata a hospedagem estática, nem elimina dependências externas. A decisão madura é descobrir o que realmente precisa acontecer durante cada acesso e manter no caminho apenas o que entrega valor naquele momento.

O contexto importa. O cluster não havia sido criado para hospedar uma landing page. Ele já existia, sustentava serviços com necessidades operacionais mais complexas e oferecia um caminho conhecido de publicação, roteamento e monitoramento. Aproveitá-lo também para o site era uma decisão pragmática naquele momento — não um exercício de construir infraestrutura por esporte.

Foi a indisponibilidade que tornou visível o acoplamento. Um problema iniciado em um dos servidores não afetou apenas as cargas que realmente precisavam do cluster: retirou do ar também uma interface de apresentação que poderia continuar disponível de forma independente.

Nessa migração, precisei então responder uma pergunta simples sobre uma arquitetura que havia crescido por conveniência:

Se este site entrega arquivos que já estavam prontos antes de alguém acessá-lo, por que ele precisa sobreviver ao meu cluster?

O site não processava uma compra. Não montava uma página diferente para cada visitante. Não consultava um banco para decidir qual título mostrar. Não carregava uma regra empresarial secreta que precisasse permanecer no servidor.

Era, essencialmente, uma interface de apresentação.

Mesmo assim, para continuar no ar, dependia de uma rede privada saudável, de um conjunto de máquinas coordenadas como uma unidade — o cluster —, de serviços em execução, de roteamento, de versões publicadas corretamente e de uma quantidade razoável de peças operacionais concordando em não ter um dia ruim ao mesmo tempo.

Na origem, havia pragmatismo.

Na prática, uma página simples havia herdado o domínio de falha da infraestrutura inteira: se qualquer parte importante daquela cadeia parasse, o visitante deixaria de receber um arquivo que já poderia estar pronto.

Eu não havia comprado uma bazuca para matar uma mosca. A bazuca já estava ali, funcionando, e pareceu prático aproveitar.

O problema foi deixar a mosca depender do cronograma de manutenção da bazuca.

Um site estático não é um site sem engenharia

A palavra “estático” ainda soa, para algumas pessoas, como sinônimo de antigo, limitado ou amador.

Não é.

Um site estático é aquele cujo conteúdo entregável pode ser construído antes do acesso. O navegador pede um arquivo e recebe aquele arquivo, sem depender de um servidor de aplicação para produzir novamente a página naquele instante. A MDN explica essa diferença entre servir arquivos como estão e executar software para montar conteúdo dinâmico antes da resposta.

Isso não significa que o projeto foi escrito à mão num index.html de 1998.

Pode haver componentes em React — peças reutilizáveis da interface —, processamento de estilos, otimização de imagens, internacionalização — a preparação do produto para diferentes idiomas e convenções locais —, testes, validação de links e uma etapa completa de construção — o build. A diferença é quando esse trabalho acontece.

Em vez de repetir parte dele toda vez que alguém abre a página, o sistema produz antecipadamente um conjunto de HTML, CSS, JavaScript, fontes e imagens. O Vite documenta que seu build de produção gera, por padrão, um pacote adequado para ser servido por hospedagem estática.

Existe engenharia antes da publicação.

Só não existe a obrigação de manter um servidor de aplicação executando para entregar o resultado depois.

SSR é uma capacidade, não uma medalha

Naquele site, a origem do SSR era menos épica e mais cotidiana: algum tempo antes, eu havia resolvido testar o recurso do Codex para criar sites. Fui preguiçoso. Em vez de discutir cada decisão arquitetural, aceitei a estrutura que ele entregou — e ela veio com renderização no servidor (server-side rendering, ou SSR).

Depois eu abri a versão 0.1.46 do pacote OpenAI Sites instalada no meu ambiente — o conjunto local de regras que orientava esse tipo de geração — e a explicação ficou mais precisa. Ela não diz literalmente “use SSR em qualquer site”. Mas, nessa versão, manda iniciar sites novos com o scaffold do OpenAI Sites — uma estrutura inicial de código —, produzir uma saída compatível com Cloudflare Workers e entregar para a hospedagem até um artefato de servidor, isto é, um pacote preparado para executar código no servidor. A própria integração da OpenAI fica responsável pelos recursos reais no Cloudflare e pela ligação da publicação. Essa inspeção é uma evidência local e identificada, não uma especificação pública nem uma afirmação sobre toda versão passada ou futura do recurso.

Isso também não era uma coincidência isolada. Executei três sites com a mesma skill — um pacote reutilizável de instruções, recursos e procedimentos para orientar o agente — e os três receberam essa estratégia. Nesse caso, ela fazia parte do pacote OpenAI Sites citado acima. A repetição observada combina com a regra escrita: a solução nasce preparada para o caso em que talvez precise executar algo no servidor. Para um criador de sites generalista, é uma precaução compreensível. Para uma página simples, significa herdar uma infraestrutura de execução que talvez jamais use de verdade.

Nesse modelo, componentes da aplicação são transformados em HTML num ambiente de servidor. A própria documentação do React descreve as APIs de servidor como recursos usados no topo da aplicação para gerar o HTML inicial.

É o equivalente digital de usar a faca que está na nossa frente para apertar um parafuso. Dependendo da faca e do parafuso, ele pode até girar. O problema termina aparentemente resolvido, mas isso não transforma a faca numa chave de fenda nem torna aquele o método mais adequado.

O gerador ofereceu uma solução capaz de fazer mais e conseguiu publicar o site. Eu é que não parei para perguntar se aquele “mais” fazia parte do requisito. A ferramenta disponível pode resolver; a responsabilidade de verificar se ela também é apropriada continua sendo minha.

SSR pode ser a escolha correta.

Pode ajudar quando o conteúdo realmente varia a cada requisição, quando a resposta depende de sessão, quando existe personalização que não deve ir para o navegador, quando há requisitos específicos de tempo até o primeiro conteúdo ou quando a arquitetura precisa combinar dados dinâmicos e HTML inicial.

Mas naquele caso a função executava para entregar uma interface que poderia ter sido construída antes.

O servidor acordava, preparava a bandeja e entregava um prato que já estava pronto.

Chamamos isso de arquitetura moderna porque “alguém ligou uma função para devolver arquivos” não fica tão bonito na apresentação.

O problema não é SSR.

O problema é tratá-lo como evolução obrigatória. Uma capacidade deixa de demonstrar maturidade quando está presente sem que o requisito exista. Nesse ponto, ela demonstra apenas que conseguimos operar mais uma coisa.

E toda coisa que conseguimos operar também é uma coisa que conseguimos quebrar, atualizar, monitorar, pagar e tentar compreender às duas da manhã.

O caminho da leitura estava carregando dependências que pertenciam à publicação

Essa distinção mudou a forma como eu olhei para o sistema.

Existem dependências necessárias para produzir uma nova versão do site: o repositório, as ferramentas de build, os testes, a validação, o serviço que recebe o artefato — o conjunto de arquivos gerado — e o processo de aprovação.

E existem dependências necessárias para ler a versão já publicada.

As duas listas não precisam ser iguais.

Se o processo de build ficar indisponível, talvez eu não consiga publicar uma versão nova naquele momento. Isso é um problema real. Mas não deveria, por consequência automática, impedir que alguém leia os arquivos da versão que já havia sido publicada.

Quando coloco o site dentro do mesmo caminho operacional de serviços dinâmicos, bancos, redes internas e outras aplicações, eu acoplo a leitura a problemas que não têm relação com ela.

Uma falha num serviço auxiliar derruba a página institucional.

Uma manutenção do cluster retira do ar a documentação.

Um problema no mecanismo usado para empacotar e publicar serviços impede a recuperação de uma interface que, depois do build, era apenas um conjunto de arquivos.

Não ganhei necessariamente resiliência por ter mais componentes.

Ganhei mais componentes capazes de participar da indisponibilidade.

Resiliência também pode ser subtração

Existe uma tendência compreensível em engenharia de responder a risco acrescentando coisas.

Mais uma réplica — outra cópia da aplicação pronta para atender. Mais um servidor. Mais um balanceador — a peça que distribui solicitações entre cópias disponíveis. Mais um sistema de monitoramento — aquele que acompanha sinais e alerta quando algo sai do esperado. Mais um mecanismo de retomada. Mais um painel para observar o painel que observa o serviço.

Algumas vezes, é exatamente disso que o sistema precisa.

Em outras, a pergunta mais valiosa é:

Qual dessas peças pode deixar de ser necessária para esta entrega?

O capítulo sobre simplicidade do livro de Engenharia de Confiabilidade de Sites do Google diferencia a complexidade essencial do problema daquela que introduzimos pela maneira como escolhemos resolvê-lo. Também destaca o valor de remover código e responsabilidades que já não servem ao objetivo do sistema.

Essa fonte não prova que todo site estático será mais disponível numa plataforma gerenciada. Ela sustenta um princípio mais limitado: simplicidade operacional e baixo acoplamento ajudam a tornar sistemas mais compreensíveis, testáveis e confiáveis.

Minha síntese a partir do caso é direta: se uma dependência não precisa participar da leitura, removê-la do caminho crítico pode ser uma medida de resiliência.

Não é “menos engenharia”.

É engenharia aplicada para deixar de operar o que não precisava existir ali.

O que sai do cluster não precisa perder governança

Remover uma página estática da infraestrutura própria não significa jogar uma pasta em qualquer lugar e torcer.

Eu ainda preciso preservar:

  • a origem versionada do conteúdo;
  • um build reproduzível;
  • validações antes de publicar;
  • versões de avaliação protegidas;
  • domínio correto; conexão criptografada pelo Protocolo de Transferência de Hipertexto Seguro (HTTPS); cabeçalhos de resposta — metadados que orientam cache, segurança e comportamento do navegador —; e indexação — condições para mecanismos de busca descobrirem e incluírem a página —;
  • métricas sob uma política de privacidade;
  • histórico de publicação;
  • uma forma verificável de voltar à versão anterior;
  • uma cópia portátil do resultado que possa ser servida em outro lugar.

O que muda é a responsabilidade operacional.

Em vez de manter máquinas, processos, rede interna e roteamento apenas para entregar arquivos, eu entrego o artefato a uma superfície especializada em distribuí-los. Uma rede de distribuição de conteúdo (content delivery network, ou CDN) mantém cópias próximas de diferentes regiões e responde às solicitações sem fazer o visitante atravessar minha infraestrutura privada para buscar cada arquivo.

Isso troca uma dependência por outra.

Não elimina risco, nem transforma o fornecedor em instituição divina incapaz de falhar. A nova plataforma pode ter indisponibilidade, limites, mudança de preço, erro de configuração ou bloqueio de conta. Domínio e o sistema que traduz nomes em endereços na internet — o DNS — continuam importando. O processo de publicação continua precisando de segurança. Uma função proprietária demais pode recriar o acoplamento que eu estava tentando remover.

Por isso, a portabilidade do artefato importa.

Se o resultado final é uma pasta padronizada de arquivos, consigo testá-la localmente, comparar seu conteúdo e publicá-la em outro destino com menos reconstrução. Se toda página depende de uma função específica do provedor, apenas mudei o nome do cluster no diagrama.

A parte dinâmica pode continuar dinâmica — só não precisa sequestrar a página inteira

Uma interface estática ainda pode enviar um formulário, consultar uma interface de integração entre sistemas — uma API —, carregar dados autenticados ou iniciar uma automação.

Essas operações são dinâmicas.

Elas precisam de validação, limite, controle de abuso, proteção de segredos, registro seguro e comportamento previsível quando o serviço de destino estiver indisponível. Em alguns casos, uma pequena função executada somente naquela rota é suficiente. Em outros, existe um sistema completo por trás.

A diferença é que a página inteira não precisa ser gerada por esse sistema só porque um botão conversa com ele.

Eu posso separar:

  • a apresentação pública, construída antes e distribuída como arquivo;
  • as rotas dinâmicas, executadas apenas quando existe uma ação real;
  • os sistemas privados, que continuam fora do alcance direto do navegador;
  • o comportamento de falha, que informa o problema sem fingir que a ação foi concluída.

Essa separação não mantém tudo funcionando durante qualquer incidente. Se a API de cadastro cair, o cadastro pode ficar indisponível. Mas o site ainda pode explicar o serviço, mostrar um canal alternativo e deixar claro o que não funcionou.

Disponibilidade não precisa ser binária. Uma parte pode degradar sem levar consigo tudo que ainda seria útil.

Como eu decido se um site pode sair desse caminho

Eu não começo perguntando qual plataforma está na moda. Começo inventariando o que acontece quando alguém acessa cada rota.

  1. O HTML muda para cada requisição? Se o conteúdo é igual para todos até a próxima publicação, existe um candidato forte à construção antecipada.
  2. Existe dado secreto ou pessoal sendo processado? Se existe, ele não pode ser empurrado para o navegador apenas para chamar a arquitetura de estática.
  3. O conteúdo precisa do servidor ou apenas as ações precisam? Um formulário dinâmico não obriga todas as páginas a dependerem do mesmo ambiente de execução — o runtime.
  4. O resultado pode ser testado como artefato? Eu quero abrir a pasta gerada, validar links, idioma, metadados, acessibilidade e comportamento antes de enviá-la.
  5. A publicação é reversível? Uma nova versão precisa poder falhar sem destruir a anterior, e a volta precisa ser mais concreta que “a plataforma deve guardar alguma coisa”.
  6. O destino cria dependências proprietárias desnecessárias? Funções, bancos e recursos específicos entram somente quando resolvem um requisito real.
  7. O que acontece durante uma falha parcial? A página continua legível? A ação desabilita de forma honesta? Existe um canal alternativo? O erro fica observável sem expor informação sensível?
  8. Quando a migração termina? Depois do teste, do período de observação e da confirmação do caminho de retorno, a infraestrutura antiga precisa ser retirada. Caso contrário, a “simplificação” termina mantendo as duas arquiteturas para sempre.

Esse último item é menos charmoso que o diagrama da migração.

Também é onde a economia e a redução real de risco finalmente aparecem.

O que este caso não autoriza concluir

Eu não estou propondo que toda aplicação vire um conjunto de arquivos estáticos.

Um sistema transacional, uma área autenticada com dados sensíveis, uma aplicação que monta respostas específicas por requisição ou um produto que depende de lógica no servidor continuam precisando de uma camada dinâmica. Dependendo de latência, soberania, integração, custo e controle, infraestrutura própria pode ser a melhor escolha.

Também não estou dizendo que aplicações de página única — as SPAs, que atualizam a interface no navegador sem carregar um documento novo a cada interação — resolvem automaticamente indexação, acessibilidade ou desempenho. Um site pode ser estático e ainda ser ruim. Para conteúdo público, gerar HTML antecipadamente pode ser melhor do que entregar uma página vazia que só aparece depois de muito JavaScript.

SSR também não é desperdício por definição. É desperdício quando paga complexidade de execução sem entregar uma necessidade da aplicação.

Por fim, uma plataforma gerenciada não remove responsabilidade. Eu continuo responsável por decidir o que publico, verificar o build, proteger rotas dinâmicas, limitar dependências e manter uma saída.

A tese não é “terceirize tudo”.

É “não obrigue uma página pronta a depender de uma fábrica inteira ainda estar funcionando”.

Arquitetura madura não é a que tem mais caixas

Eu gosto de infraestrutura. Trabalhei por anos atravessando a esteira inteira entre requisito, software, publicação, monitoramento, segurança, backup e continuidade.

Talvez justamente por isso eu tenha menos vontade de manter uma peça só porque sei operá-la.

Conhecimento técnico não deveria aumentar a quantidade de tecnologia que coloco em todo problema. Deveria aumentar minha capacidade de distinguir o que é essencial, o que é contingência e o que virou decoração arquitetural.

Um cluster é uma ferramenta excelente quando existe trabalho para um cluster.

SSR é uma ferramenta excelente quando existe algo que precisa ser renderizado no servidor.

Um site estático é uma solução madura quando o requisito é distribuir, com segurança e previsibilidade, algo que já está pronto.

Resiliência não é contar quantas caixas aparecem no diagrama.

É saber quantas delas podem falhar sem derrubar aquilo que deveria ter continuado disponível.

Na i-9.ai, esse é o tipo de pergunta que eu prefiro fazer antes de acrescentar outra camada: qual capacidade o sistema realmente precisa — e qual responsabilidade podemos remover sem perder controle?

Se sua empresa mantém uma arquitetura inteira para entregar algo que já poderia estar pronto, entre em contato. A conversa pode começar pelo caminho real de cada requisição, não pela ferramenta que alguém decidiu colocar no desenho.

Continue lendo

Para se aprofundar

Referências e limites de uso

As fontes abaixo sustentam mecanismos e princípios técnicos específicos. Elas não provam que uma plataforma gerenciada será sempre mais disponível, mais barata ou mais adequada que infraestrutura própria. A decisão descrita no artigo é uma síntese autoral aplicada a casos em que o conteúdo podia ser construído antecipadamente.

  • MDN — “O que é um servidor web?”: diferencia servidores que entregam arquivos estáticos daqueles que executam software para gerar conteúdo dinâmico; não define qual arquitetura um produto específico deve adotar.
  • MDN — “O modelo de padrões da web”: explica, em linguagem introdutória, os papéis de estrutura, apresentação e comportamento de HTML, CSS e JavaScript.
  • MDN — “HTTPS”: define o protocolo usado para proteger a comunicação entre navegador e servidor; não comprova que uma implantação específica esteja configurada corretamente.
  • MDN — “Cabeçalhos HTTP” e Google Search Central — “Como a Pesquisa funciona”: explicam metadados de resposta e etapas gerais de descoberta e indexação; não auditam a publicação descrita no artigo.
  • Google SRE — “Como enfrentar falhas em cascata”: descreve como dependências e sobrecarga podem propagar falhas; aplicar esse princípio à retirada do servidor de aplicações é a síntese arquitetural do artigo.
  • React — “Início rápido”: apresenta componentes como peças reutilizáveis da interface; não determina qual arquitetura de publicação um projeto deve usar.
  • W3C — “O que é internacionalização?”: explica a preparação de produtos para diferentes idiomas, culturas e convenções; não avalia a implementação específica citada no artigo.
  • Kubernetes — “Réplicas”, Cloudflare — “Balanceamento de carga” e Google SRE — “Monitoramento de sistemas distribuídos”: apresentam, respectivamente, cópias de aplicações, distribuição de tráfego e observação de sinais operacionais; não tornam essas peças necessárias em toda arquitetura.
  • Vite — “Build para produção”: documenta que o build padrão produz um pacote adequado para hospedagem estática; não garante qualidade, indexação, segurança ou portabilidade de qualquer aplicação construída com Vite.
  • React — “APIs de servidor do React DOM”: documenta as APIs que renderizam componentes React em HTML no servidor; não afirma que SSR seja obrigatório nem inadequado para uma classe inteira de aplicações.
  • Cloudflare Workers — “Visão geral”: apresenta o ambiente de execução, seus recursos e a entrega de ativos estáticos. Essa página não documenta as regras do pacote OpenAI Sites: esse trecho do artigo se limita à versão 0.1.46 instalada e às três execuções observadas pelo autor.
  • Cloudflare Pages — “Limites”: identifica os limites atuais do plano gratuito citado no artigo; disponibilidade, cotas e termos podem mudar e precisam ser revistos numa decisão futura.
  • MDN, “DNS”: define o sistema de nomes de domínio e sua função de associar nomes a recursos como endereços IP; esse glossário sustenta apenas a definição técnica, não uma arquitetura de DNS nem a tese ampla do artigo.
  • MDN, “API”: define API como uma interface de regras e recursos pela qual software interage com outro software; esse glossário sustenta apenas a definição técnica, não a disponibilidade das integrações citadas.
  • MDN, “SPA”: define aplicações de página única e registra vantagens e desvantagens gerais; esse glossário sustenta apenas a definição técnica, não prova que HTML estático seja superior para todo produto.
  • MDN — “Modelo de execução do JavaScript”: descreve, de forma abstrata, a infraestrutura básica de um ambiente de execução JavaScript e a cooperação entre motor e hospedeiro; seu escopo não prescreve como todo runtime ou arquitetura deve ser organizado.
  • Google — “Engenharia de confiabilidade de sites: simplicidade”: sustenta a relação operacional entre simplicidade, baixo acoplamento, compreensão e confiabilidade; os exemplos vêm do contexto do Google e não constituem uma garantia universal de disponibilidade.
Esta postagem está licenciada sob CC BY 4.0 pelo autor.

Conversa aberta

Continue a conversa

Discordou, encontrou uma lacuna ou tem uma experiência que amplia o assunto? Comente usando sua conta do GitHub. Não publique dados pessoais, credenciais ou informações sensíveis.