features · Sep 3, 2014

Quire: construir uma grande aplicação com Dart

✦
Traduzido por IA
· Ver em inglês

Aplicação Quire construída com a linguagem de programação Dart

Última atualização: 28 de maio de 2026

TL;DR

O Quire (53.992 linhas, 1.620 KB de Dart) foi construído em 2014 com Dart no cliente e no servidor, recorrendo ao DQuery e ao Bootjack em vez do AngularDART ou do Polymer.dart para um controlo mais fino do DOM. As decisões centrais (tipagem forte em toda a stack, modelos de dados partilhados entre cliente e servidor, event loop no servidor e tree shaking no JS gerado) continuam válidas em 2026.

O Quire não é a primeira aplicação web escrita em Dart, nem será a última, mas pode ser a primeira a depender tanto do Dart, tanto no cliente como no servidor.

Logótipo da linguagem de programação Dart e framework da aplicação web Quire

É um gestor de tarefas divertido, com uma estrutura em árvore no seu núcleo. O projeto em si tem 53992 linhas e 1620KB de código Dart, construído com algumas bibliotecas open source da comunidade.

Quem construiu o Quire?

Antes de começarmos a trabalhar neste projeto, já éramos entusiastas do Dart conhecidos como a equipa Rikulo, e tínhamos lançado várias bibliotecas Dart: uma framework de UI, uma biblioteca de UI, um servidor web, um servidor de mensagens, um cliente de base de dados, entre outras.

Quando o Dart foi lançado em 2011, ficámos todos entusiasmados com o seu potencial e começámos de imediato a usá-lo em pequenas partes de projetos. Acabámos por avançar para uma aplicação completa feita maioritariamente em Dart. Partilhamos aqui, com humildade, parte da nossa experiência, na esperança de que seja útil a quem desenvolve em Dart.

Porque é que o Quire escolheu Dart em vez de JavaScript?

Há imensas razões para escolher Dart. Para nós, as mais importantes são:

  • O sistema de tipos forte do Dart protege-nos de inúmeros pequenos erros. O Dart Editor, o IDE oficial, dá feedback rápido sobre erros de tipos e sugestões de autocompletar, além de facilitar o rastreio.
  • Achamos o modelo de herança baseado em classes muito mais intuitivo do que o baseado em protótipos.
  • O Dart permite usar a mesma linguagem no cliente e no servidor, partilhando o mesmo modelo de dados e a mesma base de código.
  • O Dart corrige a maior parte das armadilhas do JavaScript. Não é perfeito nisto, mas resolve 99% das velhas surpresas desagradáveis.
  • O Dart já disponibiliza algumas funcionalidades populares do JavaScript Harmony: Future (promise), Arrow Function, etc.
  • O Dart conta com uma equipa sólida, com muitas bibliotecas oficiais de alta qualidade e APIs bem organizadas. Continua a evoluir, mas a especificação já é bastante estável.
  • No servidor, preferimos o modelo de event loop ao multithreading.
  • O Dart faz tree shaking ao compilar para JavaScript. (Ver abaixo.)

Escolher Dart também tem desvantagens:

  • A comunidade Dart é muito mais pequena do que a comunidade JavaScript.
  • A comunicação entre Dart e JavaScript não é trivial.
  • É mais difícil fazer polyfill de APIs numa linguagem fortemente tipada.
  • O desempenho do Dart Editor ainda não é o ideal para projetos grandes.

Com o apoio da tipagem forte, escrever em Dart é muito mais fiável do que em JavaScript. Além disso, o Dart é menos verboso do que o Java e, por vezes (por exemplo, com expressões de função), até menos verboso do que o JavaScript puro. Em geral, trabalhar com Dart é confortável, exceto em alguns pontos:

  • Um campo final tem de ser inicializado no inicializador, antes do corpo do construtor.
  • A especificação de mixins é ainda imatura e não será corrigida antes da versão 2.0.
  • Não há parâmetros de tipo genérico em declarações de funções, apenas em classes. (Claro que isso aumentaria a carga do compilador.)

Como funciona o Dart no lado do cliente?

Até a Dart VM chegar ao Chrome, a entrega do produto passa por compilá-lo para JavaScript. Há imensas linguagens que compilam para JavaScript, mas o Dart destaca-se por algumas vantagens extra.

  • Em desenvolvimento, executamos Dart nativamente no Dartium, um navegador derivado do Chromium com uma Dart VM integrada. Não precisamos de compilar a cada iteração, o que nos poupa a inúmeras interrupções.
  • Em testes e produção, compilamos para JavaScript e executamos em todos os principais navegadores. O compilador de Dart para JavaScript faz tree shaking, eliminando o código não utilizado do resultado. Isto reduz muito o tamanho do nosso código JavaScript.

Porquê usar Dart no lado do servidor?

O Dart no servidor nunca foi um tema quente na comunidade Dart, mas consideramo-lo um forte candidato a linguagem de programação do lado do servidor, porque:

  • Um serviço web, pela sua natureza assíncrona, funciona muito bem com o modelo de event loop (em vez de multithreading).
  • O código do servidor exige muito mais robustez e segurança do que o do cliente, e aqui uma linguagem fortemente tipada dá muito jeito.

Relacionado: Quire obtém certificação ISO para proteger os seus dados — a mesma ênfase na robustez e segurança do servidor reaparece anos mais tarde na certificação formal de proteção de dados do Quire.

Que bibliotecas usa o Quire na sua stack Dart?

O Quire é construído com cerca de 30 bibliotecas importadas, das quais 10 vêm da comunidade e as restantes são lançadas pela equipa do Dart. Se for especialista em Dart, talvez espere encontrar o AngularDART e o Polymer.dart, mas, na verdade, nenhum deles está presente.

Não usamos o AngularDART porque:

  • Queremos um controlo minucioso do DOM.
  • Usamos diretrizes de arquitetura próprias para desenhar a estrutura do cliente, e o paradigma é diferente da lógica do Angular.
  • Quando analisámos o AngularDART, gerava um grande acréscimo no tamanho do JavaScript compilado, embora isso tenha melhorado bastante entretanto.

Também não usamos o Polymer.dart, porque:

  • Devido ao encapsulamento e ao redirecionamento de eventos, o ShadowDOM não colabora com frameworks orientadas a seletores, como o Bootstrap.
  • Não é possível injetar estilos a partir do exterior do ShadowDOM. Se um conjunto de componentes de terceiros for feito em Polymer, é quase impossível os utilizadores alterarem o seu aspeto. Atualização: desde dezembro de 2013, é possível modificar o estilo interno a partir do exterior. Ver Shadow DOM 201.

O que são o DQuery e o Bootjack?

Os pilares da nossa stack do lado do cliente são o DQuery e o Bootjack, ambos projetos open source lançados pela equipa Rikulo:

  • O DQuery é uma adaptação parcial do jQuery para Dart, centrada no sistema de delegação de eventos do jQuery.
  • O Bootjack é uma adaptação completa do Bootstrap 3, com CSS e APIs quase idênticos.

Construímos a nossa stack desta forma para aproveitar os conhecimentos e competências que trazíamos do mundo JavaScript.

O que é o servidor web Stream?

O Stream é o nosso servidor web, escrito em Dart puro, com funcionalidades de encaminhamento, filtros, MVC do lado do servidor, etc. Funciona sem atritos com o modelo de event loop: escrever um handler de pedidos resume-se a encadear uma sequência de rotinas não bloqueantes.

É mais produtivo e mais agradável do que o modelo tradicional de multithreading. Também escalamos o serviço web e tratamos o HTTPS com o nginx, que delega os pedidos no Stream. Com esta arquitetura, conseguimos lançar e encerrar VMs Dart individualmente e atualizar o servidor sem interromper a atividade dos utilizadores.

Conclusão

Trabalhar com Dart tem sido uma experiência agradável, e aguardamos com expectativa mais novidades entusiasmantes na comunidade Dart. Por fim, se tem curiosidade sobre o que é possível fazer com Dart, venha experimentar a nossa aplicação, o Quire. É grátis!

Saiba mais sobre como o Quire foi mais tarde reimaginado e reconstruído como Mark II.

Diagrama de arquitetura do Quire com a implementação cliente-servidor em Dart

Que lições desta construção de 2014 continuam válidas em 2026?

Tanto a linguagem Dart como a base de código do Quire evoluíram muito desde que este artigo foi escrito. O Dart 2.0 (sistema de tipos sólido) chegou em 2018, o Dart 3.0 (null safety, records, patterns) em 2023, e o Flutter mudou o panorama da UI multiplataforma (a própria equipa mobile do Quire adotou-o). Ainda assim, as decisões de arquitetura descritas acima resistem melhor do que se poderia esperar.

A tipagem forte no cliente e no servidor continua a compensar. Os erros de execução que um sistema de tipos forte apanha na compilação continuam a ser os mesmos. O JavaScript aproximou-se parcialmente da tipagem com o TypeScript, mas uma stack totalmente tipada de ponta a ponta continua a ser rara. O tipo de bugs que o Simon referiu (inúmeros pequenos erros) continua a ser o que uma stack sem tipos envia para produção.

Partilhar modelos de dados entre cliente e servidor continua a poupar trabalho. O problema de duplicar modelos (um em JS, outro em Python, a divergir em silêncio) é o mesmo em 2026 que era em 2014. A solução (uma única linguagem de ponta a ponta) também. As equipas de TypeScript sobre Node constroem arquiteturas ao estilo do Quire precisamente por isso.

O event loop continua a vencer o multithreading nos servidores web. Node, Deno, Bun e o próprio padrão Stream do Dart estão de acordo nisto. O debate volta a ser reaberto de poucos em poucos anos e chega sempre à mesma conclusão.

O tree shaking importa mais, não menos. Em 2014, o compilador com tree shaking do Dart era um fator diferenciador. Em 2026, é requisito mínimo de qualquer pipeline de build que gere JS. Webpack, Rollup, esbuild e Vite fazem-no todos. A lição mantém-se; as ferramentas é que alcançaram.

As preocupações de 2014 com o ShadowDOM ficaram, em grande parte, resolvidas. O Polymer.dart foi descontinuado e os Web Components amadureceram. As razões que o Simon apontou para evitar o Polymer (injeção de estilos, colaboração com frameworks) acabaram por ser resolvidas pela própria plataforma. O princípio geral (evitar frameworks de vanguarda no núcleo de aplicações em produção) continua a aplicar-se em 2026 a qualquer que seja a framework "entusiasmante" do momento.

Relacionado: Como é feito: um cronograma mobile baseado em Flutter — um olhar sobre como a equipa mobile do Quire usou o Flutter para construir uma vista de cronograma.

Quais são os erros mais comuns ao escolher uma linguagem para uma grande aplicação web?

Escolher a stack de linguagens para uma aplicação com vários anos de vida é uma das poucas decisões de engenharia caras de reverter. Há quatro padrões que se repetem quando as equipas erram.

1. Escolher por defeito a linguagem com a maior comunidade. O JavaScript tem a maior comunidade, mas "maior" não é o mesmo que "mais adequada ao seu problema". Uma linguagem com um sistema de tipos forte, boas ferramentas e uma comunidade mais pequena pode superar um ecossistema vasto com garantias fracas. O tamanho da comunidade conta, mas não é a única coisa que conta.

2. Escolher uma stack que separa as linguagens do cliente e do servidor. Cada modelo de dados duplicado é um bug à espera de acontecer. As equipas que usam Ruby no servidor e JS no cliente carregam esse custo para sempre. As que partilham uma única linguagem nos dois lados (Dart, TypeScript, Kotlin) evitam uma categoria inteira de bugs.

3. Adotar a vanguarda antes de estabilizar. Em 2014, a equipa do Quire evitou o AngularDART e o Polymer.dart porque ambos tinham questões de arquitetura em aberto. O AngularDART mudou radicalmente de rumo e o Polymer foi descontinuado. A regra geral (deixar uma framework provar o seu valor em produção e em escala antes de apostar nela o núcleo da aplicação) continua a aplicar-se em 2026 a qualquer que seja a framework "entusiasmante" do momento.

4. Abdicar do sistema de tipos em troca de velocidade a curto prazo. As linguagens sem tipos parecem mais rápidas na primeira semana. Ao sexto mês, o tempo poupado já foi largamente gasto em depuração. As equipas de engenharia que viveram stacks com e sem tipos em escala quase nunca voltam atrás de livre vontade.

A aposta da equipa do Quire no Dart em 2014 parece sensata em retrospetiva, não porque o Dart se tenha tornado dominante (não se tornou), mas porque os critérios subjacentes (tipagem, partilha entre cliente e servidor, event loop, tree shaking) se tornaram consenso na indústria na década seguinte.

O que envelheceu bem foram os princípios de engenharia subjacentes, não as ferramentas específicas. Esse padrão costuma valer para qualquer escolha de linguagem feita em incerteza: escolha princípios que consiga defender daqui a uma década, não a popularidade que consegue medir hoje.

Junte-se a mais de 100.000 equipas que usam o software de gestão de projetos Quire — registe-se gratuitamente

Perguntas frequentes

Em que linguagem é construído o Quire?

Em Dart, no cliente e no servidor. A aplicação tem cerca de 54.000 linhas de código Dart e cerca de 30 bibliotecas importadas.

Porque é que o Quire escolheu Dart em vez de JavaScript ou TypeScript?

Pela tipagem forte, pelo modelo de herança baseado em classes e por ter uma única linguagem no cliente e no servidor. O Dart oferecia ainda algumas funcionalidades modernas antes de terem suporte alargado no JavaScript.

Porque é que o Quire não usou AngularDART nem Polymer.dart?

A equipa queria um controlo do DOM mais fino do que o binding do AngularDART permitia, e os padrões de arquitetura do Quire não encaixavam na lógica do Angular. O Polymer.dart foi evitado porque, na altura, o ShadowDOM entrava em conflito com seletores ao estilo do Bootstrap. O Polymer acabou por ser descontinuado, o que confirmou a decisão.

O que são o DQuery e o Bootjack?

Bibliotecas open source da equipa Rikulo (a equipa de engenharia do Quire). O DQuery é uma adaptação parcial do jQuery para Dart, centrada na delegação de eventos. O Bootjack é uma adaptação completa do Bootstrap 3, com CSS e APIs quase idênticos.

O que é o Stream na stack do Quire?

O servidor web do Quire, escrito em Dart puro e baseado no modelo de event loop. Inclui encaminhamento, filtros e MVC do lado do servidor. O Quire executa o Stream por trás do nginx, que trata da escalabilidade e do HTTPS.

Simon Pai
Co-Founder at Bookshow