Dart가 만들어진 이유, 목표로 삼은 실제 문제들, 런타임·툴링·Flutter 통합이 현대 모바일 앱에서 빠르고 부드러운 UI를 어떻게 가능하게 하는지 알아보세요.

Dart는 Google이 만든 현대적인 프로그래밍 언어로, 부드러운 사용자 인터페이스에 중점을 둔 앱을 만드는 데 사용됩니다. 대부분의 사람들은 Flutter를 통해 Dart를 접합니다. Flutter로 만들어진 모바일 앱을 사용해본 적이 있다면 그 UI와 많은 앱 로직이 Dart로 작성되어 있을 가능성이 큽니다. 개발자들이 Dart에 주목하는 이유는 UI 작업에 맞춰 설계된 것처럼 느껴지기 때문입니다—빠르게 반복할 수 있고, 읽기 쉽고, 예측 가능한 성능으로 배포할 수 있도록 설계되었습니다.
iOS와 Android에서 동일한 UI 동작과 잦고 다듬어진 업데이트를 제공하는 앱이라면 Flutter 앱일 수 있고, 이는 보통 내부적으로 Dart가 사용된다는 뜻입니다. 팀들은 응답성을 포기하지 않으면서 여러 플랫폼에 대해 단일 코드베이스를 원할 때 Dart를 선택합니다.
Dart는 실제 앱 개발과 밀접하게 일치하는 몇 가지 실용적 목표를 가지고 만들어졌습니다:
이 글은 Dart가 왜 만들어졌는지, 현대 모바일 앱에서 어떤 문제를 해결하려 하는지, 그리고 실무에서 Flutter를 어떻게 구동하는지를 설명합니다. 개발 환경과 배포 환경에서의 실행 방식, UI를 멈추지 않게 비동기 작업을 처리하는 방법, 시간이 지나도 버그와 유지비용을 줄이는 언어 기능들을 다룹니다.
Dart는 대화형 앱을 만들 때 팀들이 느끼던 공백을 메우기 위해 만들어졌습니다. 풍부한 UI를 갖춘 앱이 빠르게 로드되고 부드럽게 동작하며, 성장해도 유지보수가 쉬워야 한다는 니즈가 있었습니다.
당시 개발자들은 빠른 스크립팅과 프로토타이핑에 적합한 언어와 대규모 코드베이스와 장기 유지보수에 적합한 언어 사이에서 선택해야 하는 경우가 많았습니다. Dart의 목표는 작은 데모에서 대형 제품까지 강제적인 재작성 없이 확장 가능한, 현대적이고 접근성 좋은 언어를 제공하는 것이었습니다.
Dart의 설계는 실용적인 질문에서 출발했습니다: 사용자 대상 애플리케이션—반응형 인터페이스, 잦은 상태 업데이트, 애니메이션, 네트워킹, 지속적 기능 작업을 필요로 하는 앱—을 만들 때 언어는 어떻게 생겨야 할까?
그 결과 예측 가능한 성능, 강력한 툴링, 깔끔하고 읽기 쉬운 코드를 장려하는 생태계에 초점을 맞추게 되었습니다. 중요한 점은, Dart는 Java, JavaScript, C 계열 언어에서 오는 개발자들이 빠르게 생산성을 낼 수 있을 만큼 친숙하게 설계되었다는 것입니다.
Dart는 다음과 같은 목표를 향해 설계되었습니다:
이 목표들은 강력한 표준 라이브러리, 구조화된 비동기 모델, 오류를 더 빨리 잡아내는 기능 같은 언어 결정들에 영향을 미쳤습니다.
Dart는 원래부터 "Flutter를 위해" 만들어진 것은 아니었습니다. 그러나 Flutter는 Dart의 목표와 매우 잘 맞는 제품으로 등장했고, 그 결과 Dart는 많은 모바일 개발자에게 널리 알려지게 되었습니다—빠른 개발자 반복, UI 중심 앱, 확장 가능한 가독성 있는 코드라는 요구에 부합했기 때문입니다.
Dart는 단순히 "또 하나의 언어"가 되기 위해 만들어진 것이 아닙니다. 모바일 앱을 만들면서 팀들이 자주 마주치는 현실적 문제들을 목표로 설계되었습니다: 부드럽게 느껴지는 UI, 잦은 배포, 성장하는 코드베이스의 유지보수성 등.
전통적인 모바일 워크플로는 실험을 어렵게 만들 수 있습니다: 버튼 색을 바꾸거나 레이아웃을 수정한 뒤, 재빌드·재설치·테스트 화면까지 다시 이동하는 데 시간이 걸립니다.
Dart(및 Flutter)는 매우 빠른 반복을 지원하도록 설계되었습니다. 목표는 간단합니다: UI 작업을 문서를 편집하듯이 느끼게 만드는 것—수정하고, 바로 보고, 조정하는 과정이 자연스럽게 이어지도록 하여 아이디어를 자주 테스트하고 문제를 초기에 고치게 합니다.
모바일 사용자는 특히 애니메이션이 많은 인터페이스에서 지연(jank)을 즉시 알아차립니다: 긴 목록 스크롤, 전환, 제스처 기반 효과 등.
Dart는 프레임 타임을 일관되게 유지하도록 도와줍니다. 프레임 렌더링과 제스처 처리를 담당하는 메인 스레드를 막지 않도록 동시성 구조를 제공하고, 네이티브 효율적인 코드로 컴파일할 수 있게 해줍니다. 목표는 벤치마크 자랑이 아니라 일상적인 상호작용이 다양한 기기에서 안정적으로 느껴지게 하는 것입니다.
두 개의 네이티브 앱을 유지하면 다음 같은 문제가 생깁니다:
Dart는 단일 공유 코드베이스로 진정한 네이티브 앱을 만들 수 있게 해 중복을 줄이면서도 앱 스토어 수준의 성능을 유지할 수 있도록 합니다.
앱이 커질수록 버그는 네트워크 호출, 백그라운드 작업, 상태 업데이트, 데이터 모델 같은 "접착 코드"에서 자주 발생합니다.
Dart는 비동기 워크플로를 읽기 쉽게 하는 언어 기능과 강력한 널 안전 도구를 제공해 값 누락으로 인한 크래시를 줄입니다—이런 문제들은 그렇지 않으면 시간이 지남에 따라 정리 비용이 많이 듭니다.
Dart는 무엇을 하고 있는지(빌드 중인지 출시용인지)에 따라 두 가지 “모드”로 실행되도록 설계된 점이 특징입니다.
개발 중에는 코드가 일반적으로 Dart VM에서 실행됩니다—실행 중인 앱을 로드하고 실행하며 변경 사항을 적용할 수 있는 런타임 엔진입니다. 코드를 작성하고 실행 버튼을 누르면 VM이 코드를 기기가 실행 가능한 형태로 처리합니다.
이 구조 덕분에 빠른 편집–실행 사이클이 가능해집니다: VM은 유연하게 동작하여 전체를 다시 빌드하지 않고도 변경을 빠르게 적용할 수 있습니다.
AOT 컴파일은 사용자가 즉시 체감하는 면에서 도움을 줍니다:
요약하면 JIT는 개발자 속도를, AOT는 사용자 경험을 최적화합니다.
브라우저를 대상으로 할 때는 Dart VM을 전달하지 않습니다. 대신 Dart는 JavaScript로 컴파일됩니다. 목표는 개발자 경험을 일관되게 유지하면서도 플랫폼 현실에 맞는 출력물을 만드는 것입니다.
핫 리로드는 Dart와 Flutter를 함께 쓸 때 일상에서 가장 눈에 띄는 장점 중 하나입니다. 앱을 멈추고 재빌드·재설치·다시 네비게이트하는 대신, 실행 중인 앱에 코드 변경을 주입해 UI가 거의 즉시 업데이트됩니다.
핫 리로드는 앱 세션을 유지한 채로 코드를 업데이트합니다. 일반적으로 다음과 같은 효과가 있습니다:
UI 중심 작업에서는 이 변화가 “편집 → 기다림 → 다시 열기 → 다시 이동”에서 “편집 → 확인 → 조정”으로 개발 사이클을 단축시킵니다. 간단한 여유 시간 절약이 쌓이면 레이아웃, 타이포그래피, 애니메이션을 다듬을 때 큰 생산성 향상을 가져옵니다.
UI 개발은 본질적으로 반복적입니다: 패딩, 정렬, 컴포넌트 구조를 처음부터 완벽하게 만들 수는 없습니다. 핫 리로드는 작은 실험을 저렴하게 만들어 줍니다. 새로운 레이아웃을 시도하고, 테마 색을 조정하고, 위젯을 작게 분리해 리팩터링한 뒤 즉시 화면에서 결과를 확인할 수 있습니다.
또한 시각적 또는 상태 관리 관련 버그의 피드백 루프를 단축시킵니다—논리를 약간 수정하고 위치를 잃지 않고 동작을 다시 확인할 수 있습니다.
핫 리로드는 만능이 아닙니다. 한계를 알고 있으면 혼란을 줄일 수 있습니다:
체크아웃 화면에서 "주문하기(Place order)" 버튼이 비좁게 보인다고 가정해 봅시다. 패딩을 12에서 16으로 바꾸고, 글자 굵기를 조정하고 버튼을 하단 바로 옮겼습니다. 핫 리로드로 기기에서 즉시 새 레이아웃을 확인하고, 탭해보며 겹침이 없는지 확인하고 재시도하면서 원하는 상태가 될 때까지 반복할 수 있습니다—매번 앱을 재시작할 필요가 없습니다.
실제 모바일 앱이 "빠르다"고 느껴지는 것은 벤치마크 때문이 아니라, 앱이 실제 작업을 수행하는 동안 UI가 부드럽게 유지될 때입니다.
부드러운 UI는 일관된 프레임 렌더링(예: 안정적으로 60fps나 120fps를 유지)과 반응성 있는 입력을 의미합니다. 프레임이 지연되면 지터(jank)가 발생합니다: 스크롤이 뚝뚝 끊기고 애니메이션이 끊기며 탭 반응이 늦어집니다. 50~100ms의 작은 지연도 눈에 띌 수 있습니다.
Dart는 UI가 멈추지 않도록 isolates를 제공합니다. isolate는 별도의 메모리를 가진 워커이므로 비용이 큰 작업을 메인 isolate와 분리해 실행할 수 있습니다.
많은 일반 작업이 의외로 무거울 수 있습니다:
일반적인 패턴은: UI 작업은 메인 isolate에서 처리하고, 무거운 계산은 다른 isolate로 보내 결과를 메시지로 받아 처리하는 것입니다.
모든 작업이 isolate를 필요로 하진 않습니다. 많은 시간은 I/O 대기(네트워크 호출, DB 읽기, 파일 접근)에 쓰입니다. Dart의 Future와 async/await는 코드를 기다리게 하되 이벤트 루프를 막지 않게 해 UI가 계속 렌더링되고 입력을 받을 수 있게 합니다.
final data = await api.fetchProfile(); // waiting, not blocking UI
setState(() => profile = data);
핵심 구분: I/O 대기에는 async/await를 사용하고, CPU 작업이 프레임 렌더링 시간을 잠식할 경우 isolate를 사용하세요.
Dart는 팀이 UI 중심 앱을 릴리스하면서 유지보수가 끊임없는 전쟁이 되지 않도록 돕기 위해 설계되었습니다. 많은 이점은 일반적인 실수를 초기에 방지하는 언어 기능에서 옵니다.
널 안정성은 값이 비어있을 수 있는지를 명시적인 선택으로 만듭니다. 그 결과 실무에서:
Dart의 정적 타이핑은 자동완성, 네비게이션, 리팩터링을 개선해 코드를 안전하게 변경할 수 있게 합니다. 제네릭은 컬렉션과 API를 강하게 타입화해(예: List<User>) 나중에 나타나는 데이터 형태 관련 버그를 줄입니다.
Extensions를 사용하면 기존 타입에 집중된 헬퍼를 추가할 수 있어 유틸리티 클래스를 남발하지 않아도 됩니다(예: DateTime 포맷팅, String 검증). async/await 스타일과 결합하면 전형적인 앱 로직이 중첩된 콜백으로 흐르지 않고 읽기 쉬워집니다.
Dart 패키지 생태계는 강점이지만 의존성은 장기적인 부담이 될 수 있습니다. 잘 관리되는 패키지를 선호하고, 최근 릴리스와 이슈 활동을 확인하며, 의존성 목록을 작게 유지하세요. 버전 고정과 정기 업데이트로 보안과 파괴적 변경이 쌓이지 않게 하세요.
Flutter는 "네이티브 컨트롤 위에 얹는 UI 레이어"가 아닙니다. Flutter는 자체적으로 UI를 픽셀 단위로 그리며, Dart는 이를 팀 생산성 저하 없이 실용적으로 만들어 주는 언어입니다.
Flutter 앱은 위젯으로 구성됩니다—현재 상태에서 UI가 어떻게 보여야 하는지 설명하는 작고 합성 가능한 블록들입니다. Dart의 문법은 이러한 트리를 읽기 쉽게 작성하도록 돕고, 비동기 기능은 이벤트(탭, 네트워크 결과, 스트림)에 반응하는 코드를 복잡한 콜백 없이 작성하기 쉽게 만듭니다.
무언가가 바뀌면 Flutter는 해당 상태에 의존하는 위젯 트리 부분을 다시 빌드합니다. 이 "다시 빌드하는 것이 정상"인 모델은 코드가 빠르게 실행되고 리팩터링하기 쉬울 때 잘 작동하며, Dart의 툴링과 언어 설계가 이 부분을 돕습니다.
Flutter는 부드러운 UI 업데이트를 목표로 하고, 이는 일관된 프레임 타임에 달려 있습니다. Dart는 개발 시 빠른 반복(JIT)과 릴리스 빌드 시 AOT 컴파일을 지원해 런타임 오버헤드를 줄입니다. 이런 AOT 출력은 애니메이션이 많은 인터페이스에서 발생하는 자잘한 지터를 줄이는 데 기여합니다.
또한 Flutter의 렌더링 파이프라인은 예측 가능합니다. Dart 코드는 기본적으로 단일 스레드 UI 모델을 가진 관리형 런타임에서 실행되어 많은 일반적인 "UI 스레드" 실수를 줄이되, 필요할 때 백그라운드 작업을 허용합니다.
버튼, 패딩, 행(Row), 테마, 내비게이션—대부분이 위젯입니다. 이 말이 추상적이게 들릴 수 있지만, 재사용이 상속이 아니라 구성(composition) 중심이라는 의미입니다. 어떤 요소에도 일관되게 동작(간격, 스타일, 제스처)을 감쌀 수 있습니다.
대부분의 팀은 몇 가지 상위 접근법 중 하나를 선택합니다—간단한 화면은 로컬 setState, 앱 전역 의존성은 Provider/Riverpod, 이벤트 기반 흐름은 BLoC/Cubit 등. 최적의 선택은 일반적으로 앱 복잡도와 팀 선호도에 따라 달라집니다.
실용적 비교가 필요하면 /blog/flutter-state-management를 참조하세요.
크로스플랫폼이 "네이티브 코드 없음"을 의미하지는 않습니다. 실제 앱은 여전히 카메라 제어, 푸시 알림, 블루투스, 바이오메트릭, 인앱 결제, 백그라운드 서비스, OS 깊은 통합 같은 기기별 기능이 필요합니다. Dart 생태계(특히 Flutter)는 이러한 기능에 접근하면서 전체 프로젝트가 혼합 언어의 난장판이 되지 않도록 설계되었습니다.
플랫폼 채널은 Dart 코드가 네이티브 코드(Kotlin/Java, Swift/Obj‑C)를 호출하고 결과를 받는 구조화된 방법입니다.
대체로 다음 용도로 사용합니다:
생산성 관점의 이점은 앱의 대부분을 Dart에 두고, 플랫폼별 코드를 작고 명확한 경계로 국한할 수 있다는 점입니다.
Dart FFI(Foreign Function Interface)는 Dart가 C API를 직접 호출하도록 합니다. 다음과 같은 경우에 사용합니다:
네이티브 통합은 강력하지만 복잡성을 추가합니다:
권장 관행은 네이티브 호출을 작은 Dart API로 래핑하고, 플랫폼별 통합 테스트를 추가하며, Dart와 네이티브 코드 간 계약을 명확히 문서화하는 것입니다.
Dart는 전화기에서 Flutter를 구동하는 것으로 가장 잘 알려져 있지만, 같은 언어와 많은 코드가 더 넓은 범위로 이동할 수 있습니다. 중요한 것은 무엇이 진정으로 이식 가능한지(대체로 비즈니스 로직)와 무엇이 플랫폼별인지(대체로 UI와 통합) 구분하는 것입니다.
Dart는 브라우저에서 실행될 수 있으며(대개 JavaScript로 컴파일), 팀은 보통 다음을 공유합니다:
적응이 필요한 부분:
이미 Flutter 앱이 있다면 Flutter Web로 UI 코드를 비슷하게 유지할 수 있지만 웹에 맞춘 다듬기 작업 예산은 확보해야 합니다.
Flutter는 Windows, macOS, Linux를 지원합니다. 흔한 패턴은 UI 구조와 상태 관리는 비슷하게 유지하고 다음을 적응시키는 것입니다:
Dart는 커맨드라인 도구, 빌드 스크립트, 가벼운 백엔드에서도 사용됩니다. 앱의 데이터 모델이나 API 클라이언트를 재사용하거나 단일 언어 도구체인을 유지하고 싶을 때 실용적인 선택입니다. 대규모 서버 에코시스템을 요구한다면 라이브러리 가용성과 팀 경험이 더 큰 결정 요소가 됩니다.
비즈니스 로직(모델, 서비스, 상태, 테스트)은 플랫폼 간 공유하고, UI와 네이티브 통합은 플랫폼 층으로 취급하세요. 이렇게 하면 이식성을 높이면서 모든 플랫폼에 동일한 사용자 경험을 강요하지 않을 수 있습니다.
Dart는 잘 다듬어진 대화형 제품을 빠르게 출시하는 것이 목표일 때 빛을 발합니다—별도의 iOS·Android 코드베이스를 유지하지 않고요. 그러나 항상 최선의 도구는 아니며, 플랫폼별 UI 규칙을 엄격히 따라야 하거나 특정 네이티브 도구에 깊이 의존하는 경우엔 적합하지 않을 수 있습니다.
앱이 UI 중심(다수의 화면, 애니메이션, 커스텀 컴포넌트, 잦은 디자인 수정)이라면 Dart는 강력한 선택입니다. 핫 리로드와 단일 코드베이스는 스타트업과 주 단위로 반복하는 제품팀에 실용적 이점을 제공합니다.
또한 플랫폼 간 일관된 UI가 필요하거나 유지보수가 예측 가능해야 하는 팀에도 적합합니다: 하나의 기능 세트, 하나의 버그 목록, 하나의 릴리스 스케줄을 유지할 수 있습니다.
플랫폼별 UI 관습을 매우 엄격하게 따라야 하거나(플랫폼별 최신 UI 프레임워크를 즉시 사용해야 할 때), Flutter 플러그인 생태계가 빈약해 네이티브 SDK에 크게 의존해야 할 때는 네이티브 개발이 더 간단할 수 있습니다.
또한 기존에 성숙한 네이티브 앱이 이미 있다면 전환 비용이 클 수 있습니다—대규모 재구성이 아니라면 전환이 항상 가치있지는 않습니다.
채용은 보통 가능하지만, 지역에 따라 네이티브 엔지니어가 더 풍부할 수 있습니다. 기존 코드가 이미 성숙하면 전환이 긴요하지 않은 한 즉각적인 이득이 크지 않을 수 있습니다.
대부분에 대해 "예"라면 Dart는 실용적인 선택일 가능성이 큽니다. 여러 항목이 "아니오"라면 네이티브 우선 또는 혼합 접근을 고려하세요.
Dart가 현대 앱 개발에 왜 잘 맞는지 경험해보는 가장 빠른 방법은 직접 워크플로를 체험하는 것입니다. 처음부터 모든 것을 배우려 하지 말고, 실무에서 뭔가를 실행해보고 필요에 따라 심화 학습하세요.
Flutter를 설치하세요(Flutter가 Dart SDK를 함께 포함합니다). flutter doctor로 환경을 확인합니다.
샘플 앱을 생성하고 실행하세요:
flutter create hello_dart
cd hello_dart
flutter run
lib/main.dart를 열어 위젯(예: Text() 문자열이나 색상)을 수정하고 저장하세요. 핫 리로드로 앱이 즉시 업데이트되는 것을 볼 수 있을 것입니다—이것이 Dart의 빠른 피드백 루프를 체감하는 가장 쉬운 방법입니다.제품 아이디어를 빠르게 검증하는 것이 목표라면(언어 학습이 목적이 아니라면), "UI + 백엔드 + DB" 프로토타입이 실제 병목입니다. Koder.ai 같은 플랫폼은 채팅으로 앱을 설명하면 동작하는 구현을 빠르게 생성하는 워크플로를 제공합니다. Flutter 팀에게는 초기 화면과 흐름을 빠르게 만들고, 이후 Dart와 핫 리로드로 반복 작업을 진행하는 데 유용할 수 있습니다. 백엔드도 필요하면 Koder.ai는 Go 서비스와 PostgreSQL을 생성하고, 소스 코드 내보내기, 배포/호스팅, 스냅샷 기반 롤백을 지원합니다.
Widgets: UI를 작은 조각들의 트리로 생각하세요. 기본 레이아웃 위젯(Row, Column, Container)과 상태(StatefulWidget)가 어떻게 작동하는지 배우세요.
Async + await: 대부분의 실제 앱은 데이터 가져오기, 파일 읽기, 플랫폼 API 호출을 합니다. Future, async, 에러 처리를 익히세요.
Null safety: Dart는 널(nullable) 여부를 명시적으로 만들어 일반적인 값 누락 충돌을 방지합니다. 코드베이스가 커질수록 이 장점은 빠르게 체감됩니다.
Packages: pubspec.yaml에 의존성을 추가하는 법과 패키지 품질(유지관리, 인기, 플랫폼 지원)을 평가하는 법을 배우세요.
작은 앱 하나를 만들어 기본을 증명하세요: 두 화면 UI, 간단한 폼, 하나의 네트워크 호출(또는 로컬 저장). 성능, 반복 속도, 통합 지점을 확인하기에 충분하면서 큰 결정을 내리기 전 부담은 적습니다.
다음 읽을거리: /blog/flutter-vs-react-native, /blog/dart-null-safety, /blog/flutter-performance-basics
Dart는 Google이 만든 현대적인 언어이며, 오늘날 대부분의 사람들이 Dart를 인식하는 이유는 Flutter가 UI와 많은 앱 로직에 Dart를 사용하기 때문입니다.
팀들이 Dart에 주목하는 이유는 개발 단계에서의 **빠른 반복(핫 리로드)**과, 배포 시 **예측 가능한 성능(AOT로 네이티브 코드 생성)**을 모두 지원하기 때문입니다.
Dart는 대화형 UI가 많고 부드럽게 동작해야 하며, 로드 속도가 빠르고 성장하면서도 유지보수가 쉬운 앱을 만들려는 "클라이언트 앱" 문제 영역을 목표로 만들어졌습니다.
설계 목표는 다음과 같습니다:
개발 중에는 Dart가 보통 Dart VM에서 JIT(Just-In-Time) 컴파일로 실행되어 빠른 반복과 핫 리로드 같은 워크플로를 가능하게 합니다.
릴리스 빌드에서는 Dart가 AOT(Ahead-Of-Time) 컴파일을 사용해 네이티브 머신 코드를 생성하여 시작 시간 단축과 런타임 오버헤드 감소(UI 잔상 방지)에 기여합니다.
핫 리로드는 실행 중인 앱에 변경한 Dart 코드를 주입해 현재 화면과 내비게이션 상태를 보존한 채로 UI를 즉시 갱신합니다.
주로 레이아웃, 스타일, 위젯 리팩터링 같은 UI 반복 작업에 유용하지만 다음은 핫 리로드로 할 수 없는 것들입니다:
I/O 대기(네트워크, DB, 파일 등)에는 **async/await**를 사용해 Future를 기다리는 동안 이벤트 루프를 막지 않도록 합니다.
CPU 집약 작업(대용량 JSON 파싱, 이미지 처리, 암호화 등)은 isolates로 분리해 메인(UI) isolate가 프레임을 놓치지 않도록 해야 합니다.
실용 규칙: 기다리는 작업 → async/await; 계산하는 작업 → isolate.
Null safety는 값이 비어있을 수 있는지를 타입 수준에서 명시하도록 만듭니다. 그 결과:
Dart의 정적 타입은 IDE 자동완성, 코드 네비게이션, 리팩터링을 개선해 대규모 코드베이스 유지보수를 용이하게 합니다.
제네릭도 데이터 형태 관련 버그를 줄입니다. 예: List<User>처럼 구체적 타입을 사용하면 잘못된 데이터 구조로 인한 문제를 빨리 잡을 수 있습니다.
웹에서는 브라우저가 Dart VM을 실행하지 않으므로 보통 Dart 코드를 JavaScript로 컴파일합니다.
실무에서는 **비즈니스 로직(모델, 검증, 네트워킹 등)**을 여러 플랫폼에서 공유하고, UI와 플랫폼 통합은 웹 특성(라우팅, 접근성, SEO)에 맞춰 적응시키는 경우가 많습니다.
플랫폼 채널은 Dart 코드가 OS별 API를 호출할 때 사용하는 메시지 기반 브리지입니다(예: Android는 Kotlin/Java, iOS는 Swift/Obj‑C).
Dart FFI는 C API를 직접 호출할 때 사용하며, 성능이 중요한 라이브러리(암호화, 오디오 처리, 컴퓨터 비전 등)나 기존 C/C++ 코드를 재사용할 때 유용합니다.
Dart(특히 Flutter와 함께)는 다음 상황에서 강력합니다:
다음 경우에는 완전 네이티브가 더 낫습니다:
결국 팀 역량, 기존 코드, 필요한 SDK 지원 상황을 고려해 결정하세요.