모바일
Flutter
구글이 개발한 오픈 소스 모바일 애플리케이션 개발 프레임워크이다. 안드로이드, iOS용 애플리케이션 개발을 위해, 또 구글 퓨시아용 애플리케이션 개발의 주된 방식으로 사용된다
StackOverflow 질문 수: 180810
Github Stars : ★ 165861
사용 기업
에이비일팔공
리디
번개장터
엔코위더스
차봇모빌리티
미스터블루
원티드랩
아테나스랩
중고나라
바바그라운드
짠컴퍼니
마켓컬리
마이지놈박스
커리어데이
펫트너
자비스앤빌런즈
웍스메이트
코멘토
더 보기
중고나라
[Flutter] Riverpod을 사용하여 간단하고 효과적인 캐싱 시스템 구축하기
Riverpod을 사용하여 간단하고 효과적인 캐싱 시스템 구축하기Flutter 개발자라면 데이터 관리는 앱의 성능과 사용자 경험에 직접적인 영향을 미친다는 것을 잘 알고 있을 것입니다.특히, 외부 API(OpenAPI)를 통해 데이터를 가져오는 경우 네트워크 지연이나 서버 상태에 따라 앱의 반응 속도가 달라질 수 있습니다.이러한 상황에서 백엔드에게 기본적인 캐싱 기능을 부탁할 수 없는 경우, 앱 내부에서 간단한 캐싱 시스템을 구현하여 성능을 향상시키는 것이 중요합니다.이번 글에서는 Riverpod을 사용하여 로컬 스토리지(Hive 등)를 사용하지 않고도 효과적인 캐싱 시스템을 구현하는 방법을 단계별로 알아보겠습니다.🍄 캐싱의 필요성a. API 호출의 문제점외부 API(OpenAPI)를 사용하여 데이터를 가져오는 경우, 다음과 같은 문제점이 발생할 수 있습니다.네트워크 지연 : 사용자의 네트워크 상태에 따라 API 호출 시간이 달라집니다.서버 응답 지연 : 백엔드 서버의 상태나 부하에 따라 응답 시간이 변동될 수 있습니다.비용 문제 : 빈번한 API 호출은 비용을 증가시킬 수 있습니다.데이터 일관성 : 실시간 데이터가 필요하지 않은 경우에도 불필요한 데이터 요청이 발생할 수 있습니다.b. 내부 캐싱의 장점이러한 문제점을 해결하기 위해 앱 내부에서 간단한 캐싱 시스템을 구현하는 것이 유용합니다. 내부 캐싱의 주요 장점은 다음과 같습니다.성능 향상 : 캐시된 데이터를 즉시 제공하여 앱의 반응 속도를 높입니다.네트워크 비용 절감 : 동일한 데이터에 대한 반복적인 API 호출을 줄여 네트워크 비용을 절감합니다.오프라인 지원 : 네트워크 연결이 불안정하거나 없는 상황에서도 캐시된 데이터를 제공할 수 있습니다.데이터 최신성 유지 : 캐싱 만료 시간을 설정하여 데이터의 최신성을 유지할 수 있습니다.c. 로컬 스토리지 없이 캐싱하기로컬 스토리지(Hive, SharedPreferences 등)를 사용하지 않고도 Riverpod만으로 캐싱 시스템을 구현할 수 있습니다. 이는 다음과 같은 장점을 제공합니다.간결성 : 추가적인 패키지 설치나 설정 없이 Riverpod만으로 캐싱을 관리할 수 있습니다.유연성 : 메모리 내에서 캐시를 관리하므로, 다양한 형태의 데이터를 손쉽게 캐싱할 수 있습니다.성능 : 메모리 기반 캐싱은 디스크 기반 캐싱보다 빠르게 데이터를 접근할 수 있습니다.🧙♂️캐시 매니저 구현효과적인 캐싱 시스템을 구축하기 위해서는 먼저 캐시 매니저(CacheManager) 를 구현해야 합니다. 이 매니저는 다양한 타입의 데이터를 키를 기반으로 저장하고, 캐시의 만료 시간을 관리합니다.a. CacheItem 클래스CacheItem 클래스는 캐시된 데이터를 나타내며, 데이터 자체와 함께 데이터를 저장한 시점을 기록합니다.// cache_item.dartclass CacheItem { final T data; final DateTime timestamp; CacheItem(this.data, this.timestamp);}b. CacheManager
dart
flutter
라인
과격하게 레거시를 쇄신하는 세 가지 방법과 그 사례
안녕하세요. 일본 최대 규모의 음식 배달 서비스 Demaecan(出前館, 이하 데마에칸) 프로덕트를 담당하는 김영재라고 합니다. 어느덧 프로덕트를 쇄신한 지 2년 반이 되어가고 있습니다. 이번 글은 레거시를 해소하면서 서비스를 혁신해 나가는 데마에칸의 여정 중 기록을 남기는 의미로 작성했습니다.레거시의 정의는 다양합니다. 단순히 오래된 코드를 의미하는 경우도 있고, 새로운 서비스 구현에 제약이 되는 기존 구조를 말하기도 합니다. 하지만 사전에 실려 있는 '유산'이라는 긍정적인 의미처럼, 레거시는 지금까지 서 비스가 생존할 수 있게 해준 기반이기도 합니다.레거시에 관한 재미있는 표현도 많습니다.• 어제 내가 작성한 코드는 레거시이다.• 사용자가 한 명이라도 있는 시스템은 레거시이다. 그 한 명이 바로 당신이다.• 레거시를 고칠 바엔 다시 만드는 게 더 빠르다.위와 같은 표현이 셀 수 없이 많을 정도로 엔지니어는 레거시 때문에 웃고 울곤 합니다.데마에칸도 여느 회사처럼 레거시가 있습니다. 아니, 많습니다. 데마에칸은 업력이 20년이 넘은 회사입니다. 다시 말해 20여 년의 레거시가 쌓여 있습니다. 레거시는 코드나 시스템만 의미하지는 않습니다. 스펙이나 업무 프로세스에도 레거시가 있습니다. 예를 들어 점포의 속성 중에 '2-in-1'이라는 것이 있는데요. 이것을 정의하고 구현한 모습은 세 가지가 있었습니다. 회사 안에서도 '2-in-1 점포'라고 말할 때 부서마다 다르게 이해하고 있는 것이죠. 이 또한 레거시라고 말할 수 있습니다.현재 데마에칸은 앱부터 백엔드까지, 백엔드부터 운영 프로세스까지 하나씩 재작성하면서 레거시를 쇄신하는 장기 프로젝트를 진행하고 있습니다. 쇄신하는 방법은 여러 가지가 있는데요. 이번 글에서는 일반적인 방법 외에 조금 색다른 세 가지 방법을 말씀드리고자 합니다.레거시를 해소하는 대표적인 방법으로는 Strangler Fig 패턴이 있습니다. 아래 그림과 같이 새로운 시스템을 마련한 후 조건에 따라 옛 시스템에서 새로운 시스템으로 이행하다가 새로운 시스템이 잘 작동한다는 확신이 들면 옛 시스템으로 가는 경로를 없애고 폐쇄하는 방법입니다. 직접 본 적은 없지만 Strangler Fig라는 나무가 이와 같은 방식으로 생장한다고 합니다.데마에칸에서도 이 방법으로 백엔드의 여러 컴포넌트를 활발히 개선하고 있습니다. 가장 안전하면서도 결과와 일정을 예측하기 쉬운 방법이기에 운영 중인 서비스라면 어디든 적용할 수 있습니다. 데마에칸에서는 결제, 주문, 회원 정보 등 이커머스로서 가장 핵심적인 도메인에 이 방법을 사용하고 있습니다.이 방법의 단점으로는 차근히 개선해 나가는 방식이므로 꽤 오랜 시간이 걸린다는 점과, 안정성을 중시하는 만큼 레거시의 가장 핵심적인 부분은 교체하지 못하는 경우가 많다는 점을 꼽을 수 있습니다. 그래서 보다 극단적인 방법들도 쓰이는데요. 어떤 방법이 있는지 하나씩 사례와 함께 소개하겠습니다.보다 과격하게 레거시를 해소하는 세 가지 방법어떤 방법을 사용하든 레거시를 해소하는 것은 어느 지점에서 레거시를 단절하
flutter
라인
Flutter Web을 활용해 제품 개발 환경 개선하기
안녕하세요. ABC Studio에서 Demaecan(出前館, 이하 데마에칸) 앱을 개발하고 있는 김종식입니다. 데마에칸은 2000년부터 서비스를 시작한 일본 최대 규모의 음식 배달 서비스로 ABC Studio는 2021년 봄부터 프로덕트 개선에 참여하고 있습니다.Flutter 전환의 마침표 - 일본 1위 배달 앱, 세 번째 Recode 글을 통해 데마에칸의 소비자용 앱(이하 ConsumerApp) 서비스를 Flutter 기술로 전환한 작업을 소개 드린 적이 있습니다. Flutter는 단일 코드 베이스를 활용해 다양한 플랫폼의 애플리케이션을 개발할 수 있는 강력한 크로스 플랫폼 프레임워크입니다. 처음 등장한 후 모바일 앱뿐만 아니라 PC나 웹 환경에서도 활용되면서 점점 개선되고 있습니다.사장님용 앱인 MerchantApp과 ManagerApp은 이미 제품 개선 단계에서 Flutter를 이용해 웹 버전을 활용하고 있었습니다. 특히 ManagerApp은 처음부터 테스트용으로 웹 버전을 내부에 함께 배포했는데요. 기획에서부터 디자인, QA에 이르기까지 제품 개발 과정 전반에 큰 도움이 됐다는 의견을 받았습니다. 또한 가맹점용 앱인 RetailerApp 개발 과정에서는 PR(pull request)이 생성되면 웹 빌드 및 배포를 통해 작업 완료 여부를 판단하는 용도로 실험적으로 활용하기도 했습니다.반면 ConsumerApp에서는 개발 과정에서 웹 버전을 활용하고 있지 않았습니다. 웹 버전을 활용하지 않는 상태에서 지난 3월 UI/UX 개선 과제를 완료했는데요. ConsumerApp은 이해관계자가 많은 서비스인데다가 실제 작동 화면을 꼼꼼히 확인하며 진행해야 하는 과제였던 만큼 진행 과정에서 불편함을 느꼈고, 더 빠르고 효율적으로 서비스를 개선할 수 있는 개발 환경이 필요하다고 판단했습니다. 이번 글에서는 그와 같은 환경을 마련하기 위한 시도 중 하나로 ConsumerApp이 웹에서 작동할 수 있도록 개발 환경을 개선한 사례를 소개합니다.웹 환경에서 ConsumerApp 지원 필요성 확인저희는 아래 그림과 같이 6개의 개발 환경에서 ConsumerApp 제품 개선 활 동을 진행하고 있습니다. 각 환경에서는 병렬로 진행되는 과제나 정기 배포 진행 여부를 판단하기 위한 검증을 진행하며, 이를 통해 출시 일정을 유연하게 조정합니다.현재 내부 테스트나 공유를 위해서 Android는 DeployGate, iOS는 TestFlight 서비스를 이용해 실제 기기에서 작업을 확인하고 있는데요. 많은 인원이 함께 만들고 있기 때문에 실제 기기에서 작업을 확인하려면 개인 및 팀 단위로 계정과 기기를 준비해야 하는 등 불필요하게 예산이 낭비될 수 있습니다. 또한 보안을 유지하기 위해 사내 VPN 연결을 해야만 앱 서비스를 사용할 수 있는데 이를 준비하는 과정도 상당히 번거롭습니다. 이와 같은 이유로 프로덕트 메이커 분들은 프로젝트 진행 중 실제 앱 작동을 확인하면서 커뮤니케이션하기가 쉽지 않습니다.Flutter 기술은 출시 후 꾸준히 멀티 플랫폼 환경에서 개선돼 왔습니다. 데마에칸에서 운영 중인 서비스 앱들은 모두 Flutter로 개발하고 있으며, 덕분에 웹 환경에서도 구동이 가능해졌습니다. 이에 앞서 말씀드린 여러 가지 불편함을 개선하기 위해 ConsumerApp도 웹에서 작동을 확인할 수 있는 개발 환경이 구성되면 좋겠다는 제안이 있었고, 향후 앱 제품 개선 과정에 도움이 될 것이라고 기대하며 개발 팀 주도로 ConsumerApp 웹 작동 환경 구성을 진행했습니다.Flutter Web을 이용해 ConsumerApp 웹 개발 환경을 구축한 과정Flutter Web을 이용해 ConsumerApp 웹 작동 환경을 구성하는 과정은 다음과 같은 순서로 진행했습니다.• 빌드 오류가 발생하는 참조 패키지를 웹 지원 버전으로 업데이트• 로컬 개발 환경에서 CORS 이슈 대응• 웹에서 지도 뷰 표시하기먼저 아래와 같이 로컬 개발 환경에서 로그인 화면 진입까지 실행되도록 작업하는 PoC(Proof of Concept)를 진행했습니다. ConsumerApp은 많은 기능을 제공하고 있으며 다양한 패키지를 참조해 구현돼 있기 때문에 초기 구동 환경만 준비돼도 절반의 준비는 성공한 셈입니다(참고로 ConsumerApp은 Flutter 3.19.5를 사용하고 있습니다).PoC 단계에서 작업한 내용을 바탕으로 아래 그림과 같이 웹 실행이 가능하게 만들기 위해 코드 수정 및 리팩토링이 필요한 부분을 작업 단위 목록으로 정리했습니다. 이와 같이 작업을 도출한 덕분에 이후 사이드 이펙트를 최소화하면서 코드 리뷰에 부담되지 않도록 개발을 나눠 진행할 수 있었습니다.PoC 진행 결과를 토대로 설정한 ConsumerApp Flutter Web 버전의 방향은 아래와 같습니다.• ConsumerApp Flutter Web 버전을 최종 사용자에게 제공하는 것은 목표가 아닙니다. 데마에칸은 이미 웹에서도 서비스를 제공하고 있으며, Flutter Web은 실제 서비스로 활용하기에는 초기 구동 속도가 느리고, 웹 환경에서 상용 서비스 수준으로 활용 가능한 도구가 부족한 점 등의 아쉬운 부분이 있기 때문에 준비 단계에서부터 이미 최종 사용자용으로는 고려하지 않았습니다(참고: Flutter Web or React Native Web: Who Will Win the Battle?).• 실제 기기에서 작동하는 모든 기능이 모바일과 웹에서 완벽히 동일하게 작동하도록 만드는 것은 목표가 아닙니다. 기존에 사용하던 패키지 중 웹 환경을 지원하지 않는 패키지도 있었고, 앱에서 제공하는 기능이 웹에서 제공하기에는 적절치 않은 경우도 있었기 때문입니다. 따라서 동일하게 작동하도록 만들기보다는 인앱 웹뷰, 결제 흐름 등 일부 기능 사용에 제약이 있다는 사실을 공유하고 활용하는 방향으로 결정했습니다.• 웹 실행 환경을 팀에 최적화된 혹은 적합한 환경으로 구성하는 것은 목표가 아닙니다. 현재 ConsumerApp에는 6개의 개발 환경이 있는데요. 우선 그중 하나의 환경에서 ConsumerApp을 웹 환경으로 실행해 활용할 수 있는 수준으로 준비하는 것을 목표로 했습니
flutter
라인
Flutter에서 커스텀 린트 활용하기
안녕하세요, ABC Studio에서 Demaecan(出前館, 이하 데마에칸) 앱을 개발하고 있는 김종식입니다. 데마에칸은 2000년부터 서비스를 시작한 일본 최대 규모의 음식 배달 서비스로 ABC Studio는 2021년 봄부터 프로덕트 개선에 참여하고 있습니다.한 팀에서 문법 작성 규칙을 일관되게 유지하는 방법으로 린트(lint)를 활용하는 방법이 있습니다. 이번 글에서는 Flutter에서 기본으로 제공하는 린트 외에 팀에서 필요한 규칙을 새로 만들고 IDE(통합 개발 환경)에서 활용한 사례를 소개하겠습니다. 이 방법을 사용하면 팀 전체가 동일한 코딩 스타일로 개발하도록 유도할 수 있습니다.Flutter에 커스텀 린트를 도입한 배경그동안에는 기획과 디자인, QA뿐 아니라 유관 부서 관계자분들까지 빌드한 앱을 모두 설치해서 확인해야 했습니다. 이때 특정 버전을 정확히 설치해서 확인해야 했기 때문에 잘못된 버전을 설치하면서 오해가 발생하기도 했습니다. 그런데 Flutter는 웹으로도 빌드가 가능합니다. 따라서 제가 담당하고 있는 앱을 웹으로 빌드하면 매번 디바이스에 설치할 필요 없이 즉시 최신 버전으로 확인할 수 있겠다고 생각했습니다.하지만 막상 웹 타깃으로 빌드를 실행해 보니 몇 가지 문제가 있었는데요. 특히 가장 먼저 어떤 플랫폼에서 실행되는지 확인하는 코드를 수정해야 했습니다.Flutter 프로젝트에서 플랫폼을 확인하는 방법에는 몇 가지가 있습니다. 여러 방법 중 와 를 활용하는 방법이 가장 간단할 텐데요. 이 방법을 활용할 경우 웹에서는 아래와 같은 오류가 발생하며 정상적으로 작동하지 않습니다.이에 저희 팀에서는 패키지의 을 참조하는 대신, 패키지의 을 활용해 플랫폼 확인 코드를 래핑한 형태로 과 유사한 구현체를 작성한 뒤, 기존 코드에 사용하고 있는 코드를 변경하는 리팩토링 작업을 수행했습니다. 을 활용하면 또 다른 이점도 있는데요. 각 플랫폼별로 작성해야 하는 로직에 대해서, 을 이용해 플랫폼별 테스트 코드를 작성할 때도 이점이 있습니다.리팩토링 결과는 아래 코드와 같습니다. 이제 프로젝트에서 와 를 더 이상 사용하지 않게 수정했습니다.이 작업에 대한 코드 리뷰를 진행하면서 앞으로 와 사용에 제약을 두는 린트 규칙을 추가하는 것을 논의했는데요. 이 논의가 Flutter 커스텀 린트 도입의 시작입니다.먼저 린트를 사용하는 방법을 알아봅시다. Flutter는 Dart 언어로 작성합니다. Dart 공식 문서에서는 Effective Dart를 통해 코드 작성의 모범 사례를 소개하고 있습니다(Flutter 개발을 하신다면 반드시 한 번 읽어보는 것을 추천합니다 🙂). 이 문서에서는 좋은 코드를 작성하는 여러 규칙을 소개하고 있으며, Dart tools > Linter rules 목록에서 각 규칙의 자세한 내용과 대응 방법을 확인할 수 있는데요. 개인적으로 모든 린트 규칙을 활성화해서 활용하는 것만으로도 팀에서 관리하는 프로젝트의 코드 품질을 충분히 좋은 수준으로 유지할 수 있을 것이라고 생각합니다.Flutter는 앞서 말한 Dart에서의 모범 사례들을 모아서 flutter_lints 패키지로 제공합니다. Dart를 사용할 수 있는 IDE에서는 분석기(analyzer)에서 분석한 결과가 IDE UI로 표시되며, 를 이용해 수동으로 검사할 수도 있습니다.Flutter 프로젝트에서 flutter_lint를 설정하는 방법은 아래와 같습니다.• 린트 패키지 추가하기: pubspec.yaml 파일에 flutter_lints 패키지를 추가하고 flutter pub get 명령을 실행합니다.• 린트 규칙 설정하기: 프로젝트 루트 디렉터리에 analysis_options.yaml 파일을 만들고 필요한 린트 규칙을 설정합니다(보통 파일이 이미 생성돼 있습니다).Flutter에서 커스텀 린트를 추가하는 방법커스텀 린트 규칙을 추가할 수 있도록 공식적으로 지원해 달라는 요청은 오래전부터 꾸준히 있었는데요. 아직 지원되지 않고 있습니다(이와 관련된 이슈는 이 링크를 참조하세요). 현재 사용할 수 있는 방법 중 정석적인 방법으로는 analyze_server를 이용해 분석 결과를 다른 도구와 연계하도록 구성하고 직접 만드는 방법이 있고, analyzer_plugin을 활용하는 방법도 알려져 있습니다. 하지만 이와 같은 방법들은 기본적으로 커스텀 린트를 만들고 관리하는 사용자, 즉 엔지니어에게 친화적이지 않습니다.그 대신 커스텀 린트를 쉽게 작성하고 관리하는 데 사용할 만한 방법으로 custom_lint 패키지를 이용하는 방법이 있습니다. 이 방법의 장점은 다음과 같습니다.• 작성한 목록을 별도로 확인하기 위한 CLI 커맨드를 만들 필요가 없습니다.• 프로젝트 설정이 단순합니다. analyzer 서버의 오류를 대응하지 않아도 custom_lint가 알아서 대응하므로 린트 규칙 작성에만 집중할 수 있습니다.• 핫 리로드(hot-reload)와 핫 리스타트(hot-restart)를 지원합니다. 플러그인 소스 코드를 업데이트하면 IDE와 analyzer_server가 자동으로 재시작됩니다.• 단일 코드 라인 혹은 파일 전체에 린트 규칙 예외를 지정할 수 있는 와 을 지원합니다.• 린트 규칙 구성 과정을 위해 함수와 발생을 지원합니다. 사용자가 출력한 메시지나 오류 출력이 필요하다면 로그 파일(custom_lint.log 파일)을 생성합니다.먼저 와 를 사용하는 경우 린트 오류를 표시하는 규칙( )을 커스텀 린트 패키지로 만드는 것부터 시작합니다(참고로, 이 글은 와 기준으로 정리했습니다).• Dart 프로젝트를 하나 생성해서 pubspec.yaml에 다음과 같이 와 패키지를 참조하도록 설정한 후 명령을 실행합니다.• 생성한 패키지에서 lib/{package_name}.dart 또는 bin/{package_name}.dart 파일을 생성하고 커스텀 린트 규칙을 작성합니다. custom_lint 패키지가 실행되면 함수를 자동으로 실행하도록 돼 있습니다. 이때 대상 파일 이름과 패키지 이름이 동일하게 설정돼 있어야 함수가 정상적으로 호출됩니다. 제대로 설정되지 않은 경우 정상적으로 호출되지 않으며, cust
dart
flutter
nodejs