Dart 2.17: 생산성과 통합
Dart 2.17: 생산성과 통합
언어 기능. 생산성 도구. 더 깊고 넓어진 플랫폼 통합까지, Dart 2.17 소식이에요. 오늘 Google I/O에서 새 Dart SDK, 버전 2.17을 발표했어요. 이번 릴리스는 우리의 핵심 테마인 최고의 생산성과 플랫폼 이식성을 바탕으로 하고 있어요. 멤버를 지원하는 enum, 슈퍼클래스로의 개선된 파라미터 전달, 네임드 파라미터의 더 큰 유연성이라는 새 언어 기능이 추가됐고요. 또 최고 권장 사례에 맞춰 Dart 코드를 검사하는 package:lints의 새 메이저 버전 같은 도구 개선과, 풍부한 코드 샘플을 담은 핵심 라이브러리 API 문서 전면 갱신도 있었어요. 플랫폼 통합을 위해선 Flutter 플러그인에서 dart:ffi(네이티브 C 인터롭)를 쓰는 새로운 템플릿, RISC-V 프로세서에 대한 실험적 지원, macOS·Windows 실행 파일 서명 지원이 추가됐어요.
본문
개선된 생산성을 위한 새 언어 기능
우리는 여러분이 더 생산적으로 일하도록 Dart 언어를 끊임없이 진화시키고 있어요. 새 기능을 더하고, 기존 기능도 개선하는 식이죠. Dart 2.17은 enum의 멤버 지원이라는 주요 새 기능을 더하고, 생성자에서 네임드 인자를 쓰는 방식을 다듬으며, 슈퍼클래스로 파라미터를 전달하는 코드를 훨씬 덜 장황하고 덜 반복적으로 만들어 줘요.
멤버를 가진 향상된 enum
enum은 어떤 이산적인 상태의 집합을 표현하는 데 아주 좋아요. 예를 들어 물을 enum Water { frozen, lukewarm, boiling }으로 모델링할 수 있겠죠. 그런데 만약 enum에 몇 가지 메서드를 추가하고 싶다면 어떨까요? 예를 들어 각 상태를 온도로 변환하고, enum을 String으로 변환하는 것을 지원하고 싶다면요. 확장 메서드를 써서 waterToTemp() 메서드를 추가할 수도 있지만, 그게 enum과 동기화되도록 신경 써야 해요. String 변환을 위해서는 toString()을 오버라이드하고 싶을 텐데, 그건 지금까지 지원되지 않았어요.
Dart 2.17부터는 enum의 멤버를 일반적으로 지원해요. 상태를 담는 필드, 그 상태를 설정하는 생성자, 기능을 담은 메서드를 추가할 수 있고, 기존 멤버까지 오버라이드할 수 있어요. 많은 분이 이 기능을 요청해 주셨어요. 언어 트래커에서 세 번째로 많은 투표를 받은 이슈였죠.
우리의 물(water) 예시에, 온도를 담는 int 필드와 int를 받는 기본 생성자를 추가해 볼게요.
enum Water {
…
final int tempInFahrenheit;
const Water(this.tempInFahrenheit);
}
enum이 만들어질 때 생성자가 호출되도록, 각 enum 값마다 생성자를 호출해 줘야 해요.
enum Water {
frozen(32),
lukewarm(100),
boiling(212);
…
}
String 변환을 지원하려면, enum이 Object에서 물려받는 toString을 그냥 오버라이드하면 돼요.
@override
String toString() => "The $name water is $tempInFahrenheit F.";
이렇게 하면 쉽게 인스턴스화하고 메서드를 호출할 수 있는 완전한 enum이 완성돼요.
void main() {
print(Water.frozen); // Prints “The frozen water is 32 F.”
}
이 두 접근 방식의 완전한 예시는 아래에 나와 있어요. 우리는 새 Dart 2.17 버전이 훨씬 읽고 유지보수하기 쉬운 것 같아요.
슈퍼 이니셜라이저(Super initializers)
클래스 상속 계층이 있을 때, 슈퍼클래스의 생성자에 생성자 파라미터 몇 개를 전달하는 건 흔한 패턴이에요. 그러려면 서브클래스가 1) 자기 생성자에 각 파라미터를 나열하고, 2) 그 파라미터들로 슈퍼 생성자를 호출해야 해요. 이건 보일러플레이트 코드로 이어져요. 반복이 많아지면서 코드를 읽기 어렵게 하고, 유지보수를 번거롭게 만들죠.
이 기능이 만들어지는 데는 Dart 커뮤니티 멤버 몇 분의 도움이 있었어요. GitHub 사용자 @roy-sianez가 약 반년 전에 이에 관한 언어 이슈를 제기했어요. GitHub 사용자 @apps-transround가 앞서 제안했던 것과 비슷한 방식이었죠. 파라미터가 슈퍼클래스에서 지정됐다는 걸 표현하는 새로운 구문을 도입하면 해결할 수 있지 않겠냐는 제안이었어요. 우리는 그게 훌륭한 아이디어라고 생각했고, 그래서 Dart 2.17에 추가했어요. 아래 예시에서 보듯, 이 기능은 특히 Flutter 위젯 코드에서 유용해요. 실제로 이 새 기능을 Flutter 프레임워크에 적용했을 때, 무려 약 2,000줄의 코드가 줄었어요!
네임드 인자는 어디든(Named args everywhere)
마지막으로, 메서드를 호출할 때 네임드 인자가 동작하는 방식을 다듬었어요. 이전에는 네임드 인자가 메서드의 인자 목록에서 마지막에 와야 했어요. 포지셔널 인자를 마지막에 두면 코드가 더 읽기 쉬운 경우에는 이게 짜증났죠. 예를 들어 List<T>.generate 생성자의 아래 호출을 볼게요. 이전에는 growable 인자가 마지막에 와야 해서, 제너레이터를 담고 있는 큰 포지셔널 인자 아래에 숨어버려 놓치기 쉬웠어요. 이제는 원하는 순서대로 나열할 수 있어서, 작은 네임드 인자를 먼저 두고 제너레이터를 마지막에 둘 수 있어요.
이 세 가지 기능의 더 많은 예시는 enum, super initializers, named parameters에 대한 갱신된 샘플에서 볼 수 있어요.
생산성 도구
생산성 테마를 이어가면서, 핵심 도구에 개선을 몇 가지 더했어요.
Dart 2.14에서 package:lints를 소개했어요. 이 패키지는 Dart 분석기와 함께 작동해서 오류를 막고, 더 효과적인 코드 리뷰를 가능하게 하는 표준 스타일을 쓰는 Dart 코드를 작성하도록 도와줘요. 그 이후로 분석기에 새 린트가 많이 추가됐는데, 우리가 신중하게 분류해서 모든 Dart 코드용 린트 10개와 Flutter 코드 전용 린트 2개를 골랐어요. 여기에는 import가 pubspec 파일에 포함되었는지 확인하는 린트, 타입 파라미터에서 널 체크를 잘못 쓰는 걸 막는 린트, child 프로퍼티의 일관된 스타일을 보장하는 린트 등이 포함돼요. 새 린트로는 간단한 명령으로 업그레이드할 수 있어요.
- Dart 패키지:
dart pub upgrade --major-versions lints - Flutter 패키지:
flutter pub upgrade --major-versions flutter_lints
SecureSocket은 TLS와 SSL로 보호되는 TCP 소켓을 활성화하는 데 흔히 쓰여요. Dart 2.17 이전에는 개발 중에 이런 소켓을 디버깅하는 게 까다로웠어요. 보안 데이터 트래픽을 검사할 방법이 없었거든요. 이제 keyLog 파일을 지정하는 기능을 추가했어요. 지정하면 새 TLS 키가 서버와 교환될 때마다 NSS Key Log Format 형식의 텍스트 한 줄이 그 파일에 추가돼요. 이렇게 하면 Wireshark 같은 네트워크 트래픽 분석 도구가 소켓을 통해 보내진 내용을 복호화할 수 있어요. 자세한 내용은 SecureSocket.connect()의 API 문서를 참고해 주세요.
dart doc 도구가 생성하는 API 문서는 새 API를 배우는 대부분의 Dart 개발자에게 중요한 자산이에요. 핵심 라이브러리 API에는 오랫동안 풍부한 텍스트 설명이 있었지만, 많은 개발자가 그 API를 쓰는 샘플 코드를 읽는 걸 선호한다고 알려줬어요. Dart 2.17에서는 모든 주요 핵심 라이브러리를 전면 개편해서, 가장 많이 보이는 상위 200개 페이지에 샘플 코드를 추가했어요. 그래서 이제는 종합적인 샘플 코드를 갖추고 있어요. 예를 들어 Dart 2.16의 dart:convert 문서를 Dart 2.17의 갱신된 페이지와 비교해 보세요. 문서를 훨씬 소화하기 쉽게 만들어 줄 거예요.
생산성 향상은 플랫폼에 새 기능을 추가할 때만 오는 게 아니에요. 스택을 정리하고 더 이상 쓰이지 않는 기능을 제거할 때도 옵니다. 이건 특히 새 개발자에게 중요한 표면적(surface area)을 작게 유지하는 데 도움이 돼요. 이를 위해 dart:io 라이브러리에서 deprecated 코드 231줄을 제거했어요. 아직 이런 deprecated API를 쓰고 있다면, dart fix로 대체 API로 업그레이드할 수 있어요. 또 deprecated Dart CLI 도구를 지우는 노력을 이어가서, 이번에는 dartdoc 도구(대신 dart doc 사용)와 pub 도구(대신 dart pub 또는 flutter pub 사용)를 제거했어요.
플랫폼 통합과 지원 넓히기
두 번째 핵심 테마는 플랫폼 통합과 지원이에요. Dart는 진정한 멀티 플랫폼 언어예요. 이미 다양한 플랫폼을 지원하지만, 지원되는 각 플랫폼과 깊이 통합할 수 있도록, 그리고 새로 떠오르는 플랫폼도 지원하도록 계속 발전하고 있어요.
Dart FFI — C/네이티브 코드와 인터롭하기 위한 우리의 핵심 메커니즘 — 는 Dart 코드를 기존 네이티브 플랫폼 코드와 통합하는 인기 있는 방법이에요. Flutter에서는 호스트 플랫폼의 네이티브 API(예: Windows win32 API)를 쓰는 플러그인을 만드는 좋은 방법이 될 수 있어요. Dart 2.17과 Flutter 3에서는 flutter 도구에 템플릿을 추가해서, dart:ffi로 네이티브 코드를 호출하는 Dart API를 가진 FFI Plugin을 이제 쉽게 만들 수 있어요. 자세한 내용은 flutter.dev의 갱신된 developing packages and plugins 페이지를 참고해 주세요.
ABI(애플리케이션 바이너리 인터페이스)에 특화된 타입을 가진 플랫폼에서 FFI를 쓸 수 있도록, FFI는 이제 ABI 특화 타입을 지원해요. 예를 들어 Long(C의 long)을 써서 ABI 특화 크기의 긴 정수를 올바르게 표현할 수 있어요. 그 크기는 CPU 아키텍처에 따라 32비트나 64비트일 수 있죠. 지원되는 타입 전체 목록은 AbiSpecificInteger API 페이지의 'Implementers' 목록을 확인해 보세요.
Dart FFI로 네이티브 플랫폼과 깊이 통합할 때, Dart와 네이티브 코드가 할당한 메모리나 다른 리소스(포트, 파일 등)의 정리 시점을 맞춰야 할 때가 있어요. 이건 역사적으로 아주 까다로웠어요. Dart는 가비지 컬렉션 언어라서 정리를 자동으로 처리하거든요. Dart 2.17은 Finalizer 개념을 도입해서 이 문제를 풀어요. 너무 일찍 파이널라이즈되거나 버려지지 않아야 하는 객체를 '태그'하는 Finalizable 마커 인터페이스와, Dart 객체에 붙여서 객체가 가비지 컬렉션되기 직전에 실행되는 콜백을 제공하는 NativeFinalizer 클래스가 포함돼요. 이 둘을 함께 쓰면 네이티브 코드와 Dart 코드 양쪽에서 정리 코드를 실행할 수 있어요. 자세한 내용은 NativeFinalizer의 API 문서에 있는 설명과 예시, 또는 일반 Dart 코드에서 비슷한 지원을 제공하는 WeakReferences와 Finalizer 문서를 참고해 주세요.
Dart를 네이티브 코드로 컴파일하는 우리의 지원은 Flutter 앱이 훌륭한 시작 성능과 빠른 렌더링을 갖게 만드는 핵심 요소예요. 두 번째 사용 사례는 dart compile로 Dart를 실행 파일로 컴파일하는 기능이에요. 이 실행 파일은 Dart SDK가 설치되어 있지 않아도 어떤 머신에서든 독립적으로 실행될 수 있어요. Dart 2.17의 또 다른 새 기능은 실행 파일 서명 지원으로, 서명이 자주 요구되는 Windows와 macOS에 배포할 수 있게 해 줘요.
우리는 새로 떠오르는 플랫폼의 최전선에 서서 지원 플랫폼 세트를 계속 넓히고 있어요. RISC-V는 프로세서를 위한 새롭고 혁신적인 명령어 세트예요. 전 세계 비영리 단체인 RISC-V International이 RISC-V 규격을 소유하고 있어서, 그 명령어 세트는 자유롭고 개방적이에요. 아직 떠오르는 플랫폼이지만 우리는 그 잠재력에 기대를 걸고 있어요. 그래서 우리의 2.17.0–266.1.beta Linux 릴리스(또는 베타 채널의 이후 버전)에 실험적 지원을 포함했어요. 피드백을 듣고 싶으니, 이슈를 등록하거나 경험을 올려주세요!
Dart 2.17 시작하기
오늘의 Dart 2.17 릴리스가 여러분을 흥분시키고, 생산성을 높이며, 앱에서 더 많은 플랫폼 통합을 가능하게 해 주길 바라요. 시작하려면 Dart 2.17 릴리스를 직접 다운로드하거나, 오늘의 Flutter 3 SDK 릴리스에 통합된 형태로 가져올 수 있어요.
Google I/O를 위해 준비한 새 콘텐츠도 확인해 보시길 권해요!