플러터의 빠진 조각: 풀스택 Dart가 모든 것을 바꾸는 이유

플러터의 빠진 조각: 풀스택 Dart가 모든 것을 바꾸는 이유

Firebase용 Cloud Functions에서 Dart를 지원하게 되면서, 이제 전체 스택을 하나의 통합된 애플리케이션처럼 다룰 수 있게 됐어요.

출처: The Flutter missing link: Why full-stack Dart changes everything

본문

오랫동안 Flutter 개발자들은 분리된 아키텍처 현실 속에서 살아왔어요. Dart를 써서 고성능이고 아름다운 프론트엔드를 만들죠. 안정적인 타입 시스템과 표현력 좋은 문법을 십분 활용하면서요. 그런데 그 로직을 클라우드로 확장해야 하는 순간, "언어 불일치"라는 벽에 부딪히게 돼요. 갑자기 TypeScript, Go, Python 같은 다른 언어로 맥락을 전환해야 하고, 서로 다른 동시성 모델을 오가며 데이터 구조를 손수 이식해야 하죠. 이런 마찰은 단순한 불편함에 그치지 않아요. "이중 문서화 부담(Double-Doc Tax)"이라는 큰 비용을 만들어 내요. 팀이 로직과 문서를 두 번씩 동기화해야 하니까, 프로젝트의 소중한 개발 시간을 사실상 빼앗기는 셈이에요.

하지만 Firebase용 Cloud Functions에서 Dart를 실험적으로 지원한다는 발표와 함께, 그런 아키텍처 마찰의 시대는 막을 내리고 있어요. 이제 처음으로, 우리는 전체 스택을 하나의 통합된 애플리케이션으로 다룰 수 있게 됐어요.

모든 것을 지배하는 하나의 언어

이번 변화에서 가장 혁신적인 부분은 "공유 패키지(Shared Package)" 패턴이에요. 비즈니스 로직과 데이터 모델을 독립된 Dart 패키지로 옮기면, 전통적인 스택을 괴롭히던 수동 중복을 없앨 수 있어요. 공유 패키지에서 필드를 하나 수정하면, 그 변경이 즉시 전체 스택으로 전파돼요. 이 구조 덕분에 검증 규칙이 클라이언트와 서버에서 동일하게 유지되고, 여러 언어에 걸친 구현에서 비롯되는 오류도 사라져요.

공통 Dart 패키지에서 데이터 모델과 검증 규칙을 공유하면, 프론트엔드와 백엔드가 항상 동기화된 상태를 유지할 수 있어요.

"이중 문서화 부담"을 없애는 것은 생산성 측면에서 큰 승리예요. firebase_functions 패키지를 쓰고 모델을 공유하면, 팀끼리 동기화에 시간을 낭비하는 대신 기능을 만드는 데 바로 집중할 수 있어요.

"워밍업" 없는 성능

서버리스 환경, 특히 "제로로 스케일링(Scale-to-Zero)"되는 환경에서는 콜드 스타트(함수가 처음 실행될 때 걸리는 시간)가 성능을 좌우해요. Node.js나 Java 같은 전통적인 런타임은 무거운 가상 머신이나 JIT(Just-In-Time) 워밍업 시간이 필요하곤 하죠. Dart는 AOT(Ahead-of-Time) 컴파일로 이 방정식을 바꿔요. 날씬한 네이티브 바이너리로 직접 컴파일되기 때문에, Dart 함수는 아주 빠르게 살아나요.

전통적인 SDK는 211MB에 달할 수 있는 반면, 네이티브 Dart 바이너리는 10MB까지도 작아질 수 있어요. Dart는 비동기·이벤트 기반 아키텍처를 쓰기 때문에, 데이터베이스 쿼리나 API 요청 같은 I/O 중심 서버리스 작업을 대규모 스레드 풀 오버헤드 없이 매우 효율적으로 처리해요.

Dart 바이너리는 워밍업 없이 즉시 실행돼요. 무려 10밀리초 정도로 빨라요.

이제 컨테이너는 선택 사항

모바일 개발자들이 백엔드로 전환할 때 가장 큰 벽으로 여겼던 것 중 하나는, Dockerfile을 작성하고 컨테이너 레지스트리를 관리하며 Linux 환경을 설정해야 하는 인프라 부담이었어요. Firebase CLI는 이제 이 복잡성을 완전히 추상화해 줘요. 단 한 줄의 명령으로, CLI가 컴파일과 Google Cloud 인프라 배포라는 무거운 작업을 모두 처리해 줘요.

파워 유저를 위한 숨은 '프로 팁'도 있어요. Dart 툴체인은 매끄러운 크로스 컴파일을 지원해요. Mac이나 Windows 머신에서 바로 Linux 64비트 바이너리를 컴파일할 수 있고, CLI가 그 바이너리를 Cloud Run에 업로드해 줘요.

> dart compile exe bin/server.dart --target-arch x64 --target-os linux
Generated: /Users/user1/dart_server/bin/server.exe
> ls -l bin/server.exe
.rwxr-xr-x@ 7.8M user1 15 May 13:00 -I  bin/server.exe

반복하는 개발 루프

Flutter 개발자들이 가장 아끼는 기능은 "핫 리로드(Hot Reload)"예요. 네이티브 Dart 지원은 비슷한 철학을 백엔드로 가져오는데, 바로 Firebase 로컬 에뮬레이터 스위트(Firebase Local Emulator Suite)죠. 이 스위트는 완전한 오프라인 환경을 제공해서, 백엔드 경험이 마침내 Dart 개발자에게 "네이티브"처럼 느껴지게 해 줘요.

덕분에 Firestore나 Auth 상호작용을 포함한 엔드투엔드 애플리케이션을, 코드 한 줄이 프로덕션에 도달하기 전에 거의 즉각적인 피드백을 받으며 테스트할 수 있어요.

실험적인 Admin SDK

이 작업의 토대는 새로운 Firebase Admin SDK예요. Cloud Functions 안에서는 Firestore 같은 서비스에 안전하게 접근하도록 자동 초기화되지만, 그 잠재력은 훨씬 더 커요. pub.dev에서 제공되기 때문에 "Functions"에만 묶여 있지 않아요. Cloud Run, Compute Engine, 심지어 로컬 머신에서도 실행할 수 있는 다재다능한 서버 사이드 라이브러리예요. 이 패키지는 Dart가 강력하고 범용적인 서버 사이드 언어로 진화하는 한 걸음이에요.

풀스택의 미래

이것이 Flutter 생태계의 근본적인 변화를 의미하긴 하지만, 아직 실험 단계라는 점은 알아두셔야 해요. 시작하려면 Dart SDK 3.9 이상과 Firebase CLI v15.15.0 이상이 필요해요. 현재는 HTTPS 함수와 호출 가능(callable) 함수에 대한 지원이 중점적으로 제공돼요.

클라이언트와 클라우드 사이의 분리를 없애는 것은 개발 속도 면에서 큰 도약이에요. 통합된 스택을 쓰면 엔드투엔드 시스템을 최대 효율로 구축할 수 있고, 생산성이 높은 워크플로의 길을 열며 Dart가 서버에서 새로운 가능성을 발휘할 수 있게 돼요.

첫 Dart Cloud Functions를 만들어 보고 싶다면 Cloud Functions for Firebase 문서를 확인해 보세요. Cloud Run을 이용해 Dart Cloud Function을 배포하고 싶다면 이 샘플 앱을 살펴보세요.

더 알아보기

  • Cloud Functions for Firebase 문서에서 Dart Cloud Functions 시작하기를 확인할 수 있어요.
  • Cloud Run을 활용한 Dart Cloud Function 배포 샘플 앱을 살펴보세요.