Dart 2.14 발표
Dart 2.14 발표
오늘 Dart SDK 버전 2.14를 출시해요. 이번 릴리스는 이식성·생산성·견고함이라는 독특한 조합으로 앱을 만드는 데 가장 좋은 플랫폼을 만들자는 우리의 지속적인 여정의 다음 릴리스예요. 이번에는 Apple Silicon 지원이 더 좋아졌고, 코드 스타일 분석을 통해 코드를 작성하면서 오류를 잡아내는 표준 린트(lints), 더 빨라진 pub 도구, 캐스케이드(cascades)가 있는 코드의 더 나은 포맷팅, 그리고 몇 가지 작은 언어 기능 같은 생산성 향상이 담겨 있어요.
본문
Dart SDK의 Apple Silicon 지원
Apple이 2020년 후반에 새 Apple Silicon 프로세서를 발표한 이후, 우리는 새 프로세서에서 네이티브로 실행되도록 Dart SDK를 업데이트하는 작업을 해 왔어요. 필요한 변경 사항은 한동안 dev 채널에, 지난 한 달간 beta 채널에 있었고, Dart 2.14.1부터는 Dart stable 채널에서도 사용할 수 있어요. macOS SDK를 내려받을 때는 반드시 ARM64 옵션을 선택해야 해요. Flutter SDK에 번들된 Dart SDK에는 아직 이런 개선이 없다는 점을 참고하세요.
이 지원에는 Apple Silicon에서 SDK/Dart VM 자체를 실행하는 것과, Apple Silicon에서 실행되는 실행 파일(용 dart compile로 컴파일)을 지원하는 것이 모두 포함돼요. Dart 명령줄 도구는 네이티브 Apple Silicon 지원을 사용하게 되면서 훨씬 더 빨리 시작돼요.
Dart와 Flutter가 공유하는 표준 린트
개발자들은 흔히 자기 코드가 특정 스타일을 따르길 원해요. 그런 규칙 중 상당수는 단순한 취향(잘 알려진 tabs vs. spaces 논쟁 같은 것)이 아니라, 실수나 버그로 이어질 가능성이 있는 코딩 스타일을 다루는 거예요. 예를 들어, Dart 스타일 가이드는 if-else 문 같은 모든 제어 흐름 구조에 중괄호를 사용하도록 요구해요. 이는 여러 개의 중첩된 if-else 문을 어떻게 해석할지 모호해지는 고전적인 dangling else 문제를 막아줘요. 또 다른 예는 타입 추론이에요. 초기값이 있는 변수를 선언할 때 타입 추론을 쓰는 건 괜찮지만, 초기화되지 않은 변수를 선언할 때는 타입 안전성을 위해 타입을 지정하는 게 중요해요.
좋은 코드 스타일을 강제하는 한 가지 방법은 보통 코드 리뷰를 통한 인간의 강제예요. 하지만 코드를 작성하는 동안 실행되는 정적 분석(static analysis)으로 규칙을 강제하는 것이 훨씬 더 효과적일 때가 많아요.
Dart에서 이 정적 분석은 매우 구성 가능하고, 수백 개의 스타일 규칙(린트라고도 불러요)이 있어요. 선택지가 이렇게 많은 탓에 어떤 규칙을 켤지 고르기가 꽤 부담스러울 수 있어요. Dart 팀은 Dart 코드를 쓰고 스타일을 잡는 가장 좋은 방법을 설명하는 Dart 스타일 가이드를 유지하지만, 역사적으로 스타일 가이드에 대응하는 공식 린터 규칙 세트는 없었어요.
많은 개발자 — 그리고 pub.dev 사이트 스코어링 엔진 — 가 pedantic 린트 규칙 세트를 사용했어요. 그런데 pedantic은 Google 내부 Dart 스타일 가이드에 기원을 두고 있고, 역사적 이유로 일반 Dart 스타일 가이드와 다르죠. 게다가 Flutter 프레임워크는 pedantic 규칙 세트를 쓴 적이 없고 대신 자체 표준 규칙 세트를 가졌어요.
좀 지저분하게 들릴 수 있는데, 실제로 그랬어요. 하지만 오늘 출시와 함께 우리는 스타일 가이드를 구현하는 완전히 새로운 린트 컬렉션 세트를 갖게 됐고, Dart와 Flutter SDK가 새 프로젝트에서 이 규칙 세트를 기본으로 사용하도록 업데이트됐어요. 규칙 세트는 다음과 같아요.
- package:lints/core.yaml: 모든 Dart 코드가 따라야 한다고 믿는 Dart 스타일 가이드의 핵심 규칙들. pub.dev 스코어링 엔진도 pedantic 대신 이걸 사용하도록 업데이트됐어요.
- package:lints/recommended.yaml: core 규칙에 추가 권장 규칙이 더해진 세트. 일반적인 모든 Dart 코드에 권장돼요.
- package:flutter_lints/flutter.yaml: core와 recommended 규칙에 Flutter 전용 권장 규칙이 더해진 세트. 모든 Flutter 코드에 권장돼요.
기존 프로젝트가 있다면 이 새 규칙 세트로 업그레이드하길 강력히 권장해요. pedantic에서 업그레이드하는 건 몇 단계면 충분해요.
Dart 포맷터와 캐스케이드
우리는 Dart 포맷터가 캐스케이드가 있는 코드를 포맷하는 방식을 여러 가지로 최적화했어요. 이전에는 포맷터가 어떤 경우 헷갈리는 포맷팅을 만들기도 했죠. 예를 들어, 이 예시에서 doIt()은 무엇에 호출되는 걸까요?
var result = errorState ? foo : bad..doIt();
항상 bad에 호출되는 것처럼 보이지만, 실제로 캐스케이드는 전체 ? 표현식에 적용돼요. 그래서 캐스케이드는 false 절만이 아니라 그 표현식의 결과에 호출돼요. 새 포맷터는 이를 명확하게 만들어요.
var result = errorState ? foo : bad
..doIt();
다른 변경 사항은 여러 캐스케이드가 있는 줄을 포맷하는 방법과, 캐스케이드가 일반적으로 들여쓰기되는 정도에 관한 거예요. 캐스케이드가 포함된 코드를 포맷하는 속도도 크게 높였어요. protocol buffers용으로 생성된 Dart 코드에서는 포맷팅 속도가 최대 10배 빨라진 걸 보고 있어요.
자세한 내용은 추적 이슈(tracking issue)를 참고하세요.
파일 무시를 지원하는 Pub
현재 pub.dev 커뮤니티 저장소에 패키지를 게시하면, pub은 몇 가지 예외를 제외하고 그 폴더의 모든 파일을 가져가요. 숨김 파일(점: .으로 시작하는 파일)과 .gitignore에 나열된 파일은 건너뛰죠. 여러 개발자가 .gitignore 목록 밖에서 어떤 파일을 무시할지 제어할 수 있는 기능을 요청했어요. 예를 들어, 패키지를 유지 관리하는 데 쓰지만 패키지 사용자에게는 관련 없는 내부 개발 도구가 tool/ 폴더에 있을 수 있죠.
Dart 2.14의 업데이트된 pub 명령은 새 .pubignore 파일을 지원해요. pub.dev에 업로드하고 싶지 않은 파일을 여기에 나열할 수 있어요. 이 파일은 .gitignore 파일과 같은 형식을 사용해요. 자세한 내용은 패키지 게시 문서를 참고하세요.
Pub와 dart test 성능
pub은 아마 코드 의존성 관리에 가장 많이 쓰이지만, 두 번째로 중요한 용도도 있어요. 바로 도구에 동력을 공급하는 거예요. 그런 예시 중 하나가 dart test 명령으로 노출되는 Dart 테스트 도구예요. 이 명령은 실제로 package:test의 test 엔트리포인트를 실행하는 command pub run test:test의 래퍼일 뿐이에요. 그 엔트리포인트를 호출하기 전에 pub은 먼저 더 빨리 실행될 수 있도록 네이티브 코드로 컴파일해요.
Dart 2.14 이전에는 pubspec의 어떤 변경(package:test와 무관한 것 포함)이라도 test 빌드를 무효화해서, 아래처럼 "Precompiling executable"이 들어간 출력을 많이 보게 됐어요.
$ dart test
Precompiling executable... (11.6s)
Precompiled test:test.
00:01 +1: All tests passed!
Dart 2.14에서 pub은 빌드 단계를 언제 무효화할지 훨씬 더 영리하게 판단해서, 버전이 변경될 때만 빌드가 일어나요. 게다가 병렬화를 사용해 빌드 단계 자체를 수행하는 방식을 개선해서, 그 단계가 훨씬 더 빨리 완료돼요. 테스트한 일부 패키지에서는 시간이 절반으로 줄어드는 걸 봤어요.
새로운 언어 기능
Dart 2.14에는 작은 언어 기능도 몇 가지 포함돼 있어요. 이번에는 더 좁은 유용성일 수 있지만, 이전에는 지원되지 않던 더 전문적인 사용 사례를 가능하게 하는 더 구체적인 개선에 집중했어요.
먼저, 새 삼중 시프트 연산자(>>>)를 추가했어요. 이것은 기존 시프트 연산자(>>)와 비슷한데, >>이 산술 시프트(arithmetic shift)를 수행하는 반면 >>>은 논리(부호 없는) 시프트를 수행해서, 시프트되는 숫자가 양수인지 음수인지와 무관하게 최상위 비트로 0비트가 시프트돼요.
또한 타입 인자에 대한 오래된 제한을 제거했어요. 제네릭 함수 타입을 타입 인자로 사용하는 것이 이전에는 금지됐거든요. 다음 모두가 2.14 이전에는 유효하지 않았지만 이제 허용돼요.
late List<T Function<T>(T)> idFunctions;
var callback = [<T>(T value) => value];
late S Function<S extends T Function<T>(T)>(S) f;
마지막으로, 애너테이션 타입에 대한 작은 조정을 했어요. (@Deprecated 같은 애너테이션은 메타데이터를 담기 위해 Dart 코드에서 흔히 쓰여요.) 이전에는 애너테이션에 타입 인자를 전달할 수 없어서 @TypeHelper<int>(42, "The meaning") 같은 코드가 허용되지 않았어요. 이 제한이 이제 제거됐어요.
패키지와 핵심 라이브러리 변경
핵심 Dart 패키지와 라이브러리에 여러 가지 개선을 했어요.
dart:core:Object클래스에 정적 메서드hash,hashAll,hashAllUnordered를 추가했어요. 이들은 여러 객체의 해시 코드를 일관된 방식으로 결합하는 데 쓸 수 있어요(hashAll 예시).dart:core: 네이티브DateTime클래스가 이제 정확히 1시간이 아닌 일광 절약 시간(daylight saving time) 변경 주변의 로컬 시간을 더 잘 처리해요. 예를 들어 30분 시프트를 사용하는 Lord Howe Island, 호주 같은 경우죠.- package:ffi: 아레나 할당자(arena allocator)를 이용한 메모리 관리를 지원하도록 추가했어요(예시). 아레나는 영역 기반 메모리 관리의 한 형태로, 아레나/영역을 빠져나가면 리소스가 자동으로 해제돼요.
- package:ffigen: 이제 C typedef로부터 Dart typedef를 생성하는 것을 지원해요.
Breaking changes
Dart 2.14에는 이전에 발표된 더 작은 breaking changes도 몇 가지 포함돼 있어요. 이 변경들은 몇 가지 전문적인 사용 사례에만 영향을 줄 거라고 예상돼요.
#46545: ECMAScript5 지원 제거
모든 현대 브라우저는 최신 ECMAScript 버전을 지원하므로, 2년 전 우리는 ECMAScript 5(ES5) 지원을 폐기할 계획을 발표했어요. 이로써 최신 ECMAScript의 개선을 활용하고 더 작은 출력을 생성할 수 있게 됐죠. Dart 2.14에서 이 작업이 완료됐고, Dart 웹 컴파일러는 더 이상 ES5를 지원하지 않아요. 결과적으로 IE11 같은 더 오래된 브라우저는 더 이상 지원되지 않아요.
#46100: stagehand, dartfmt, dart2native 폐기
2020년 10월 Dart 2.10 블로그 글에서, 우리는 모든 Dart CLI 개발자 도구를 단일 통합 dart 도구(Flutter 도구와 비슷하게)로 결합하는 작업을 발표했어요. 그 진화의 일환으로 Dart 2.14는 이전 dartfmt와 dart2native 명령을 폐기하고 stagehand를 중단했어요. 이 도구들은 모두 통합 dart 도구에 동등한 대체 수단이 있어요.
#45451: VM 네이티브 확장 폐기
우리는 Dart VM의 네이티브 확장을 폐기했어요. 이는 Dart 코드에서 네이티브 코드를 호출하는 옛 메커니즘이에요. Dart FFI(foreign function interface)가 이 사용 사례에 대한 현재 메커니즘이고, 우리는 그것을 더욱 강력하고 쓰기 쉽게 진화시키는 작업을 적극적으로 하고 있어요.
Null safety 업데이트
우리는 3월에 Dart 2.12 릴리스에서 사운드(sound) null safety를 출시했어요. Null safety는 Dart의 최신 주요 생산성 기능으로, 종종 찾아내기 어려운 버그 종류인 null 오류를 피하도록 도와줘요.
지난 업데이트 이후, null safety의 사운드 검사 이점을 켜기 위한 기존 패키지와 앱의 마이그레이션에서 큰 진전을 봤어요. pub.dev의 패키지 중 상위 250개 패키지 100%가 이제 null safety를 지원하고, 상위 1000개 중 94%가 지원해요. 이는 더 많은 개발자가 완전한 사운드 null safety로 앱을 실행할 수 있다는 뜻이에요. 분석에 따르면 flutter run 세션의 56%가 완전한 사운드로 실행돼요. 마이그레이션 작업을 해주신 생태계의 모든 개발자분들께 감사드려요!
2.14 사용 가능 여부와 지속적인 모멘텀
위 변경 사항이 담긴 개선된 Dart SDK는 오늘 Dart 2.14.1과 Flutter 2.5 SDK에서 사용할 수 있어요. 새 개선 사항과 기능을 즐겁게 사용하시길 바래요.
또한 이 기회에 멋진 Dart 커뮤니티에 감사를 전하고 싶어요. 프로그래밍 언어 설문조사에 대한 최근 업데이트들에서 알 수 있듯, Dart의 모멘텀은 강해요. 잘 알려진 RedMonk 순위는 "Dart의 놀라운 상승(remarkable ascent)"을 언급하며 Dart를 처음으로 상위 20위 안에 올렸어요. StackOverflow의 포괄적인 2021 Developer Survey도 읽는 게 똑같이 즐거웠어요. Dart는 개발자가 가장 사랑하는 프로그래밍 언어 7위로 보고됐죠. Dart 플랫폼이 지속적으로 성장하고 모멘텀을 갖는 걸 보니 정말 기쁘네요.