features · Sep 3, 2014

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

AI翻訳
· 英語版を見る

My helpful screenshot

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

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

Quire は Dart で書かれた最初の Web アプリケーションではなく、最後のものでもありませんが、クライアントとサーバーの両側で Dart にこれほど大きく依存したアプリは、おそらく初めてでしょう。

My helpful screenshot

階層構造を核に据えた、楽しいタスク管理ツールです。プロジェクト自体は 53,992 行、1,620 KB の Dart コードで構成され、コミュニティ発のオープンソースライブラリをいくつか活用して作られています。

Quire を作ったのは誰か?

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

2011 年に Dart が初めて発表された際、私たちは皆その将来性に胸を躍らせ、すぐに小規模なプロジェクトの一部で Dart を使い始めました。そして最終的に、Dart を主軸とした本格的なアプリケーションの構築に踏み出すことになりました。ここでは、私たちの経験の一端をささやかながら共有し、Dart 開発に関する手がかりをお届けできればと思います。

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

Dart を選ぶ理由はいくらでもありますが、私たちにとって特に大きかったのは次の点です。

  • Dart の強い型システムが、無数の小さなミスから私たちを守ってくれます。公式 IDE である Dart Editor は、型エラーに対する素早いフィードバックや自動補完を提供し、追跡も容易にしてくれます。
  • クラスベースの継承モデルは、プロトタイプベースのものよりずっと直感的だと考えています。
  • クライアントとサーバーで同じ言語を使い、データモデルやコードベースを共有できる機会を Dart はもたらしてくれます。
  • Dart は JavaScript の落とし穴のほとんどを解消しています。完璧とは言えませんが、昔ながらの厄介な驚きの 99% は確実にカバーしてくれます。
  • Future(Promise)やアロー関数など、JavaScript Harmony の人気機能のいくつかが Dart では今すぐ使えます。
  • Dart は強力なチームに支えられており、品質の高い公式ライブラリや整理された API が揃っています。Dart はまだ進化の途上にありますが、仕様はすでにかなり安定しています。
  • サーバー側では、マルチスレッドよりもイベントループモデルの方が好ましいと考えています。
  • Dart は JavaScript にコンパイルする際、ツリーシェイキングを行います(後述)。

一方で、Dart を選ぶことには欠点もあります。

  • Dart のコミュニティは JavaScript コミュニティに比べてはるかに小規模です。
  • Dart と JavaScript の相互運用は決して容易ではありません。
  • 強く型付けされた言語では、API のポリフィルを書くのがより難しくなります。
  • Dart Editor の動作は、大規模なプロジェクトではまだ最適とは言えません。

強い型サポートに支えられているおかげで、Dart でのコーディングは JavaScript よりずっと信頼性が高まります。また Dart は Java ほど冗長ではなく、(たとえば関数式を使うような場面では)プレーンな JavaScript よりさらに簡潔になることすらあります。総じて Dart で開発するのは快適ですが、いくつか気になる点もあります。

  • final フィールドは、コンストラクタ本体よりも前のイニシャライザで初期化しなければなりません。
  • ミックスインの仕様はまだ未成熟で、2.0 までは修正されない見込みです。
  • 関数宣言にはジェネリック型パラメータを付けられず、クラスにしか使えません(もちろん、対応するとコンパイラの負荷は増えるでしょう)。

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

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

  • 開発時には、Chromium をフォークして Dart VM を組み込んだブラウザ Dartium 上で Dart をネイティブに実行します。このサイクルではコンパイルが不要なので、数えきれないほどの中断から解放されます。
  • テストや本番環境では JavaScript にコンパイルし、主要なすべてのブラウザで動かします。Dart の JavaScript コンパイラはツリーシェイキングを行い、未使用のコードを成果物から取り除きます。これによって JavaScript のコードサイズが大幅に削減されます。

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

サーバーサイドの Dart は Dart コミュニティでも決して人気のテーマではありませんが、私たちはサーバーサイド言語として Dart には十分な可能性があると考えています。理由は次のとおりです。

  • Web サービスは本質的に非同期であり、(マルチスレッドよりも)イベントループモデルと非常に相性が良いです。
  • サーバーサイドのコードはクライアント以上に堅牢性とセキュリティが求められます。そこで強く型付けされた言語が本領を発揮します。

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 Web サーバーとは?

Stream は私たちの Web サーバーで、純粋な Dart で書かれており、ルーティングやフィルタ、サーバーサイド MVC などの機能を備えています。Stream はイベントループモデルとスムーズに噛み合います。リクエストハンドラを書くというのは、ノンブロッキングなルーチンを連鎖させていくだけのことです。従来のマルチスレッドモデルよりも生産的であるだけでなく、書いていて気持ちが良いものです。また、サービスのスケーリングや HTTPS の処理は nginx に任せ、リクエストを Stream に委譲する構成にしています。このアーキテクチャのおかげで、Dart VM を個別に起動・停止し、ユーザーの操作を中断することなくサーバーをアップグレードできます。

まとめ

Dart での開発は楽しい経験であり、Dart コミュニティのさらなる発展を心待ちにしています。最後に、Dart で何ができるのか気になった方は、ぜひ私たちのアプリ Quire を触ってみてください。無料です!

My helpful screenshot

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

この記事を書いてから、Dart 言語と Quire のコードベースはいずれも大きく進化しました。Dart 2.0(健全な型システム)は 2018 年に、Dart 3.0(null 安全、レコード、パターン)は 2023 年に登場し、Flutter はクロスプラットフォーム UI の景色を一変させました。それでもなお、ここまで紹介したアーキテクチャ上の判断は、思っている以上にしっかりと持ちこたえています。

クライアントとサーバーをまたぐ強い型付けは、今も投資に見合うリターンをもたらします。 強い型システムがビルド時に捕まえるランタイムエラーは、今もまったく同じランタイムエラーです。JavaScript は TypeScript を通じて型付けに歩み寄りましたが、エンドツーエンドで完全に型付けされたスタックは依然として珍しい存在です。Simon が挙げていたバグ群(無数の小さなミス)は、今もなお、型のないスタックが本番に運んでしまうバグ群そのものです。

クライアントとサーバーでデータモデルを共有するアプローチは、今も工数を削減してくれます。 モデルが重複する問題(JS と Python で別々に書かれ、いつの間にかずれていく)は、2026 年でも 2014 年と変わりません。その解決策(端から端まで 1 つの言語で揃える)も同じです。TypeScript と Node を組み合わせるチームが Quire 風のアーキテクチャを採るのは、まさにこのためです。

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

ツリーシェイキングの重要性は、減るどころかむしろ増しています。 2014 年当時、Dart のツリーシェイキング対応コンパイラは大きな差別化要素でした。2026 年の現在、JS をターゲットとするビルドパイプラインなら備わっていて当然の機能です。Webpack、Rollup、esbuild、Vite はいずれも対応しています。教訓は変わらず、ツール群が後から追いついてきた形です。

2014 年に懸念されていた ShadowDOM の問題は、ほぼ解消されました。 Polymer.dart は非推奨となり、Web Components は成熟しました。Simon が Polymer を避けた理由(スタイルの注入、他フレームワークとの協調)は、最終的にプラットフォーム側で解決されています。一般原則(本番アプリの中核には、登場間もない先端フレームワークを使わない)は、2026 年でも、今まさに「期待のフレームワーク」として注目されているどのフレームワークにも当てはまります。

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

数年単位で動かすアプリケーションのスタック選定は、覆そうとすると割に合わなくなる、数少ないエンジニアリング判断のひとつです。チームが選択を誤るとき、必ず似た 4 つのパターンが現れます。

1. ともかくコミュニティが最大の言語を選ぶ。 JavaScript のコミュニティは確かに最大ですが、「最大」と「自分たちの課題への最適解」は別物です。強い型システム、優れたツール、そして規模は小さくても堅実なコミュニティを持つ言語は、巨大でも保証の弱いエコシステムを上回ることがあります。コミュニティの規模は重要ですが、それがすべてではありません。

2. クライアントとサーバーで言語が分かれるスタックを選ぶ。 データモデルが重複するたびに、そこは将来のバグの温床になります。サーバーに Ruby、クライアントに JS というチームは、そのコストを永遠に背負い続けます。クライアントとサーバーの両側で 1 つの言語を共有するチーム(Dart、TypeScript、Kotlin)は、丸ごと 1 種類のバグから解放されます。

3. 安定化を待たずに先端技術へ飛びつく。 Quire のチームが 2014 年に AngularDART や Polymer.dart を避けたのは、どちらにもアーキテクチャ面の未解決の問いがあったからです。AngularDART はその後大きく方向転換し、Polymer は非推奨になりました。一般則(自社アプリの中核を賭ける前に、まずそのフレームワークが本番規模で実績を示すのを待つ)は、2026 年でも、いまホットな「期待のフレームワーク」にそのまま当てはまります。

4. 短期的なスピードのために型システムを省く。 型なしの言語は最初の 1 週間は確かに速く感じます。半年が過ぎる頃には、その時に節約した時刻は、デバッグの時刻として何倍にもなって返ってきます。型なしと型ありのスタックを大規模に経験したエンジニアリングチームが、自ら進んで型なしに戻ることはまずありません。

Quire チームが 2014 年に Dart へ賭けたことが振り返って妥当に映るのは、Dart が支配的になったからではなく(実際そうはなりませんでした)、その背後にある判断軸(型付き、クライアントとサーバーで共有、イベントループ、ツリーシェイキング)が、フォロー中の 10 年で業界の共通認識となったからです。長く価値を保ったのは、特定のツールの選択そのものではなく、その下にあるエンジニアリング原則でした。このパターンは、不確実さのなかで言語を選ぶときにはたいてい当てはまります。今日測れる人気ではなく、10 年先でも擁護できる原則を基準に選ぶべきなのです。

よくあるご質問

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

クライアントとサーバーの両側で Dart を使用しています。アプリケーションは約 54,000 行の Dart コードで構成され、約 30 のライブラリをインポートしています。

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

強い型付け、クラスベースの継承モデル、そしてクライアントとサーバーで言語を統一できる点が決め手です。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 とは何ですか?

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

Simon Pai
Co-Founder at Bookshow