-
Flutter Macro카테고리 없음 2024. 5. 20. 21:22
매크로
5월 15일 구글 I/O 2024에서 플러터 3.22가 공개 되었네요.
미디엄에도 글이 올라왔습니다. Landing Flutter 3.22 and Dart 3.4 at Google I/O 2024
웹어셈블리도 공식적으로 지원하게 되었고, 매크로 기능을 소개하였습니다.
웹어셈블리는 관심있게 보고 있던 주제였습니다.
최근에 회사에서 러스트 스터디를 진행했는데 스터디 중 웹어셈블리 언어로 러스트가 가능하다는 걸 알았기 때문이죠..!
특히 러스트의 소유권에 대한 개념은 참 흥미롭고 재밌었던 것 같습니다.
이거에 대한 주제도 따로 한번 써봐야겠네요..
다시 돌아와서..
오늘 볼 주제는 매크로 입니다.
Swift에서도 최근 매크로가 도입되었고 조금 공부해봤는데 이번 기회에 플러터에도 매크로가 개발중이라는 사실을 알게 되었네요..!
이 부분 같이 문서 보면서 공부해 보겠습니다!
Swift
저는 Swift로 iOS를 개발하다가 Dart언어로 플러터로 개발해보면서 제일 익숙하지 않았던게 JSON에 대한 디코딩 인코딩 기능입니다. (build_runner,, freezed,,)
Swift에서는 Codable 프로토콜을 사용하여 간단하게 인코딩과 디코딩을 할 수있죠.
Swift에서 만약 모델 타입을 디코딩 하고 싶다면 아래와 같이 하면 됩니다.
// 모델 타입 // Codable은 Encodable과 Decodable을 합친 typealias struct ToDo: Codable { let userId: Int let id: Int let title: String let completed: Bool } // 모델 타입에 대한 인코딩 & 디코딩 let json = """ { "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false } """ do { // JSON 디코딩 let decoded = try JSONDecoder().decode(ToDo.self, from: json.data(using: .utf8)!) print(decoded.id) print(decoded.completed) print(decoded.title) // 인코딩 let encoded = try JSONEncoder().encode(decoded) let jsonString = String(data: encoded, encoding: .utf8) print(jsonString) } catch { print("error") }
이렇게 Codable Protocol을 채택한 것만으로 해당 타입은 손쉽게 인코딩과 디코딩을 할 수 있습니다.
플러터에서는 어떨까요?
Flutter
// 디코딩 const jsonString = { "name": "John Smith", "email": "john@example.com" } final user = jsonDecode(jsonString) as Map<String, dynamic>; print('Howdy, ${user['name']}!'); print('We sent the verification link to ${user['email']}.');
라이브러리를 사용하면 이렇게 Map 타입으로 캐스팅 한 뒤 사용하게 됩니다.
이러면 해당 value에 대한 type이 다이나믹이기 때문에 어떤 타입인지 모호하고 컴파일 시점에 유추하기 힘든면이 있습니다.
만약 Key를 잘못 넣었을 때 상황도 생각하기 싫네요.. ㅠ그래서 보통의 경우에는 json_serializable 또는 freezed 라이브러리를 사용하여 모델 타입에 대한 코드를 생성하게 됩니다.
@JsonSerializable() class Todo { final int userId; final int id; final String title; final String description; Todo({ required this.userId, required this.id, required this.title, required this.description, }); // 디코딩 factory Todo.fromJson(Map<String, dynamic> json) => _$TodoFromJson(json); // 인코딩 Map<String, dynamic> toJson() => _$TodoToJson(this); ------------------------------------------------------------------ /// fromJson 메서드와 toJson에 대한 메서드 코드를 아래와 같이 자동생성해 줍니다. /// todo.g.dart 생성 파일 // GENERATED CODE - DO NOT MODIFY BY HAND part of 'todo.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** Todo _$TodoFromJson(Map<String, dynamic> json) => Todo( userId: (json['userId'] as num).toInt(), id: (json['id'] as num).toInt(), title: json['title'] as String, description: json['description'] as String, ); Map<String, dynamic> _$TodoToJson(Todo instance) => <String, dynamic>{ 'userId': instance.userId, 'id': instance.id, 'title': instance.title, 'description': instance.description, }; }
라이브러리를 사용하게 되면 모델타입에 대한 인코딩 & 디코딩 해주는 코드를 만들어주게 됩니다. 보통은 이렇게 현업에서 사용 했던 것 같아요.
그럼 매크로는 코드제너레이터와 어떤 차이가 있을까요?
매크로
매크로에 대한 정의는
https://github.com/dart-lang/language/blob/main/working/macros/motivation.md 이곳에 정의되어있습니다.
Metaprogramming라고 설명하고 있는데요.
매크로를 사용한다면 JSON 뿐만 아니라 수많은 Boilerplate code를 줄일 수 있습니다.단순 반복되는 코드를 매크로를 사용하여 줄일 수 있는 것이죠.
다트팀은 개발자가 지루한 작업을 컴파일 타임에 대신 할 수 있는 것을 매크로라고 정의 한 것 같습니다.매크로와 코드 제네레이터 방식은 언뜻보면 의미는 비슷합니다만 자세히 보면 생성시점이 다릅니다.
- 코드 제네레이터는 위에서 설명했듯이 컴파일 이전에 파일을 생성 합니다.
- 매크로는 컴파일 타임에 코드를 생성하게 됩니다.
매크로를 가장 쉽고 편하게 이해할 수 있는 라이브러리가 있습니다.!
바로 Json 패키지 인데요. 해당 라이브러리는 다트팀에서 만든 라이브러리로 JSON 인코딩 & 디코딩을 쉽게 할 수 있도록 만들어진 라이브러리 입니다!
다만 해당 패키지는 stable에 릴리즈 된게 아니라 dart 3.5.0 이상이여만 사용해 볼 수 있습니다.
Macro 문서를 보시고 설치하시면 되요! (플러터 master 채널이나 dev 채널로 바꾸셔야 되요)설치를 완료 후 터미널에 flutter --version 을 하게 되면 dart 버전을 체크 후 3.5.0이면 됩니다.
자 이제 매크로를 사용해 보겠습니다.
먼저 Json타입을 파싱할 모델 타입을 정의합니다.네. 이게 끝입니다. 정의 부분에 fromJson 이라던지 toJson 메서드도 없습니다.
freezed나 json_serializable을 사용했다면 사전에 해야 될 작업도 많았지만 @JsonCodable() 어노테이션만 붙이면 정말 간단히 끝나게 됩니다.
위의 모델타입에 보면 Go to Augmentation 이라는 키워드가 보이고 해당 키워드를 클릭하게 되면
컴파일러가 class를 따로 만들어 fromJson 과 toJson의 메서드를 만들어 준게 보입니다.
저희는 이렇게 간편히 모델타입을 파싱 하면 됩니다..!
정말 간편해 보이지 않나요? ㅎㅎ
저는 프로젝트가 커질수록 코드제너레이트 하는 부분도 귀찮고, 점점 더 오래걸리는게 불편했거든요 ㅠ
그리고 지금은 단순 예로 json을 사용했지만 매크로가 정식으로 사용가능하다면 파싱뿐만 아니라,
다른 중복되는 코드도 굉장히 줄 일 수 있을것 같습니다.
해당 문서를 보시면 다트에서 매크로가 어떻게 클래스를 생성하는지 자세히 나와있습니다.
이상으로 다트 매크로에 대해 알아보았습니다!!
모두 적게 일하고 돈 많이 버세요!!!!