features · Sep 3, 2014

Quire:Dartで大規模アプリケーションを構築する

✦
AI翻訳
· 英語版を見る

Dartプログラミング言語で構築されたQuireアプリケーション

最終更新日:2026年5月28日

TL;DR

Quire(Dartコード53,992行、1,620 KB)は2014年に、クライアントとサーバーの両方をDartで構築しました。DOMをより細かく制御するため、AngularDARTやPolymer.dartではなくDQueryとBootjackを採用しています。中核となる判断(全体を通した強い型付け、クライアントとサーバーで共有するデータモデル、サーバーのイベントループ、JS出力時のツリーシェイキング)は、2026年の今も通用します。

Quireは、Dartで書かれた最初のWebアプリケーションではなく、最後でもないでしょう。それでも、クライアントとサーバーの両側でここまでDartに頼るアプリは、これが初めてかもしれません。

QuireのWebアプリケーションを支えるDartプログラミング言語のロゴとフレームワーク

根っからのツリー構造を備えた、楽しいタスク管理ツールです。プロジェクト全体で53992行、1620KBのDartコードがあり、コミュニティのオープンソースライブラリをいくつか使って構築されています。

Quireを作ったのは誰?

このプロジェクトに取りかかる前から、私たちはRikuloチームとして知られるDart愛好家でした。UIフレームワーク、UIライブラリ、ウェブサーバー、メッセージングサーバー、データベースクライアントなど、Dartのライブラリをいくつも公開してきました。

2011年にDartが初めて公開されたとき、その将来性に胸を躍らせ、すぐにプロジェクトの一部でDartを使い始めました。やがて、主にDartで構成される本格的なアプリケーションを作るところまで進みました。ここでは、Dartでの開発に役立つ情報になればと、私たちの経験をささやかながら共有します。

QuireはなぜJavaScriptではなくDartを選んだの?

Dartを選ぶ理由は山ほどあります。なかでも私たちにとって大切だったのは、次の点です。

  • Dartの強力な型システムが、数えきれないほどの小さなミスを防いでくれます。公式IDEのDart Editorは、型エラーをすばやく知らせてくれ、自動補完や追跡のしやすさも備えています。
  • クラスベースの継承モデルは、プロトタイプベースのモデルよりずっと直感的だと考えています。
  • クライアントとサーバーで同じ言語を使え、データモデルもコードベースも共有できます。
  • Dartは、JavaScriptの落とし穴のほとんどを解消しています。完璧ではありませんが、昔からの嫌な驚きの99%には対処しています。
  • Future(promise)やアロー関数など、人気のJavaScript Harmony機能のいくつかを今すぐ使えます。
  • Dartは強力なチームに支えられ、質の高い公式ライブラリや整理されたAPIが多数あります。Dartは進化の途上ですが、仕様はすでにかなり安定しています。
  • サーバー側では、マルチスレッドよりイベントループモデルを好みます。
  • DartはJavaScriptへのコンパイル時にツリーシェイキングを行います。(後述)

Dartを選ぶことには、デメリットもあります。

  • Dartのコミュニティは、JavaScriptのコミュニティよりはるかに小さいです。
  • DartとJavaScriptの間の連携は、簡単ではありません。
  • 強い型付けの言語では、APIのポリフィルが難しくなります。
  • Dart Editorの性能は、大規模なプロジェクトでは(まだ)最適とは言えません。

強い型のサポートがあるので、Dartで書くほうがJavaScriptよりずっと信頼できます。また、DartはJavaよりも冗長さが少なく、関数式などではプレーンなJavaScriptよりも簡潔に書けることがあります。全体として、Dartでの作業は快適ですが、いくつか気になる点もあります。

  • finalフィールドは、コンストラクタ本体より前のイニシャライザで初期化する必要があります。
  • Mixinの仕様はまだ未成熟で、2.0より前に修正されることはなさそうです。
  • 関数宣言にジェネリック型パラメータは使えず、クラスにしか使えません。(もちろん、これはコンパイラの負担を増やします。)

クライアント側でDartはどう動くの?

Dart VMがChromeに搭載されるまでは、製品をJavaScriptにコンパイルして配信することになります。JavaScriptにコンパイルされる言語は数多くありますが、Dartにはいくつかの追加の強みがあります。

  • 開発中は、Dart VMを内蔵したChromium派生のブラウザ、Dartium上でDartをネイティブに実行します。この段階ではコンパイルが要らないため、数えきれない中断を避けられます。
  • テストと本番では、JavaScriptにコンパイルして主要なブラウザすべてで動かします。Dart‐ JavaScriptコンパイラはツリーシェイキングを行い、使われていないコードを出力から取り除きます。これにより、JavaScriptコードのサイズが大幅に減ります。

サーバー側でもDartを使うのはなぜ?

サーバー側のDartは、Dartコミュニティで話題になることがほとんどありませんでした。それでも私たちは、サーバーサイドのプログラミング言語として有力な候補だと考えています。理由は次のとおりです。

  • ウェブサービスは非同期という性質上、(マルチスレッドよりも)イベントループモデルと非常に相性が良いです。
  • サーバー側のコードには、クライアントよりはるかに高い堅牢性とセキュリティが求められます。強い型付けの言語は、この点でとても役に立ちます。

関連記事:QuireがISO認証を取得し、お客様のデータを保護。サーバー側の堅牢性とセキュリティを重視する姿勢は、数年後、Quireの正式なデータ保護認証にも表れています。

QuireはDartスタックでどんなライブラリを使っているの?

Quireは約30件のライブラリインポートで構築されています。そのうち10件はコミュニティ製で、残りはDartチームが公開したものです。Dartに詳しい方ならAngularDARTとPolymer.dartを想像するかもしれませんが、実はどちらも使っていません。

AngularDARTを使っていないのは、次の理由からです。

  • 繊細なDOM制御がしたかったからです。
  • クライアントの構造を独自のアーキテクチャ指針で設計しており、そのパラダイムがAngularのロジックと異なるからです。
  • 調査した時点のAngularDARTは、コンパイル後のJavaScriptコードのサイズに大きなオーバーヘッドがありました。ただし、この点は大きく改善されています。

Polymer.dartも使っていません。理由は次のとおりです。

  • カプセル化とイベントの再ターゲットのため、ShadowDOMはBootstrapのようなセレクタ指向のフレームワークと連携できません。
  • ShadowDOMの外からスタイルを注入することはできません。サードパーティのコンポーネント群がPolymerで作られていると、ユーザーが見た目を変えるのはほぼ不可能です。 更新:2013年12月時点で、外部から内部のスタイルを変更できるようになりました。Shadow DOM 201をご覧ください。

DQueryとBootjackとは?

クライアント側スタックの礎となっているのが、DQueryとBootjackです。どちらもRikuloチームが公開したオープンソースのプロジェクトです。

  • DQueryは、jQueryをDartに部分的に移植したもので、jQueryのイベントデリゲーションの仕組みに焦点を当てています。
  • Bootjackは、Bootstrap 3の完全な移植で、CSSとAPIはほぼ同一です。

このようにアプリケーションスタックを組んだのは、JavaScriptの世界で培った知識とスキルを活かすためです。

Streamウェブサーバーとは?

Streamは私たちのウェブサーバーで、純粋なDartで書かれ、ルーティング、フィルター、サーバーサイドMVCなどの機能を備えています。Streamはイベントループモデルとなめらかに連携します。リクエストハンドラを書くことは、ノンブロッキングの処理を順につなげるだけです。

従来のマルチスレッドモデルより生産的で、作業していても楽しいです。ウェブサービスのスケーリングとHTTPSの処理はnginxで行い、リクエストをStreamへ引き渡しています。この構成なら、Dart VMを個別に起動・停止でき、ユーザーの操作を止めずにサーバーをアップグレードできます。

まとめ

Dartでの開発は楽しい経験で、Dartコミュニティのさらなるワクワクする発展を楽しみにしています。最後に、Dartで何ができるのか気になる方は、私たちのアプリQuireで実際に試してみてください。無料です。

続きはこちら:QuireがMark IIとして再構想・再構築された経緯

Dartによるクライアントとサーバーの実装を示すQuireのアーキテクチャ図

2014年のこの構築から、2026年にも通用する教訓は?

この記事が書かれてから、DartもQuireのコードベースも大きく進化しました。2018年にはDart 2.0(健全な型システム)、2023年にはDart 3.0(null安全性、レコード、パターン)が登場しました。また、Flutterがクロスプラットフォーム UIの勢力図を変えました(Quire自身のモバイルチームもFlutterに移行しました)。それでも、上で紹介した設計上の判断は、思いのほか長く通用しています。

クライアントとサーバーを貫く強い型付けは、今も効果があります。 強い型システムがビルド時に捉える実行時エラーは、今も同じ種類のエラーです。JavaScriptはTypeScriptによって型付けへ部分的に近づきましたが、エンドツーエンドで完全に型付けされたスタックは今も珍しい存在です。Simonが挙げた数えきれない小さなミスは、型のないスタックが本番環境へ持ち込むバグの典型です。

クライアントとサーバーで共有するデータモデルは、今も作業を減らします。 データモデルの複製の問題(JSとPythonに別々のモデルがあり、気づかないうちにずれていく)は、2014年も2026年も同じです。解決策(エンドツーエンドで1つの言語を使う)も同じです。Node上でTypeScriptを使うチームがQuireのようなアーキテクチャを組むのは、まさにこの理由からです。

ウェブサーバーでは、マルチスレッドよりイベントループが今も優勢です。 Node、Deno、Bun、そしてDart自身のStreamパターンも、この点で一致しています。この議論は数年おきに蒸し返されますが、行き着く先はいつも同じです。

ツリーシェイキングは、重要性が薄れるどころか増しています。 2014年には、Dartのツリーシェイキングコンパイラは差別化要因でした。2026年の今では、JSを対象とするビルドパイプラインなら当たり前の機能です。Webpack、Rollup、esbuild、Viteもすべて対応しています。教訓は今も有効で、ツールが追いついたということです。

2014年当時のShadowDOMへの懸念は、ほぼ解消しました。 Polymer.dartは廃止され、Web Componentsは成熟しました。Simonが挙げたPolymerを避けた理由(スタイルの注入、フレームワークとの連携)は、やがてプラットフォーム側で解決されました。本番アプリの中核には最先端のフレームワークを避けるという一般原則は、2026年の今も、その時々の「注目の」フレームワークにそのまま当てはまります。

関連記事:制作の舞台裏:Flutterベースのモバイルタイムライン。Quireのモバイルチームが、Flutterでタイムライン表示を作った様子を紹介しています。

大規模Webアプリの言語選びで、よくある失敗は?

複数年にわたるアプリケーションの言語スタックを選ぶことは、後から変えるのに高いコストがかかる数少ないエンジニアリング上の判断のひとつです。チームが失敗するとき、次の4つのパターンがよく見られます。

1. 最大のコミュニティを持つ言語を、何となく選んでしまう。 JavaScriptのコミュニティは最大ですが、「最大」は「課題に最も合う」と同じ意味ではありません。強い型システムと優れたツールを備えた、小さなコミュニティの言語が、保証の弱い巨大なエコシステムを上回ることもあります。コミュニティの規模は重要ですが、唯一の判断基準ではありません。

2. クライアントとサーバーで言語を分けたスタックを選んでしまう。 重複したデータモデルは、すべてバグの種です。サーバーにRuby、クライアントにJSを使うチームは、そのコストを払い続けます。両側で1つの言語(Dart、TypeScript、Kotlin)を共有するチームは、バグの種類をまるごと避けられます。

3. 安定する前の最先端技術を採用してしまう。 Quireのチームは2014年、AngularDARTとPolymer.dartのどちらにも設計上の未解決の問題があったため、採用を見送りました。

AngularDARTは大きく方向転換し、Polymerは廃止されました。一般的なルール(アプリの中核を賭ける前に、大規模な本番環境でフレームワークの実績を確かめる)は、2026年の今も、その時々の「注目の」フレームワークに当てはまります。

4. 目先のスピードのために、型システムを省いてしまう。 型のない言語は、最初の1週間は速く感じられます。ところが6か月も経てば、節約した時間は、デバッグの時間として何倍にもなって返ってきます。型なしと型ありのスタックを大規模に経験したエンジニアリングチームが、自ら進んで元に戻ることはほとんどありません。

2014年のQuireチームのDartへの賭けが、今になって妥当に見えるのは、Dartが主流になったからではありません(主流にはなりませんでした)。その根底にあった基準(型付け、クライアントとサーバーの共有、イベントループ、ツリーシェイキング)が、その後の10年で業界の共通認識になったからです。

時を経ても色あせなかったのは、個別のツール選びではなく、根底にあるエンジニアリングの原則でした。不確実な状況で行う言語選びは、たいていこの傾向に当てはまります。今測れる人気ではなく、10年先でも説明できる原則で選びましょう。

Quireプロジェクト管理ソフトウェアを使う10万以上のチームに仲間入り。無料で登録

よくある質問

Quireは何の言語で構築されていますか?

クライアントとサーバーの両方でDartです。アプリケーションはDartコードで約54,000行、ライブラリのインポートは約30件です。

QuireはなぜJavaScriptやTypeScriptではなくDartを選んだのですか?

強い型付け、クラスベースの継承モデル、そしてクライアントとサーバーで共通の1つの言語という理由です。また、DartはJavaScriptが広く対応する前に、いくつかのモダンな機能を提供していました。

QuireはなぜAngularDARTやPolymer.dartを使わなかったのですか?

チームは、AngularDARTのバインディングが許す以上に細かいDOM制御を求めており、QuireのアーキテクチャパターンもAngularのロジックと合いませんでした。Polymer.dartを避けたのは、当時ShadowDOMがBootstrap型のセレクタと衝突していたためです。Polymerはその後廃止され、この判断が正しかったことが裏づけられました。

DQueryとBootjackとは何ですか?

Rikuloチーム(Quireのエンジニアリングチーム)が公開したオープンソースライブラリです。DQueryはjQueryのDartへの部分的な移植で、イベントデリゲーションに焦点を当てています。BootjackはBootstrap 3の完全な移植で、CSSとAPIはほぼ同一です。

QuireのスタックにおけるStreamとは何ですか?

Quireのウェブサーバーで、純粋なDartで書かれ、イベントループモデルを採用しています。ルーティング、フィルター、サーバーサイドMVCを標準で備えています。QuireはStreamをnginxの背後で動かしており、スケーリングとHTTPSはnginxが処理します。

Simon Pai
Co-Founder at Bookshow