Clean architecture에 대해서 포스팅하다가 좋은 패키지들에 대한 내용 소개가 필요할 거 같아 작성하게 되었다.
사용하기 좋은 패키지
1. Freezed
https://pub.dev/packages/freezed
Clean architecture에서 Domain Layer는 애플리케이션의 핵심 비즈니스 논리를 포함해서 외부 프레임워크나 라이브러리에 의존하지 않아야 하며, 데이터모델을 불변으로 만들어 안정성을 높이는 게 중요하다.
이 Freezed 패키지는 데이터모델을 불변으로 만들어준다. 우선 왜 불변이 필요하냐 라는걸 들어가기 전에, 불변 프로그래밍(Immutable Programming)의 중요성에 대해서 설명이 필요하다.
https://adabeat.com/fp/immutability-in-functional-programming/
간단하게 이야기하자면,
불변프로그래밍이라는 것은, 객체가 생성된 후에는 그 상태를 변경할 수 없도록 하는 프로그래밍 패러다임이다. 복잡한 애플리케이션 개발에서 아주 중요한 역할을 하는데, 코드의 예측 가능성을 높이는데 큰 도움이 된다.
예측이 가능하다, 즉 불변객체는 생성 후 변경할 수 없으므로 코드의 동작을 예측하기가 더 쉬워지며,
상태변경으로 인한 부작용이 적으며,
멀티스레드 환경에서 객체의 상태가 변경되지 않으므로 동시성 문제를 방지하는데 큰 도움이 되며,
새로운 객체는 필요할때만 생성하므로 효율적으로 메모리 관리하가 편하다.
이렇게 불변프로그래밍을 지향하는 코드를 작성하는 데에 있어 Freezed가 아주 적합한 도구라고 할 수 있다.
여담으로 Freezed를 사용하면, json_serializable, Equatable을 따로 사용하지 않아도 된다는 장점이 있다. (Json_serializable은 서버와 주고받는 데이터 형식, Json을 class(객체) 간 변환을 편하게 해주는 패키지이다. Equatable은 객체 동등성, == 을 재정의 해주는 패키지이다.)
2. Get_it
https://pub.dev/packages/get_it
get_it은 의존성 주입할때 좀 더 편리하게 사용할 수 있는 패키지이다.
설명이 길어질 수 있어서 추후 관련 내용을 포스팅하면 링크를 달아서 더 자세하게 알 수 있도록 하겠다. 일단 코드로 비교해 주자면,
/// get_it을 쓰지 않는다면
/// 다음과같이 매번 선언을 하고 사용해야한다.
class MyApp extends StatelessWidget {
final MyServiceA serviceA = MyServiceA();
final MyServiceB serviceB = MyServiceB();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
serviceA.getAll();
serviceB.getFiltedData();
},
child: Text('데이터 가져오기'),
),
),
),
);
}
}
/// get_it을 쓰는경우.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
// GetIt을 사용하여 서비스 A 및 서비스 B 인스턴스를 가져와 작업 수행
GetIt.instance<MyServiceA>().getAll();
GetIt.instance<MyServiceB>().getFiltedData();
},
child: Text('Do Something'),
),
),
),
);
}
}
이렇게 차이가 나지만, 이 내용은 추후 다시 설명하도록 하겠다. 하지만 쓰면 정말 편한 패키지 중 하나이다.
3. Chopper (http, dio, retrofit...)
https://pub.dev/packages/chopper
Chopper는 API 요청을 편리하게 작성할 수 있는 패키지이다. API호출뿐만 아니라 json 처리도 편리하게 할 수 있으며, 데이터 들어오는 것을 interceptor 해서 처리하거나 Converters가 있어서 데이터 변환에도 아주 편리하다. 이와 비슷한 패키지로는 http, dio, retofit 등이 있고 각 패키지들도 장단점이 있으므로 한 번씩 경험해 보기 바란다. (개인적으로 간단하게 사용하기엔 dio가 편했다.)
Chopper는 공식문서가 잘 되어있는 편이라, Interceptor는 어떻게 쓰는지, Converter는 어떻게 활용하는지 자세히 있어서 써보면 좋은 패키지 중 하나라고 생각한다.
아래는 실제로 내가 사용한 코드 중 일부이다.
각 서버마다 구축되어 있는 방식, 오류 던져주는 방식 모두 다 다르므로 참고만 하기 바란다.
4. dartz
https://pub.dev/packages/dartz
dartz는 Either이라는 것을 사용할 수 있는 패키지이다. Either이란, 두 가지의 반환타입을 가질 수 있게 도와준다.
dart언어에서는 항상 하나의 타입만 반환이 가능하다. 하지만 Either를 사용하면 두 가지 타입을 반환할 수 있도록 도와줘서 성공했다면 Right, 실패했다면 Left로 반환하게 된다.
아래 코드를 보자
유저의 데이터를 삭제하는 Usecase이다. Either <ErrorModel, bool>을 반환하여, return right를 하면 bool을 반환하고, return left를 하면 ErrorModel을 반환하는 방식이다.
개인적으로 타입을 하나만 반환하는 것에 굉장히 답답했는데, 이걸로 해소가 되는 거 같아 너무나도 사이다스러운 패키지였다.
개인적으로 dartz를 쓴다면 아래 extension은 꼭 쓰도록 하자 굉장히 편리하다.
import 'package:dartz/dartz.dart';
/// [EitherX]는 Dartz 라이브러리의 [Either] 타입에 대한 확장(extension)입니다.
extension EitherX<L, R> on Either<L, R> {
/// [Either]의 값이 [Right]인 경우 해당 값을 반환합니다.
///
/// 사용 예:
/// ```dart
/// final result = Right(42);
/// final value = result.asRight(); // 42
/// ```
R asRight() => (this as Right).value;
/// [Either]의 값이 [Left]인 경우 해당 값을 반환합니다.
///
/// 사용 예:
/// ```dart
/// final result = Left('Error occurred');
/// final error = result.asLeft(); // 'Error occurred'
/// ```
L asLeft() => (this as Left).value;
}
추천할 패키지는 너무너무너무 많지만 우선 화면에 필요한 패키지들과 쓰면 좋은 정도(?)의 패키지들은 추후 포스팅하도록 하겠다.
'Study > Dart,Flutter' 카테고리의 다른 글
22. [Flutter] 상태 관리(Riverpod)를 이용하여 비동기 관리하기 (0) | 2024.06.20 |
---|---|
21. [Dart] dart의 factory그리고 singleton에 대하여 (2) | 2024.01.13 |
20. [Dart, Flutter] extension활용하여 가독성 높이는 코드작성하기 [2부] (0) | 2024.01.08 |
19. [Dart, Flutter] extension에 대하여 [1부] (0) | 2024.01.08 |
18. [Dart, Flutter] dart enum에 대하여 (0) | 2024.01.08 |