앱 개발이라는 여정은 마치 퍼즐을 맞추는 일과도 같아요. 처음에는 각각의 조각들이 어디에 들어가는지조차 감이 오지 않지만, 하나씩 배워가며 조각을 맞춰 나가다 보면 어느 순간 전체 그림이 또렷해지죠. 이번 Flutter 숙련 과정은 그 조각들을 효과적으로 맞춰갈 수 있도록 구성된 커리큘럼이었어요.
책검색 앱, 블로그 앱, 마켓 앱, 각각의 프로젝트는 단순히 기능 구현을 넘어 기초부터 실전까지 자연스럽게 연결되는 학습 흐름을 제공했어요. 특히 Firebase, REST API, 소켓 통신까지 다뤄보며, 실제 서비스를 만들 수 있는 기반을 탄탄히 다질 수 있었죠. 이 글에서는 그중에서도 기억에 남는 몇 가지 키포인트를 중심으로, 다시 한 번 정리해보고자 해요.
프로젝트 구조를 이해하는 순간, 모든 게 명확해진다
Flutter는 자유도가 높은 만큼, 프로젝트 구조가 정돈되지 않으면 개발할수록 혼란이 커지기 쉬워요. 그런 의미에서 MVVM 아키텍처를 제대로 익힌 건 매우 큰 수확이었어요. MVVM은 단순히 폴더 구조를 나누는 게 아니라, 책임을 명확히 나누는 설계 패턴이에요. UI는 View, 상태와 로직은 ViewModel, 데이터 처리는 Repository와 Model이 담당하게끔 분리하는 거죠.
이렇게 구조를 나누면 생기는 가장 큰 장점은 유지보수와 테스트가 훨씬 쉬워진다는 것이에요. 예를 들어, 홈 화면에서 리스트를 가져오거나 글을 작성하는 기능이 있을 때, 각 로직을 ViewModel에 깔끔히 정리해두면 UI는 오로지 사용자 입력과 출력에만 집중하면 되거든요. 또한 flutter_riverpod을 사용하면서 상태 관리도 훨씬 명확해졌어요. NotifierProvider를 중심으로 상태와 뷰를 잇는 방식은 단순하면서도 확장성 있게 설계되어 있었죠. ViewModel 내에서 API를 호출하고 상태를 업데이트하면, UI는 자동으로 반응해주니까 복잡한 상태 흐름을 다루는 데도 큰 도움이 됐어요.
이 구조적 접근 덕분에 이후에 Firebase Firestore를 연동하거나, REST API를 통해 데이터를 가져올 때도 어디에 어떤 코드를 넣어야 할지를 명확히 알 수 있었어요. 이건 단순히 기능 구현 이상의 효율성과 확신을 주는 지점이었어요.
데이터를 다루는 법을 배운 순간, 앱이 살아 움직인다
앱의 핵심은 데이터를 다루는 능력이라고 해도 과언이 아니에요. 화면이 예뻐도, 사용자의 입력을 받아 서버와 통신하고 결과를 보여주는 과정이 자연스럽지 않다면 좋은 사용자 경험을 만들기 어려우니까요.
Flutter 숙련 과정에서 가장 많은 걸 배운 파트가 바로 이 데이터 통신 부분이었어요. 먼저 Firebase Firestore를 활용한 블로그 앱에서는 비동기 처리의 개념과 문서 중심 데이터 설계를 실감 있게 배울 수 있었어요. Firebase는 곧바로 데이터를 저장하고 실시간 반영까지 해주는 덕에, ‘쓰기-읽기’ 흐름을 빠르게 경험할 수 있었고요. 특히 이미지 업로드를 위해 firebase_storage를 활용하면서 비동기 업로드 처리와 권한 설정의 중요성도 함께 익힐 수 있었어요.
반면, 마켓 앱에서는 전통적인 REST API 방식으로 데이터를 가져오는 방법을 배웠어요. GET, POST, PATCH, DELETE 요청을 직접 다뤄보면서 API 호출 구조와 HTTP 상태 코드에 익숙해졌고, dio를 사용한 커스텀 클라이언트 구성도 자연스럽게 이해할 수 있었죠. 이때 중요한 건 단순히 API를 호출하는 게 아니라, 에러 처리와 JSON 파싱까지 포함한 전체 흐름을 파악하는 것이었어요.
예를 들어, 다음과 같은 코드를 통해 API 요청과 에러 핸들링의 구조를 체계화했어요.
try {
final response = await dio.get('$baseUrl/products');
if (response.statusCode == 200) {
final products = List<Product>.from(response.data.map((e) => Product.fromJson(e)));
return products;
} else {
throw Exception('서버 오류: ${response.statusCode}');
}
} catch (e) {
print('네트워크 오류: $e');
return [];
}
이런 코드 구조를 반복하면서 “실제 서비스에서는 어떤 문제가 자주 생기는지”도 감을 잡게 되었어요. 예를 들어 인증 토큰 누락, 서버 응답 지연, JSON 구조 변경 같은 예상치 못한 변수들 말이죠. 이걸 해결하는 과정에서 interceptor, try-catch, DTO 클래스 설계의 중요성이 절실히 느껴졌어요.
결국 이 모든 과정은 단순한 기술 학습을 넘어, 사용자와 서버 사이에서 일어나는 모든 일을 예측하고 대비할 수 있는 시야를 갖게 해줬다고 생각해요.
실시간 기능까지! 소켓 통신과 채팅의 묘미
Flutter 앱에서 실시간 기능을 구현한다는 건 꽤 도전적인 일이에요. 하지만 stomp_dart_client를 사용해서 웹소켓 기반의 실시간 채팅 기능을 직접 구현해보면서, 이 부분에 대한 자신감도 크게 얻을 수 있었어요.
특히 기억에 남는 건, 단순히 소켓 연결만 하는 게 아니라 구독(PUB/SUB) 방식으로 메시지를 주고받고, 이를 Stream을 통해 UI에 반영하는 구조를 만들었다는 것이에요. 처음에는 StompClient의 onConnect, subscribe, send 등의 흐름이 헷갈릴 수 있었지만, 한 번 구조를 잡고 나면 이후에는 새로운 메시지 수신이나 전송 로직도 쉽게 추가할 수 있었어요.
또 하나 중요한 포인트는 소켓 연결 관리였어요. 앱이 종료되거나 채팅을 나갔을 때 소켓 연결을 정리하는 로직이 빠지면 메모리 누수나 예기치 않은 에러가 발생할 수 있기 때문에, onDispose() 같은 라이프사이클 훅을 적극적으로 활용해야 했죠.
이 실습을 통해 얻은 가장 큰 교훈은, Flutter에서도 충분히 실시간 기능을 안정적으로 구현할 수 있다는 확신이었어요. 실시간 알림, 채팅, 상태 공유 등 다양한 기능에 도전해볼 수 있는 기반이 되어주었습니다.
마치며...
이번 Flutter 숙련 과정은 단순히 기능을 구현해보는 수준을 넘어서, 앱을 하나의 제품으로 만들기 위해 필요한 사고방식과 기술 스택을 익히는 여정이었어요. MVVM 아키텍처를 중심으로 한 프로젝트 구조, Firebase와 REST API를 통한 데이터 처리, 소켓 통신 기반의 실시간 기능까지 어느 하나 빠짐없이 앱 개발의 본질을 짚어볼 수 있었죠.
무엇보다도 중요한 건, 이 과정을 통해 "Flutter로 어떤 앱이든 만들 수 있겠다"는 자신감을 얻었다는 거예요. 초반에는 버튼 하나 만드는 것도 어렵게 느껴졌던 Flutter가, 이제는 머릿속에 있는 아이디어를 빠르게 구현할 수 있는 도구가 되었어요.
이 글이 Flutter를 공부하는 다른 분들께도 작지만 실용적인 가이드가 되었으면 좋겠고, 혹시 아직 시작을 망설이고 있다면, 지금 바로 Flutter로 첫 앱을 만들어보는 것만큼 좋은 시작은 없다는 말을 전하고 싶어요. Flutter, 생각보다 훨씬 재밌고 강력한 친구입니다.
'IT' 카테고리의 다른 글
플러터, 앱 구조 가이드 학습하기 (0) | 2025.04.25 |
---|---|
REST API 한 큐에 이해하기 (0) | 2025.04.21 |
앱 UI 구현, 무엇부터 시작해야 할까요? (0) | 2025.04.18 |
[항해플러스 | 항해99] 1인 개발자를 위한 백엔드 부트캠프, 할인코드 있어요! (2) | 2025.04.17 |
채팅 기능이 필요할 땐 Socket (2) | 2025.04.17 |