- A abordagem HTML-first fez com que o formulário de solicitação de serviço público funcionasse mesmo sem JavaScript, permitindo que usuários concluíssem a solicitação mesmo em dispositivos, navegadores e redes precários
- O app anterior em React foi retirado do ar em 3 dias por causa de reclamações de clientes; os problemas incluíam spinner de carregamento, estado global em JavaScript, falhas de acessibilidade e um método de armazenamento de imagens que batia no limite de 5 MB do
localStorage - A nova implementação, baseada em Astro, transformou cada etapa do formulário em uma página separada e salvava, a cada etapa, os dados enviados e os uploads em uma sessão de backend, evitando perda dos dados digitados
- A validação do formulário foi feita com um web component que encapsulava a validação HTML nativa do navegador, usando uma estrutura de aprimoramento progressivo que, em caso de falha, seguia para a validação padrão do navegador e depois para a validação da API no backend
- Após o lançamento, o número de pessoas que concluíram o formulário dobrou, revelando também que usuários que abandonam por falhas de JavaScript não aparecem em pacotes de analytics baseados em JavaScript
Contexto do problema e a tentativa anterior que falhou
- O cliente era uma empresa de serviços públicos, e a solicitação do serviço podia ser feita por formulários ASP antigos no site ou por processos manuais
- O processo manual custava mais para a empresa, e ela operava como um monopólio regulado em que a satisfação do cliente cair abaixo de 96% poderia gerar multas de milhões de libras
- Duas tentativas anteriores de resolver o problema falharam, e na mais recente contratados de outro país criaram um app em React
- O app em React foi retirado do ar 3 dias após o lançamento público por causa de reclamações dos clientes
- O app misturava spinners de carregamento e estado global em JavaScript, além de não atender aos requisitos de acessibilidade
- O upload de imagens era um recurso central do formulário, mas tentava salvar as imagens e todos os dados do formulário no
localStorage, que tem limite de 5 MB
Critérios definidos para uma abordagem HTML-first
- O novo site foi construído com Astro e adotou uma estrutura HTML-first
- O JavaScript foi usado apenas dentro de web components, com o papel de melhorar progressivamente um site que já funcionava normalmente sem JavaScript
- Aplicou-se o critério de que serviços públicos devem funcionar em todos os dispositivos possíveis
- Aplicou-se o critério de que o site deve funcionar mesmo com conexão ruim
- Aplicou-se o critério de que dados inseridos no formulário nunca devem desaparecer
- O caso de Terence Eden mostrou que páginas HTML simples do GOV.UK permitiam ler informações sobre benefício habitacional até no navegador do PlayStation Portable, que era lento e frequentemente ficava sem memória
- As páginas do GOV.UK eram escritas em HTML simples com design leve e precisavam funcionar até em navegadores muito ruins
Estrutura do formulário e forma de preservar os dados
- Cada sessão do formulário precisava ter um ID único
- Em todas as etapas do assistente do formulário, os dados enviados e os arquivos enviados precisavam ser salvos no backend
- O formulário precisava poder ser concluído mesmo sem JavaScript
- O formulário precisava poder ser concluído até em navegadores antigos e de baixo desempenho
- A acessibilidade precisava atender aos critérios da WCAG, e a equipe definiu AA como meta, não AAA
- JavaScript e CSS moderno deveriam ser usados para melhorar a experiência
- Na estrutura final, cada etapa do assistente do formulário virou uma página separada, e ao clicar em avançar o formulário era enviado
- Se a API considerasse os dados válidos, o navegador era redirecionado para a próxima etapa
- Envio de formulário seguido de redirecionamento é um padrão antigo de aplicações web e teve um pequeno renascimento moderno graças ao Remix
- O serviço não era um app que mostrava dados em tempo real, e enviar 20 MB de JavaScript antes da renderização era inadequado para um formulário grande
Validação do formulário e aprimoramento progressivo
- Validação de formulário e renderização de erros são áreas em que equipes costumam gastar muitos meses por causa de bibliotecas de validação para React
- Os navegadores já incluem um sistema de validação, que pode ser aproveitado com menos trabalho do que implementações imitadoras de baixa qualidade que exigem manutenção de bibliotecas separadas
- O HTML web component implementado era um elemento customizado simples que encapsulava o HTML existente
- Esse web component não usava Shadow DOM e quase não renderizava HTML dentro do JavaScript
- O componente envolvia o formulário HTML e reaproveitava a validação HTML em uma apresentação mais moderna
- Os tooltips popup da validação HTML eram bloqueados, e os erros eram colocados em elementos
aria-describedbyassociados aos campos - Hoje, recomenda-se usar
aria-errormessage - Quando um campo se tornava válido durante a digitação, a validação era limpa, e reavaliada no
blure no momento do envio - Essa experiência de usuário era entregue com menos de 1 KB e, em caso de falha, voltava para a validação padrão do navegador
- Se a validação padrão do navegador também falhasse, a API de backend fazia a validação
- Problemas de validação eram informados no momento mais cedo que o navegador do usuário permitisse, e mesmo em caso de falha sempre havia fallback para uma experiência aceitável
- Depois, uma nova versão do web component foi reescrita do zero para uso geral e recebeu o nome validation-enhancer
- O exemplo de uso mostra
validation-enhancerenvolvendo um formulário HTML e reutilizando diretamenteinput type="email",requiredearia-errormessage
Email
Submit
Resultados após o lançamento e conclusão
- Depois do lançamento, o número de pessoas que concluíram o formulário dobrou
- Os responsáveis por analytics não sabiam de onde esses usuários vieram
- Pacotes de analytics baseados em JavaScript não enxergam usuários que abandonam por falhas de JavaScript
- A abordagem de manter sessões no backend e nunca perder os dados do usuário funcionou
- Em um caso, um usuário concluiu o formulário um mês depois de tê-lo iniciado
- Após o fim do contrato, o sucessor reagiu dizendo que uma estrutura que sempre funciona sem JavaScript dá mais trabalho para a equipe
- Excluir usuários de navegadores antigos, usuários com conexão ruim e usuários de tecnologias assistivas é inaceitável em um serviço público monopolista
- É preciso abandonar a tendência de continuar empurrando práticas ásperas e imaturas que surgiram na fase de expansão da indústria de software
- Se você criar uma aplicação web que funciona até em um PlayStation Portable com conexão 3G, ela funcionará para todos os usuários e talvez continue funcionando daqui a 30 anos
2 comentários
Comentários do Hacker News
Como alguém que não é desenvolvedor web, fico curioso e não entendo por que essa abordagem daria mais trabalho
A abordagem descrita no texto parece bem simples: criar componentes padrão para formulários e colocar um botão de envio embaixo. Eu fazia isso quando montava sites pessoais há muito tempo, e não era tão difícil. Posso estar falando isso por não conhecer bem a área, mas criar um frontend cheio de firulas parece muito mais difícil
Não é porque sejam burros. Se você perguntar diretamente “dá para fazer um site sem React?”, obviamente vão responder “sim”. Mas, se você mandar criar um site novo, por familiaridade e pela vontade de terminar o trabalho, acabam começando um novo projeto em React sem pensar muito
Alguns realmente não conhecem outro jeito. Não sabem como subir um servidor HTTP comum que entregue HTML puro, nem têm experiência em criar formulários que validam e enviam sem JavaScript. Essas pessoas não são as que escrevem no HN, nem participam de discussões online sobre ferramentas e tecnologias novas, ou sobre ferramentas e tecnologias antigas. Aprenderam só o suficiente para conseguir emprego em um bootcamp ou em uma disciplina de webapp na faculdade e, depois disso, foram aprendendo conforme necessário apenas as ferramentas específicas exigidas pelo empregador ou escolhidas por alguém da equipe
Como alguém mais velho, demorei um pouco para perceber isso, mas agora entendo. Dependendo da trajetória profissional, algumas pessoas entram em contato com as partes mais simples de HTML, CSS e JavaScript puro só depois de já terem visto as partes complexas e específicas de frameworks dessas tecnologias. Então, para elas, isso não parece algo menos profissional; ao contrário, pode soar mais obscuro, avançado ou como conhecimento secundário
Dizer “isso dá muito mais trabalho para a gente” também pode não ser uma afirmação errada de propósito. Quando você executa uma tarefa com ferramentas pouco familiares, mesmo que sejam menos complexas, é bem possível que o trabalho pareça de fato muito maior
O app era rápido e simples, mas houve um preço. Ficou mais limitada a capacidade de simplesmente puxar elementos ricos de UI direto de pacotes npm, e foi preciso muito mais trabalho para oferecer uma boa experiência ao usuário. Tudo levava mais tempo e, no fim, a experiência do usuário também ficou pior. Nós nos importávamos com isso, mas às vezes não há tempo para cuidar de tudo até o fim
A empresa fracassou, e não acho que React a teria salvado. Mas posso dizer em primeira mão que uma obsessão moral com a “simplicidade” também não ajudou. Sempre existe um trade-off
Alguém diz que apresentou uma solução mais simples e razoável do que a maioria pensaria, e a pessoa que assumiu depois não ficou satisfeita
Será que o código entregue era mesmo de alta qualidade? Será que a reação foi ao fato de “não ser React”? Será que havia algum template imposto pela empresa sobre como criar apps?
Não dá para saber
Faz tempo que não ouço muito sobre isso, mas a proposta HTML Triptych continua sendo uma das coisas que eu gostaria de ver algum dia nos navegadores. A forma como formulários HTML conversam com endpoints REST é um bom padrão
A validação auxiliar para o usuário é tratada com atributos do input, a validação real acontece do outro lado da requisição, e o fluxo fica algo como GET /form => POST /thing => GET /thing/1. Se os recursos do triptych forem implementados, isso será um ótimo padrão
[0] https://triptychproject.org/
Não gosto nem um pouco de sites em React, mas o que não entendo é: esses sites não fazem lazy loading de jeito nenhum?
Mesmo um aplicativo grande de página única pode ser muito rápido se carregar os componentes só quando forem necessários
Passei de Angular1 -> Vue2 -> Svelte2 e acabei ficando com web components puros sem shadow DOM, que são agradáveis de usar e rápidos
Hoje em dia, a maioria dos apps é feita simplesmente com HTMX + Go + SQLite
Achei que isso era suficiente para a maioria dos projetos
Um dos meus sites tem muitas imagens e lida com 10 TB de tráfego por mês. Nesse caso, a configuração é a seguinte: 1. uso S3 porque preciso de um armazenamento de dados confiável 2. coloco o Cloudflare na frente e ativo o Tiered Cache. Assim, os POPs preferem buscar do Cloudflare em vez da origem. Faço cache de tudo por 1 ano tanto no navegador quanto no Cloudflare, e configurei regras para ignorar a política de cache da origem e as query strings, usando apenas objetos imutáveis que exigem versionamento 3. coloco o BunnyCDN na frente disso
Só o Cloudflare não permite operar um site pesado em imagens, então com esse método reduzo bastante os custos. Pelas políticas, ele não deve ser usado principalmente para imagens, e sim para HTML, CSS, JavaScript e outros conteúdos do site
Se usar só S3, o custo fica enorme
Mas recentemente estou fazendo um app mobile. PWA tem limitações. O sistema operacional pode limpar o armazenamento do IndexedDB, então não dá para oferecer um armazenamento de dados confiável dentro do app sem cadastro ou sem envolvimento de backend
No fim, no Android tive que migrar para Flutter, mas aí veio outra dor. Às vezes as atualizações do app ficam muito tempo “em revisão”, o que é frustrante. Comparado com isso, o web app do mesmo app é atualizado muito rápido
Fico me perguntando por que não existe um sistema operacional mobile que deixe você criar apps com JavaScript, HTML e CSS e ainda ofereça armazenamento estável sem muito esforço. O bom dos apps PWA é poder atualizar rápido
Viajar no tempo é a parte fácil; depois disso, você precisa dar um jeito de impedir a queda da Palm e o esquecimento do webOS como sistema operacional de smartphone
Se 2009 for longe demais, também dá para apostar suas fichas no Firefox OS de 2012
Brincadeiras à parte, pessoas e empresas já tentaram. Mas uma combinação de timing ruim e vários acontecimentos impediu que essa realidade acontecesse na nossa linha do tempo
Parece estar exatamente no ponto ideal em que não tem a carga desnecessária de C, mas também sai da frente como Java para deixar você focar na lógica de negócio. É diferente de Rust
Não é bom para tudo. Especialmente, sinto falta da capacidade de criar abstrações. Mas é excelente para apps de servidor com muita lógica de negócio. Parece uma linguagem especializada nessa área, e não uma que tenta fazer tudo
Também criei algumas bibliotecas para abstrair as partes de SQL e HTMX/web/OAuth. Agora meus apps são muito parecidos entre si, então ficou fácil portar funcionalidades de um para outro
https://github.com/cattlecloud/webtools
https://github.com/cattlecloud/litesql
Como contraponto, existe In Defence of the Single Page Application
https://williamkennedy.ninja/javascript/2022/05/03/in-defenc...
In Defence of the Single Page Application - https://news.ycombinator.com/item?id=31275178 - maio de 2022, 32 comentários
Este texto é bom, e é um ótimo exemplo de pegar um problema e resolvê-lo com a tecnologia certa e a profundidade certa. Ter pleno conhecimento de domínio do cliente realmente ajuda
Só não gosto do enquadramento no estilo “HTML simples é melhor que React”. Porque a mesma coisa poderia ser dita exatamente do mesmo jeito por um desenvolvedor React
Eu poderia falar sem parar sobre muitas coisas que o texto passa por cima, como a complexidade e as sutilezas do armazenamento de sessão no servidor e do armazenamento no navegador, mas isso ficaria longo demais
As coisas simples em HTML também são simples em React
É literalmente o mesmo código. Nada impede você de usar validação nativa de HTML do navegador em React. O código que fica complexo em React, por exemplo lógica de validação excessivamente complexa, também fica complexo em Astro. O Astro também tem seu próprio jeito de lidar com validação por schema etc., e para integrar isso a um site em Astro você também precisa integrar roteador de cliente e afins, então ali também é muito fácil cair em complexidade excessiva
O objeto de comparação provavelmente também é uma equipe terceirizada no exterior com conhecimento incompleto, e pela estrutura do projeto existe incentivo para construir uma solução o mais rápido possível, em o mínimo de tempo possível e com a maior complexidade possível
Esse último ponto é sutil. Não quer dizer que a empresa terceirizada faça isso de propósito, mas, pela estrutura de incentivos, a complexidade excessiva realmente joga a favor deles, então não existe incentivo direto para seguir por um caminho simples
De toda forma, uma solução simples que lide diretamente com o problema imediato é sempre melhor, independentemente da stack escolhida
Não tenho antipatia pela validação de formulários do Astro; eu só queria destacar que existe uma conversa além de “validação nativa de HTML do navegador”
Ótimo texto, mas sempre fico em conflito quando leio textos inspiradores assim. A ideia de um site simples que está completamente certo, funciona bem, carrega rápido e não depende de navegadores modernos me agrada.
Aí começo a pensar se isso não é porque eu não sou inteligente o bastante para entender React ou a tecnologia da moda da vez.
Dá a sensação de existir um limite de compreensão que eu não consigo atravessar. Se me derem um editor simples como o Sublime e mandarem fazer uma página web, é um espaço feliz para mim, mesmo com JavaScript. Se me derem VSCode ou Zed, plugins de Claude/Copilot/ChatGPT pendurados por todo lado e um tutorial de React, meu cérebro vira mingau
Manter as coisas simples não é algo ruim; na verdade, muitas vezes é preciso ser inteligente o bastante para não torná-las complexas demais
Embrace Extend Extinguish é real, e quem embarca nisso merece até ser substituído por LLMs que mentem mais rápido e cospem código lixo
Isso me lembra quase 15 anos atrás. Eu usava gerenciamento de sessão no backend com Grails e formulários HTML aprimorados com CSS responsivo e “um pouco” de JS.
A diferença para hoje é que a tecnologia dos navegadores não era tão avançada. Era preciso se preocupar com vários navegadores e lidar com IE7, até IE6, então era difícil e exigia QA extensivo. O BrowserStack só apareceu depois.
Há um motivo para as bibliotecas JavaScript terem evoluído. Não existia npm, nem mesmo bower. Aí veio o Backbone.js, e eu gostei dele. AngularJS foi incrível, depois a versão seguinte do Angular trouxe uma grande quebra de compatibilidade, e depois vieram React, Polymer e outros.
Hoje em dia os navegadores nativos conseguem fazer muita coisa e a melhoria progressiva também é fácil. Mas nem sempre foi assim. Na época, a decisão de usar React fazia sentido por vários motivos, e pode ter feito sentido aqui também
Mais de 10 anos atrás eu criava apps assim no GOV.UK para o Ministério da Justiça. Fizemos nossa própria biblioteca de assistente de formulários para validar formulários longos por etapas e dividi-los em várias páginas, porque o Ruby on Rails não oferecia isso por padrão.
Na época, o princípio de que todos deveriam poder usar serviços digitais, independentemente do ambiente pelo qual acessassem, era muito importante
Para cada ID de sessão, dá para relacionar as páginas de uma aplicação multipágina com aquele ID de sessão, então, se necessário, o usuário pode até digitá-lo manualmente. Mas deve ser possível identificar com informações suficientes, como endereço IP, data do upload, navegador e sistema operacional. Ainda assim, a sessão mais precisa precisa estar no navegador, para que o cookie de uma única solicitação não se misture com o de outro requerente, como um parente usando um PlayStation Portable
Tenho curiosidade sobre qual tecnologia eles usam em apps móveis. Imagino que não sejam apps móveis completos, talvez usem webviews
Isso não é “trocamos um app em React por formulários HTML e o desempenho melhorou”. É “trocamos uma página web ruim por uma página web boa e o desempenho melhorou”.
É tolice colocar a culpa na tecnologia usada para tocar a experiência no navegador. Dá para criar uma ótima experiência de usuário com React, e também dá para fazer um site horrível só com HTML puro.
A melhoria veio de uma mudança de design, não da tecnologia
Mas é verdade. A mudança do lado do usuário veio de corrigir o design, não da tecnologia utilizada.
Isso se parece muito com bullet points ruins de currículo. Tipo quando alguém diz “reescrevi o site com abordagem HTML-first e aumentei os visitantes em 100%”, como se o resultado de negócio tivesse vindo da alteração no código. Quando você pergunta sobre esse item, no fim a pessoa admite que redesenhou o site inteiro para corrigir problemas de design ou adicionar funcionalidades, e foi isso que levou ao aumento de visitantes
JavaScript: The Good Parts, do Douglas Crockford, é ridiculamente curto. React: The Good Parts seria ainda mais curto
Curiosamente, o texto original descreve um formulário estilo assistente multipágina, algo que quase não vi nos últimos 10 anos. Só que, sempre que eu via isso, geralmente era em sistemas corporativos terríveis. A última vez foi em algo como um produto da Oracle para prestação de despesas.
O problema dessas coisas sempre é que elas ficam lentas no meio da tarefa. Você precisa esperar vários segundos a cada botão. Se tiver que voltar uma ou duas etapas, a irritação dobra. Um app de página única mal feito tende a ser lento no começo. Demora para carregar, mas, depois que carrega, normalmente o desempenho fica aceitável
Opiniões no Lobste.rs
Fazer algo que funcione direito para as pessoas obviamente dá mais trabalho. Mas isso também é, no fim das contas, o cerne de todo o trabalho
Parece mais que o que os sucessores queriam dizer é que eles não conhecem muito bem os fundamentos da plataforma web
Não quer dizer que isso seja desejável, só que essa é a realidade atual
É triste a parte em que levou tempo para explicar “envio de formulário e redirecionamento” aos colegas. Isso acontece porque todo mundo se acostumou a apps web centrados no cliente
O desenvolvimento web está realmente num estado lamentável hoje, e há muita coisa que precisa ser ensinada de novo
Não acho que seja necessário um nível tão alto de compatibilidade para justificar essa abordagem. Como o texto diz, no fim é só um formulário
Por isso, eu provavelmente faria assim em qualquer caso
Queria trabalhar construindo sites como o descrito no texto. A restrição de ser um download muito pequeno que precisa funcionar em quase todos os navegadores e ainda cuidar da acessibilidade parece um desafio bem interessante
Fico curioso se existe alguma empresa especializada nisso e se estão contratando. Talvez eu só seja uma pessoa mais velha com saudade de quando as coisas eram mais simples
A funcionalidade está isolada o bastante para ser muito fácil extrair isso como uma biblioteca reutilizável, e ainda há bastante coisa a fazer. Dá vontade de colocar isso como padrão de frameworks web. Texto realmente muito bom
Um pouco ironicamente, no Firefox eu nem conseguia ver nem selecionar completamente o corpo do texto por causa de algum estilo, então tive que mudar para o modo de leitura. O título, os marcadores de citação cor-de-rosa e os blocos de código apareciam, mas o resto não
Edit: vendo abaixo, provavelmente é um problema do meu ambiente. Estou deixando pelo contexto
O texto em si eu li bem. Sejam desenvolvedores ou usuários finais, todos nós estamos pagando o custo da “agilidade” do React. Já pensei várias vezes que seria bom poder usar outra stack no trabalho
Também me impressionaram a capacidade de empatia do autor e o fato de ele ter desenhado isso como uma estrutura em que “todos ganham”. Ter esse cuidado acaba trazendo retorno
Concordo muito. No passado fiz um blog com JavaScript em excesso, e quase houve uma revolta por causa das funcionalidades baseadas em JS
Ainda não tive tempo de migrar para uma abordagem HTML-first, mas por fora deixei parecendo em grande parte uma página web HTML-first
Nos meus dados de análise também vi resultados parecidos. A taxa de rejeição caiu de 80% para cerca de 50%, e os novos visitantes dos textos seguintes quase dobraram
Dá arrepios pensar em quantas pessoas passaram a evitar meu domínio para sempre por causa daquela implementação desastrosa feita em JS no começo. Para uma página web ou blog, esse é um dos conselhos mais importantes
Esse tipo de abordagem também ajuda no preenchimento automático de formulários. Antes, o formulário inteiro era dinâmico e cada parte não tinha atributos que permitissem identificá-la, então eu não conseguia fazer o preenchimento automático
Foi uma pena ver algo superprojetado para parecer bonito em vez de priorizar a funcionalidade, então gostei de ler este texto sobre design voltado ao usuário
Se acrescentar streaming com SSE e uma biblioteca de morph, dá para criar funcionalidades dinâmicas, em tempo real e multiplayer de um jeito bem bacana