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로 만든 첫 번째 웹 애플리케이션도, 마지막 애플리케이션도 아니겠지만, 클라이언트와 서버 양쪽에서 이렇게까지 Dart에 의존한 앱으로는 처음일 수 있습니다.

Quire 웹 애플리케이션의 Dart 프로그래밍 언어 로고와 프레임워크

트리 구조를 핵심으로 삼은 재미있는 업무 관리 도구입니다. 이 프로젝트는 커뮤니티의 오픈소스 라이브러리 몇 가지를 활용해 만든 53,992줄, 1,620KB 분량의 Dart 코드로 이루어져 있습니다.

Quire는 누가 만들었나요?

이 프로젝트를 시작하기 전부터 저희는 Rikulo 팀이라는 이름의 Dart 애호가였습니다. UI 프레임워크, UI 라이브러리, 웹 서버, 메시징 서버, 데이터베이스 클라이언트 등 여러 Dart 라이브러리를 공개해 왔습니다.

2011년 Dart가 처음 나왔을 때 그 미래 가치에 모두 들떴고, 곧바로 작은 프로젝트 일부에 Dart를 적용하기 시작했습니다. 그러다 결국 Dart가 대부분을 차지하는 완전한 애플리케이션을 만들기에 이르렀습니다. 저희의 경험을 겸손하게 나누어, Dart 개발에 참고가 되기를 바랍니다.

Quire는 왜 JavaScript 대신 Dart를 선택했나요?

Dart를 선택할 이유는 아주 많습니다. 그중 저희에게 가장 중요했던 이유는 다음과 같습니다.

  • Dart의 강한 타입 시스템은 수많은 사소한 실수를 막아 줍니다. 공식 IDE인 Dart Editor는 타입 오류에 대한 빠른 피드백과 자동 완성을 제공하고, 추적도 더 쉽게 해 줍니다.
  • 클래스 기반 상속 모델이 프로토타입 기반 모델보다 훨씬 직관적이라고 생각합니다.
  • Dart는 클라이언트와 서버에서 같은 언어를 쓸 수 있어서, 같은 데이터 모델과 코드 베이스를 공유할 수 있습니다.
  • Dart는 JavaScript의 함정 대부분을 해결했습니다. 완벽하지는 않지만, 예전의 고약한 놀라움 중 99%는 처리해 줍니다.
  • Dart는 인기 있는 JavaScript Harmony 기능 몇 가지를 지금 바로 쓸 수 있게 해 줍니다. Future(promise), 화살표 함수 등이 그렇습니다.
  • 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-to-JavaScript 컴파일러는 트리 셰이킹으로 결과물에서 사용하지 않는 코드를 제거합니다. 덕분에 JavaScript 코드 크기가 크게 줄어듭니다.

서버 측에서도 Dart를 쓰는 이유는 무엇인가요?

서버 측 Dart는 Dart 커뮤니티에서 뜨거운 주제였던 적이 없지만, 저희는 Dart가 서버 측 프로그래밍 언어의 유력한 후보라고 생각합니다. 이유는 다음과 같습니다.

  • 웹 서비스는 비동기적인 특성상 (멀티스레딩보다) 이벤트 루프 모델과 아주 잘 맞습니다.
  • 서버 측 코드는 클라이언트보다 훨씬 높은 견고성과 보안이 필요합니다. 강한 타입 언어가 이럴 때 큰 도움이 됩니다.

관련 글: Quire, 데이터를 보호하는 ISO 인증 획득 — 서버 측 견고성과 보안을 중시하는 같은 태도는 수년 뒤 Quire의 공식 데이터 보호 인증으로 이어졌습니다.

Quire는 Dart 스택에서 어떤 라이브러리를 사용하나요?

Quire에는 약 30개의 라이브러리 import가 있으며, 그중 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의 이벤트 위임 시스템에 초점을 맞춰 jQuery를 Dart로 부분 포팅한 것입니다.
  • Bootjack은 거의 동일한 CSS와 API를 갖춘 Bootstrap 3의 완전한 포팅입니다.

이렇게 애플리케이션 스택을 구성해, JavaScript 세계에서 쌓은 지식과 기술을 그대로 활용했습니다.

Stream 웹 서버는 무엇인가요?

Stream은 순수 Dart로 작성한 저희 웹 서버로, 라우팅, 필터, 서버 측 MVC 등의 기능을 갖추고 있습니다. Stream은 이벤트 루프 모델과 매끄럽게 동작합니다. 요청 핸들러를 작성하는 일은 논블로킹 루틴을 차례로 연결하는 것이 전부입니다.

기존 멀티스레딩 모델보다 생산성이 높을 뿐 아니라 작업하는 즐거움도 더 큽니다. 또한 nginx로 웹 서비스를 확장하고 HTTPS를 처리하며, 요청을 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 safety, 레코드, 패턴)이 나왔고, Flutter는 크로스 플랫폼 UI 환경을 바꿔 놓았습니다.

(Quire의 모바일 팀도 Flutter로 전환했습니다.) 하지만 위에서 다룬 아키텍처 결정들은 예상보다 훨씬 잘 버티고 있습니다.

전 계층의 강한 타입은 여전히 값어치를 합니다. 강한 타입 시스템이 빌드 단계에서 잡아내는 런타임 오류는 지금도 똑같은 오류입니다.

JavaScript는 TypeScript를 통해 타입 쪽으로 어느 정도 다가갔지만, 처음부터 끝까지 타입이 갖춰진 스택은 여전히 드뭅니다. Simon이 짚은 버그의 부류(수많은 사소한 실수)는 타입 없는 스택이 지금도 운영 환경까지 끌고 가는 바로 그 부류입니다.

클라이언트와 서버의 공유 데이터 모델은 여전히 작업을 줄여 줍니다. 데이터 모델 사본 생성하기 문제(JS에 하나, Python에 하나를 두고 조용히 어긋나는 상황)는 2026년에도 2014년과 같습니다. 해법(처음부터 끝까지 한 언어)도 같습니다. 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로 타임라인 뷰를 만든 과정을 살펴봅니다.

대규모 웹 앱의 언어를 고를 때 가장 흔한 실수는 무엇인가요?

수년간 운영할 애플리케이션의 언어 스택을 고르는 일은 되돌리는 데 큰 비용이 드는 몇 안 되는 엔지니어링 결정입니다. 팀이 잘못 고를 때는 네 가지 패턴이 반복됩니다.

1. 커뮤니티가 가장 크다는 이유로 기본 선택하기. JavaScript의 커뮤니티가 가장 크지만, "가장 크다"는 것이 "내 문제에 가장 잘 맞는다"는 뜻은 아닙니다. 강한 타입 시스템과 좋은 도구를 갖춘 작은 커뮤니티의 언어가, 보장이 약한 방대한 생태계보다 나은 성과를 낼 수 있습니다. 커뮤니티 규모는 중요하지만 유일하게 중요한 것은 아닙니다.

2. 클라이언트와 서버의 언어가 갈라지는 스택 고르기. 중복된 데이터 모델은 모두 터질 날을 기다리는 버그입니다. 서버는 Ruby, 클라이언트는 JS로 출시하는 팀은 그 비용을 영원히 치릅니다. 두 영역에서 한 언어(Dart, TypeScript, Kotlin)를 공유하는 팀은 버그의 한 부류를 통째로 피합니다.

3. 안정되기 전에 최신 기술 도입하기. Quire 팀은 2014년에 AngularDART와 Polymer.dart를 피했습니다. 둘 다 아키텍처상의 미해결 문제가 있었기 때문입니다.

AngularDART는 크게 방향을 틀었고 Polymer는 지원이 중단되었습니다. 앱의 핵심을 걸기 전에 프레임워크가 대규모 운영 환경에서 검증되기를 기다리라는 일반 원칙은 지금 "가장 주목받는" 프레임워크가 무엇이든 2026년에도 그대로 적용됩니다.

4. 단기 속도를 위해 타입 시스템 건너뛰기. 타입 없는 언어는 첫 주에는 더 빠르게 느껴집니다. 하지만 여섯 달쯤 지나면 아낀 시간은 디버깅 시간으로 모두 돌려주고도 남습니다. 타입 없는 스택과 타입 있는 스택을 대규모로 모두 겪어 본 엔지니어링 팀은 자발적으로 되돌아가는 일이 거의 없습니다.

Quire 팀의 2014년 Dart 선택이 돌이켜 보아 합리적인 것은 Dart가 주류가 되어서(그렇지 않았습니다)가 아닙니다. 그 근거였던 기준(타입, 클라이언트와 서버의 공유, 이벤트 루프, 트리 셰이킹)이 이후 10년 동안 업계의 공감대가 되었기 때문입니다.

세월이 지나도 빛이 바래지 않은 것은 특정 도구가 아니라 그 밑에 깔린 엔지니어링 원칙이었습니다. 불확실한 상황에서 내리는 언어 선택은 대개 마찬가지입니다. 오늘 측정할 수 있는 인기보다, 10년 뒤에도 옹호할 수 있는 원칙을 기준으로 고르세요.

10만 개 이상의 팀이 사용하는 Quire 프로젝트 관리 소프트웨어, 무료로 가입하세요

자주 묻는 질문

Quire는 어떤 언어로 만들어졌나요?

클라이언트와 서버 모두 Dart입니다. 애플리케이션은 약 54,000줄의 Dart 코드이며 라이브러리 import는 약 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은 거의 동일한 CSS와 API를 갖춘 Bootstrap 3의 완전한 포팅입니다.

Quire 스택에서 Stream은 무엇인가요?

순수 Dart로 작성되어 이벤트 루프 모델을 사용하는 Quire의 웹 서버입니다. 라우팅, 필터, 서버 측 MVC가 기본으로 들어 있습니다. Quire는 nginx 뒤에서 Stream을 운영하며, nginx가 확장과 HTTPS를 처리합니다.

Simon Pai
Co-Founder at Bookshow