Hello 👋

[Dart] fromJson constructor는 왜 factory로 만들까?

Overview Dart에서 JSON을 parsing하는 class를 만들 때 fromJson이라는 factory named constructor를 만들곤 한다. class Person { final String name; final int age; Person({required this.name, required this.age}); // ✅ factory Person.fromJson(Map<String, dynamic> json) => Person(name: json["name"], age: json["age"]); } 그런데, fromJson constructor는 factory가 아니어도 아무 문제가 없다. class Person { final String name; final int age; Person({required this.name, required this.age}); // ✅ Person.fromJson1(Map<String, dynamic> json) : name = json["name"], age = json["age"]; } Dart 문서의 예시에서도 fromJson을 factory constructor로 만들고 있다....

September 22, 2024 · 2 min

[Dart] Isolate 요약

Dart isolate 관련 문서들을 참고하여 isolate의 개념 및 동작방식을 요약한다. 참고한 문서 Concurrency in Dart | dart.dev Isolates | dart.dev Concurrency and isolates | Flutter docs Isolate 사용 이유 모든 Dart code는 기본적으로 main isolate에서 실행된다. Main isolates의 event loop는 UI paint, I/O, user input 등 UI 관련 event들을 처리한다. Main isolate에서 시간이 오래 걸리는 작업을 실행하면 event loop가 다음 repaint event 처리 시점을 놓치게 되면서 UI freezing이 발생할 수 있다....

September 21, 2024 · 4 min

[Dart] Understanding null safety

Overview 이 글은 Understanding null safety 문서의 내용을 바탕으로 Dart에서 null safety가 나온 배경 및 null safety의 동작 방식을 쉽게 이해하기 위해 작성하였다. 기본 문법적인 설명들을 제외하고 null safety의 원리를 이해하는데 필요하다고 생각되는 부분들만 정리했기 때문에 원문의 일부 내용이 누락되어 있고 설명하는 순서도 다르다. 빠르게 Dart null safety의 동작 방식에 대해 이해하는 것이 목적이라면 이 글을 이해하는 것으로 충분하겠지만, 더 자세한 설명이 필요하다면 원문을 정독하는 것을 권한다. Null safety가 나온 이유 Dart에서 null은 Null type으로 표현된다....

September 15, 2024 · 6 min

Retry with Exponential Back-Off and Jitter

최근 본 면접에서 새로 알게 된 Exponential Back-Off 라는 개념과 Jitter를 사용한 개선 방법을 공부하고 정리한다. 그리고, Flutter 앱을 개발할 때 이 전략을 활용하기 위해 Dart code로 구현해 본다. Retry Strategy 어떤 system에서 다른 system을 call하는 상황에서 failure는 언제든지 발생할 수 있다. 앱을 개발할 때는 server 부하 또는 일시적인 network 오류 등에 의해 http 요청이 오랜 시간 동안 완료되지 않거나 실패하는 상황을 떠올릴 수 있다. 이러한 일시적인 문제 때문에 client에서 server로 보내는 data가 유실될 수 있는데, 이것을 막기 위해 여러 가지 방법으로 retry 전략을 세운다....

September 13, 2024 · 4 min

[Dart] DI를 위한 interface 만들기

Overview DIP를 준수하는 class 설계를 위해 interface가 필요하다. 이 interface는 일반 class만 사용해도 쉽게 구현할 수 있다. 아래는 clean architecture에서 use case에서 repository 의존성을 분리하여 의존성 흐름이 adapter에서 business logic 계층으로 향하도록 역전시키는 구현 예시이다. Adaptor 계층에서 repository pattern을 사용하여 use case가 repository 의존성을 주입받는다. class Repository { String fetchData() { throw Exception("Not implemented"); }; } class RepositoryImpl extends Repository { @override String fetchData() { return storage.getData(); } } class UseCaseImpl extends UseCase { UseCaseImpl({required this....

September 10, 2024 · 4 min

[Flutter] NumberFormat을 사용해서 통화(currency) formatting 하기

NumberFormat NumberFormat class는 intl package에서 제공하는 local-specific number formatting class “Locale-specific"이란, 문자열을 formatting 할 때 특정 text나 symbol을 locale에 맞게 변환해 주는 것 ICU formatting pattern을 사용해서 number format 지정 0 : a single digit # : a single digit, omitted if the value is zero . : decimal separator ¤(\u00A4) : currency sign Examples NumberFormatter("###.0#").format(12.345); // 12.34 Currency formatting NumberFormatter는 currency formatting을 위한 named constructor를 제공함 NumberFormat.currency(locale,name,symbol,decimalDigits,customPattern) locale : ₩, $ 등 화폐 단위를 표기를 위한 locale name : 화폐 단위로 ISO 4217 code 사용 symbol : 화폐 단위로 custom sign 사용 (name을 덮어씀) decimalDigits : 소수점 아래 자릿수 customPattern : custom pattern 사용 Examples (en locale 기준) NumberFormat....

September 10, 2024 · 2 min

[Flutter] Gradient를 적용하는 두 가지 방법

Flutter는 두 가지 방법으로 gradient를 적용할 수 있다. BoxDecoration 사용 ShaderMask 사용 BoxDecoration BoxDecoration의 gradient 속성에 gradient를 적용한다. Box widget을 gradient로 채울 때 사용한다. Example Container( width: 100, height: 100, decoration: const BoxDecoration( gradient: LinearGradient( colors: [Colors.red, Colors.blue], ), ), ), ShaderMask ShaderMask를 사용해서 특정 widget에 shader를 입힐 수 있다. ShaderMask의 shaderCallback에서 shader 객체를 반환하면 child에 전달한 widget에서 white color인 element에 shader를 입힐 수 있다. shaderCallback 함수는 LinearGradient 등 gradient 객체의 createShader(rect) method를 사용해서 shader를 반환할 수 있다....

September 9, 2024 · 1 min

[Flutter] Modal bottom sheet 상단에 border radius 주기

Scaffold를 사용하는 경우 Modal bottom sheet 안에서 Scaffold의 AppBar를 활용하는 경우 ModalBottomSheetRoute의 border radius와 Clip.hardEdge를 설정한다. showModalBottomSheet()를 사용하는 경우: showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical( top: Radius.circular(24), ), ), clipBehavior: Clip.hardEdge, builder: (context) => Scaffold( appBar: AppBar(...), body: Container(...), ), ) Navigator.push에 ModalBottomSheetRoute를 직접 사용하는 경우: final route = MaterialPageRoute( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical( top: Radius.circular(24), ), ), clipBehavior: Clip.hardEdge, builder: (context) => Scaffold( appBar: AppBar(...), body: Container(....

September 1, 2024 · 2 min

[Flutter] 화면 빈 곳을 tap해서 가상 키보드 닫기

Flutter app에서 TextField 등의 widget을 탭하면 해당 widget의 FocusNode가 활성화되면서 가상 키보드가 나타남 가상 키보드를 닫으려면 해당 widget의 FocusNode를 비활성화(unfocus) 시켜야 한다. FocusScope 사용 FocusScope는 FocusNode를 하나의 group으로 묶어서 관리할 때 사용하는 widget으로, Route가 push될 때 자동으로 생성되어 widget tree에 추가됨 FocusScope.of(context) method가 반환하는 FocusScopeNode는 FocusNode의 subclass로, FocusScope group 안에서 focus를 제어하는 객체 FocusScopeNode의 unfocus()를 호출해서 현재 focusing된 widget(e.g. TextField)을 unfocus 시킨다. FocusScope.of(context).unfocus(); 또는, requestFocus()에 새로운 FocusNode를 전달하여 이전 focus를 해제시킨다....

August 29, 2024 · 2 min

[Dart] Iterable collections

Iterable collections Dart 문서 읽기 Collection과 Iterable Collection : element의 집합을 표현하는 객체 (e.g. List, Set, Map) Iterable : element에 순차적으로 접근할 수 있는 collection의 한 종류 Iterable abstract class를 상속받은 List, Set 등을 통해 Iterable 객체 생성 Map은 key를 사용해서 value를 얻는 방식으로 Iterable이 아님. 단, entries나 values 속성을 통해 key 또는 value group을 Iterable 객체로 읽을 수 있음 Iterable과 List는 element에 접근하는 방법에 차이가 있음 List는 [index] operator를 사용하지만, Iterable은 elementAt(index) method를 사용해서 특정 index의 element에 접근...

August 17, 2024 · 4 min