https://www.youtube.com/watch?v=CCtVxzDbZcQ
1. 이건 꼭 알아야 한다[^1]
[? 질문] 이 강의(Flutter 실전 앱 개발: 미국 주식 앱)는 무엇을 만들고, 어떤 실전 역량을 키우게 하는가[^1]
[= 답] 클린 아키텍처를 기반으로 한 미국 주식 검색 앱을 만들면서, 실무에서 자주 마주치는 데이터 불완전성(Null 등) 대응, 로컬 캐싱(Hive), CSV 다운로드·파싱, 검색 디바운싱, 차트 직접 그리기(Canvas/Paint), 테마(다크 모드 포함) 전환과 같은 실전 요소를 다룬다.[^3]
[? 질문] 기존 방식(그냥 JSON 받아서 쓰는 방식)의 문제는 무엇이며, 어떻게 개선하는가[^4]
[= 답] “데이터는 항상 이렇게 올 것”이라는 가정으로 JSON을 그대로 쓰면 Null 섞임 등으로 버그가 날 수 있으므로, **DTO(데이터 전송 객체)**와 래퍼/매퍼 같은 구조를 도입해 데이터 계약을 명확히 하고 안전하게 변환·사용하도록 한다.[^4]
[? 질문] 이 앱의 사용자 흐름(검색/상세/차트/테마)과 내부 처리(네트워크·캐시·성능 최적화)는 어떻게 구성되는가[^9]
[= 답] 최초에는 네트워크에서 주식 목록을 받아 DB에 캐싱하고, 이후 검색은 DB 기반으로 수행하며, 잦은 검색 요청으로 인한 부담을 줄이기 위해 500ms 이내 입력은 취소(디바운싱) 처리한다. 상세 화면에서는 정보를 표시하고, 차트는 라이브러리 없이 직접 캔버스/페인트로 렌더링하며, 테마 전환 시 색상 정보가 이에 맞게 바뀌도록 구성한다.[^9]
2. 큰 그림[^1]
이 콘텐츠는 “오준석의 생존코딩” 채널에서 소개하는 Flutter 강의 안내로, 이전에 진행한 클린 아키텍처 강의의 연장선에서 실제 앱(미국 주식 앱)을 만들며 실전 패턴을 학습하는 강의임을 설명한다.[^3] 특히 데이터 레이어를 더 깊게 다루며, 로컬/리모트 소스 구성, DTO·매퍼, CSV 파싱, 캐싱, UI 차트 드로잉, 테마 전환까지 포함한다.[^27]
- 핵심 메시지 1: 클린 아키텍처 실전 적용을 “화면 2개짜리로 단순해 보이지만” 실제 업무에서 재사용 가능한 형태로 연습한다.[^20]
- 핵심 메시지 2: 데이터 처리의 현실성(Null, 다양한 포맷, CSV 파싱, 캐싱, DTO/래퍼)을 통해 “그냥 JSON 그대로 쓰기”의 한계를 보완한다.[^4]
- 핵심 메시지 3: 사용자 경험/성능 요소(검색 디바운싱, 테마, 차트 직접 렌더링)를 함께 다뤄 앱 완성도를 높인다.[^12]
3. 하나씩 살펴보기[^1]
3.1 인사와 강의의 위치: 이전 ‘클린 아키텍처’ 강의의 연장선[^1]
영상은 강사(오준석)가 인사로 시작하며, 이번 강의가 “전번에 했던 강의 클린아키텍처에 이어서” 진행되는 과정임을 먼저 못 박는다.[^1] 즉, 이미 한 차례 다룬 클린 아키텍처를 계속 활용하는데, 이번에는 그동안 다루지 않았던 실전 요소들을 추가로 얹는다는 흐름이다.[^3]
- 이번 강의는 클린 아키텍처를 계속 활용한다는 점이 전제다.[^3]
- 단순히 UI 만드는 강의가 아니라, “데이터를 다루는 방식”과 “구조화”에 초점이 있음을 초반부터 강조한다.[^3]
3.2 로컬 DB/캐시: sqflite 대신 Hive로 간단 캐시 구현[^3]
강의에서 새롭게 가져가는 기술 요소로, 기존에 흔히 쓰던 sqflite가 아니라 Hive를 사용해 “간단하게 캐시를 구현하는 방법”을 다룬다고 말한다.[^3] 여기서 포인트는 “정교한 관계형 DB를 먼저 떠올리는 방식”이 아니라, 앱에서 흔히 필요한 캐싱(네트워크로 받은 데이터를 로컬에 저장해 재사용)을 가볍게 구현하는 방향이라는 점이다.[^9]
- [h Hive를 사용해 캐시 구현을 다룬다]는 것이 이번 강의의 차별 요소 중 하나로 제시된다.[^3]
- 이후 앱 동작 설명에서도 “네트워크로 받은 다음 DB에 캐싱”이라는 흐름으로 Hive 기반 캐시의 필요성이 연결된다.[^9]
[!NOTE] 캐시를 왜 강조하는가
앱은 최초 로딩 이후에도 동일 데이터를 반복적으로 네트워크에서 가져오면 비효율적이므로, 로컬에 저장해 이후 검색·조회에 활용하는 전략이 실전에서 흔히 쓰인다.[^9]
3.3 “JSON은 항상 완벽하지 않다”: Null 등 불완전 데이터와 DTO/래퍼 도입[^4]
강사는 기존 방식의 문제를 비교적 구체적으로 짚는다. 이전에는 “데이터가 항상 이렇게 들어올 것이다”라는 가정 아래 JSON 데이터를 그대로 받아 활용하는 식이었다고 말한다.[^4] 하지만 실전에서는 이 가정이 깨지며, 그렇게 하면 “버그 같은 게 발생할 수 있다”고 경고한다.[^4]
여기서 제시하는 대표 예시는 데이터에 Null이 섞여 오는 경우다.[^5] 즉, API 응답의 특정 필드가 누락되거나 Null로 오면, 이를 그대로 사용하던 코드가 런타임에서 예외를 내거나 UI 표시가 깨질 수 있다.[^4]
이 문제를 해결하기 위한 학습 요소로 다음을 언급한다.[^6]
- DTO 개념을 다룬다.[^6]
- DTO와 함께 래퍼, 그리고 이후 코드 구조에서 다시 언급되는 매퍼(mapper) 같은 구성요소를 사용한다.[^7]
즉, 네트워크/외부 데이터(JSON, CSV 등)를 앱 내부 도메인/모델에서 바로 쓰지 않고, 중간 계층(DTO/래퍼/매퍼)을 둬서 “외부 데이터의 형태/품질 변화”에 강한 구조로 만든다는 방향을 제시한다.[^27]
[? 질문] 왜 “그냥 JSON을 그대로 받기”가 위험한가[^4]
[= 답] 실제 응답에는 Null이 섞이거나 가정과 다른 형태가 들어올 수 있어, 그대로 사용하면 버그가 발생하기 때문이다.[^5]
[!IMPORTANT] 실전 데이터 처리 관점
외부에서 오는 데이터는 신뢰할 수 없다는 전제를 두고, DTO/래퍼/매퍼로 “앱이 사용할 안전한 형태”로 변환한 뒤 쓰는 흐름을 학습한다는 점을 강조한다.[^6]
3.4 데이터 입력은 JSON만이 아니다: HTML 파싱/CSV 다운로드·파싱 사례[^7]
강사는 실전 상황을 확장해 말한다. 데이터를 가져오는 방식이 “JSON 데이터만 갖고 오는 게 아니라” 다양한 경우가 있을 수 있다고 전제한다.[^7]
- 예로 “HTML 페이지를 파싱한다거나” 같은 케이스를 언급한다.[^7]
- 이번 강의에서는 그중 하나의 사례로 CSV 파일을 다운로드 받아 파싱하는 내용을 넣었다고 말한다.[^8]
이 대목은 “API가 항상 JSON을 주는 게 아니라, 때로는 파일(CSV) 기반으로 제공되거나 다른 포맷을 처리해야 한다”는 실무적 맥락을 전달한다.[^8] 따라서 강의는 네트워크-JSON 파싱에만 머무르지 않고, CSV 다운로드/파싱을 통해 데이터 수집 경로를 넓히는 방향을 포함한다.[^8]
[? 질문] 실전에서 데이터 소스는 왜 다양해지는가[^7]
[= 답] 상황에 따라 JSON뿐 아니라 HTML 파싱, 파일(CSV) 다운로드 등 여러 형태로 데이터를 다뤄야 할 수 있기 때문이다.[^8]
3.5 앱 소개(기능 흐름 1): 미국 주식 목록 수집과 검색 UX[^9]
강의에서 만드는 앱은 “미국 주식” 정보를 다루는 앱이라고 명시한다.[^9] 앱은 먼저 주식 정보를 “쭉 받아 놓고” 사용자가 검색할 수 있게 구성되어 있다.[^10]
- 주식 목록을 받아서 화면에 준비해두고[^10]
- 검색창에서 예시로 “테슬라”를 검색하는 시연을 한다.[^11]
즉, 사용자가 특정 종목명을 입력하면 해당 종목을 찾는 기본적인 주식 검색 앱의 UX를 보여준다.[^11]
3.6 앱 소개(기능 흐름 2): 네트워크 → 캐싱 → DB 기반 검색으로 전환[^12]
검색 동작의 내부 흐름을 비교적 명확히 설명한다.
- 사용자가 검색을 시작하면 “처음에 이 데이터가 네트워크를 통해서 쭉 들어온 다음”[^12]
- 그 데이터가 “데이터베이스에 캐싱”된다.[^13]
- “다음부터는 데이터베이스를 통해서 검색”하게 된다.[^14]
즉, 최초 1회는 네트워크에서 데이터 확보 → 로컬 저장(캐시) → 이후 쿼리는 로컬에서 처리하는 구조다.[^14] 이는 네트워크 비용과 지연을 줄이고, 오프라인/준오프라인 사용성을 개선할 수 있는 전형적 패턴으로 소개된다.[^13]
- [h 최초 네트워크 수신 후 DB 캐싱, 이후 DB 검색]이라는 데이터 흐름이 앱의 핵심 동작 중 하나로 제시된다.[^14]
3.7 성능/부하 대응: 500ms 디바운싱으로 검색 요청 취소[^15]
강사는 DB 기반 검색을 하더라도, 검색창 입력이 발생할 때마다 DB에 검색 요청이 계속 들어가면 “시스템에 부담”이 된다고 설명한다.[^15] 이를 해결하기 위해 “500 밀리세컨 이내에 들어가는 검색어는 캔슬”되도록 하는 디바운싱(debouncing) 기술을 적용했다고 말한다.[^15]
여기서 내용의 핵심은 다음과 같다.
- 검색어 입력은 키를 누를 때마다 이벤트가 발생하므로 요청이 너무 잦아질 수 있다.[^15]
- DB 쿼리 자체가 네트워크보다 빠를 수 있어도, 과도한 호출은 부하를 만든다.[^15]
- 그래서 일정 시간(500ms) 안에 연속 입력이 들어오면 앞선 요청을 취소하고, 사용자가 잠시 멈춘 뒤의 입력에 대해서만 검색을 수행한다.[^15]
[c 500ms 디바운싱으로 잦은 검색 요청을 취소해 성능 부담을 줄인다]라는 메시지가 이 구간에서 명확히 제시된다.[^15]
[!TIP] 디바운싱을 적용하는 의도
사용자가 “테슬라”를 입력할 때ㅌ→테→테ㅅ…처럼 입력이 연속으로 발생한다. 매 입력마다 DB 검색을 하면 낭비가 커서, 일정 시간 안의 입력은 묶어 처리한다는 발상이다.[^15]
3.8 상세 화면: 종목 클릭 시 정보 표시 + 주가 그래프 표시[^16]
검색 결과에서 종목을 “클릭”하면 앱이 “데이터를 또 읽고 와서” 정보를 표시한다고 말한다.[^16] 이 흐름은 목록/검색 화면과 별개로, 상세 화면에서 추가 데이터를 읽어 표시하는 동작을 의미한다.[^16]
상세 화면에서는 다음을 보여준다.
- 종목의 정보를 표시한다.[^17]
- 동시에 주가 그래프를 표시한다.[^17]
이후 차트 구현 방식이 강의의 중요한 학습 포인트로 이어진다.[^18]
3.9 차트 구현의 핵심: 라이브러리 없이 Canvas/Paint로 직접 그리기[^18]
강사는 그래프 렌더링에 대해 “어떤 라이브러리도 일체 사용하지 않고 직접 다 그립니다”라고 강조한다.[^18] 즉, 일반적인 차트 라이브러리(예: fl_chart 등)를 가져다 쓰는 방식이 아니라, Flutter의 기본 드로잉 도구로 구현한다는 뜻이다.[^18]
여기서 다루는 개념으로 다음 키워드를 직접 나열한다.[^19]
- Path
- Canvas
- Paint
이 개념들을 다뤄보지 않은 사람에게는 “좋은 경험이 될 것”이라고 말하며, 단순 UI 위젯 조합을 넘어서 커스텀 드로잉 역량을 얻는다는 점을 내세운다.[^19]
- [h 차트 라이브러리 없이 직접 그리는 경험을 제공]한다는 점이 이 강의의 실전성 포인트로 제시된다.[^18]
[!IMPORTANT] “직접 그리기”의 의미
차트가 필요한 앱을 만들 때 라이브러리를 쓰면 빠르지만, 커스텀 요구(디자인, 상호작용, 성능, 특정 스타일)에 대응하기 어려울 수 있다. 강의는 기본기(Canvas/Paint/Path)를 통해 이런 상황을 대비시키는 방향으로 소개된다.[^18]
3.10 “심플해 보이지만 실전적”: 2개 화면 구성의 의도[^20]
강사는 앱이 “굉장히 심플하고 화면 두 개짜리”로 보일 수 있다고 말한다.[^20] 하지만 그 단순함이 “학습 내용도 단순하다”는 의미가 아니라, 오히려 “실전에서 많이 사용할 수 있는 내용들”을 담았다고 강조한다.[^20]
즉,
- 화면 수는 적어도(2개)[^20]
- 내부 구현은 실무형 요소(데이터 처리, 캐싱, 디바운싱, 커스텀 차트, 테마 등)로 구성되어 있다.[^12]
이로써 강의의 포지셔닝이 “작은 앱으로 실전 기술을 밀도 있게 학습”하는 형태임을 전달한다.[^20]
3.11 테마(다크 모드 포함): 테마 변경에 따라 색상 정보가 동기화되게 구성[^21]
강의 요소로 “테마도 중요한 내용”이라고 별도로 언급한다.[^21] 시연 시점에 화면은 “다크 모드”라고 말하고[^22], 테마를 바꾸면 그에 맞게 “색상 정보가 바뀐다”는 점을 보여준다고 한다.[^24]
즉, 단순히 다크/라이트를 토글하는 데서 끝나는 것이 아니라, 앱의 UI 요소들이 테마 변경에 동기화되어 색상이 자연스럽게 바뀌도록 처리하는 내용을 포함한다는 설명이다.[^24]
- [h 테마 전환과 색상 변경 동기화]가 강의의 학습 요소로 포함된다.[^21]
3.12 코드 구조 공개: Clean Architecture 3레이어 + 유틸, 차트 모듈 분리[^25]
강사는 마지막에 “코드 구조 한번 보여 드리겠습니다”라고 하며 프로젝트 구조를 설명한다.[^25] 언급된 구조는 클린 아키텍처 관점의 레이어링을 따른다.
lib폴더에 data layer가 있고, 그 안에 데이터 관련 파일들이 구성돼 있다고 말한다.[^26]- domain layer에도 구성되어 있다고 한다.[^26]
- main 파일이 있고[^26]
- presentation layer에는 “화면 2개”에 대한 구성이 있으며, “차트 같은 거 별도로 만들어서” 구성돼 있다고 한다.[^26]
- 그리고 util 클래스가 있다고 말한다.[^26]
즉, 앱의 기능(검색/상세/차트/테마)을 레이어별 책임으로 나누고, 차트는 presentation 쪽에서 별도 구성(모듈처럼)해 관리하는 형태를 보여준다.[^26]
3.13 데이터 레이어를 더 ‘심도 있게’: local/remote, DTO, mapper, CSV 파싱 등[^27]
구조를 보여준 뒤 강사는 “데이터 쪽이 조금 더 심도 있게 다루고 있다”라고 정리한다.[^27] 그리고 데이터 레이어에 포함된 구성 요소를 열거한다.[^27]
- 소스가 local, remote로 나뉜다.[^27]
- DTO가 있다.[^27]
- mapper가 있다.[^27]
- CSV 파싱하는 것도 있다.[^27]
즉, 이 강의의 무게중심이 “화면 구성”만이 아니라, 실전 앱에서 어려움을 만드는 데이터 취급(다양한 소스/포맷, 변환 계층, 캐싱)을 클린 아키텍처 안에서 체계적으로 연습하는 데 있음을 다시 강조한다.[^27]
마지막으로 “좀 더 다양한 예제를 나누고 있다”라고 하며 강의에서 만나자고 마무리한다.[^28]
4. 핵심 통찰[^1]
-
[c 앱의 난이도는 화면 개수가 아니라 ‘데이터/구조/성능’에서 결정된다] 겉보기엔 2화면의 단순 앱이어도, 캐싱·Null 대응·포맷 다양성·디바운싱·차트 렌더링·테마 등 실전 요소가 난이도를 만든다는 관점을 제시한다.[^20]
- 실행: “작은 앱”을 만들 때도 네트워크→캐시→조회 흐름과 데이터 변환 계층을 먼저 설계해보는 연습을 한다.[^14]
-
[h 외부 데이터는 신뢰할 수 없으므로 DTO/래퍼/매퍼로 방어해야 한다] JSON을 그대로 쓰면 Null 등으로 버그가 날 수 있다는 문제의식이 강의 설계의 중요한 동기다.[^4]
- 실행: API 응답 모델과 앱 내부 도메인 모델을 분리하고, 변환 지점을 명확히 둔다(매퍼 도입).[^^27]
-
[h “데이터 소스는 JSON뿐”이라는 고정관념을 깨고 CSV 같은 현실 입력을 다룬다] 실전에서는 HTML 파싱, CSV 다운로드 등 다양한 형태가 존재할 수 있음을 전제하고, 그중 CSV 파싱을 학습 요소로 포함한다.[^7]
-
[h 성능 최적화는 사용자 입력 이벤트(검색)에서 체감된다] DB 기반 검색이라도 요청이 과도하면 부담이 될 수 있고, 500ms 디바운싱으로 이를 완화하는 기법을 적용한다.[^15]
- 실행: 검색창/자동완성 기능에는 디바운스(또는 스로틀)를 기본으로 검토한다.[^15]
-
[h 차트 라이브러리 없이 Canvas/Paint로 직접 구현하는 경험은 UI 확장성을 키운다] Path/Canvas/Paint를 다루며 커스텀 드로잉을 직접 해보는 것을 강의의 가치로 제시한다.[^18]
-
[m 테마 전환은 단순 토글이 아니라 “색상 정보 동기화”까지 포함한다] 다크 모드에서 테마 변경 시 색상 정보가 맞춰 바뀌는 내용을 다룬다고 말한다.[^24]
5. 헷갈리는 용어 정리[^3]
클린 아키텍처: 데이터(data)·도메인(domain)·프리젠테이션(presentation) 레이어로 책임을 분리해, 변경에 강하고 테스트/유지보수가 쉬운 구조를 지향하는 설계 접근(영상에서 레이어 구조로 제시).[^26]
Hive: Flutter/Dart에서 사용할 수 있는 로컬 저장소로, 강의에서는 sqflite 대신 캐시 구현에 사용한다고 언급.[^3]
sqflite: Flutter에서 SQLite를 쓰기 위한 패키지로, 이번 강의에서는 “sqflite 말고 Hive”를 사용한다고 대비 언급.[^3]
DTO(Data Transfer Object): 외부(네트워크/파일)에서 들어오는 데이터를 앱 내부로 옮길 때 쓰는 전송용 객체로, Null 등 불완전성을 다루기 위해 도입한다고 설명.[^6]
래퍼(Wrapper): DTO 등 데이터를 감싸 추가 정보/안전성을 제공하는 패턴을 의미하는 맥락으로 언급.[^6]
매퍼(Mapper): DTO 등 외부 형식을 도메인/내부 모델로 변환하는 역할로, 데이터 레이어 구성요소로 열거됨.[^27]
디바운싱(Debouncing): 짧은 시간 안에 연속으로 들어오는 입력/이벤트를 묶고 이전 요청을 취소해 최종 입력만 처리하는 기법(여기서는 500ms 기준).[^15]
Path / Canvas / Paint: Flutter에서 커스텀 그래픽을 직접 그릴 때 사용하는 핵심 구성요소로, 차트를 라이브러리 없이 구현하며 다룬다고 언급.[^19]
참고(콘텐츠 정보)[^1]
- 제목: Flutter 실전 앱 개발 - 미국 주식 앱 (with 클린 아키텍처) 강의 소개[^1]
- 채널: 오준석의 생존코딩[^1]
- 길이: 3분 58초[^1]
- 링크: https://www.youtube.com/watch?v=CCtVxzDbZcQ[^1]
- 키워드: flutter, 플러터, android, 안드로이드, ios[^1]
[^1]: @[00:00]~ "네 안녕하세요" / @[00:02] "생존 코딩 오준석입니다" 및 사용자가 제공한 콘텐츠 메타데이터(제목/채널/길이/링크/키워드).
[^3]: @[00:12] "…전번에 했던 강의 클린아키텍처에이어서… 하이브를 사용… 간단하게 캐시를 구현…"
[^4]: @[00:27] "기존에는 데이터가 항상 이렇게 들어올 것이다라는 가정… 그냥 그대로 받아서… 버그…"
[^5]: @[00:42] "데이터의 널이 섞여 온다던지…"
[^6]: @[00:44] "그래서 dto 개념도 한번 다뤄 봤구요"
[^7]: @[00:48] "dto와 래퍼 … 사용" / @[00:55] "…json 데이터만 갖고 오는게 아니라… html 페이지를 파싱…"
[^8]: @[00:55] "…이번에는 csv 파일을 다운 받아서 파싱…"
[^9]: @[01:02] "앱 소개… 주식 정보를 가지고 와서… 미국 주식"
[^10]: @[01:09] "미국 주식 정보를 이렇게 쭉 받아 놓고 검색"
[^11]: @[01:16] "테슬라 이런 식으로 검색"
[^12]: @[01:24] "처음에… 데이터가 네트워크를 통해서…"
[^13]: @[01:32] "데이터베이스의 캐싱"
[^14]: @[01:40] "다음부터는 데이터베이스를 통해서 검색"
[^15]: @[01:40] "…db에 검색 요청… 부담… 500ms 이내… 캔슬… 디바이싱 기술"
[^16]: @[01:49] "클릭을 했을 때는 데이터를 또 읽고 와서"
[^17]: @[02:02] "정보를 표시하고 주가 그래프를 표시"
[^18]: @[02:02] "그래프… 어떤 라이브러리도 일체 사용하지 않고 직접"
[^19]: @[02:13] "패스 캔버스 페인트…"
[^20]: @[02:24] "…심플… 화면 두 개… 하지만 실전에서 많이 사용할 수 있는…"
[^21]: @[02:24] "…테마도 중요한 내용"
[^22]: @[02:35] "지금 이건… 다크 모드"
[^24]: @[02:58] "색상 정보가 바뀐다라는 거… 다루고 있습니다"
[^25]: @[03:02] "코드 구조 한번 보여 드리겠습니다"
[^26]: @[03:07]~@[03:31] "LIB 폴더… 데이터 레이어… 도메인 레이어… 프리젠테이션 레이어… 화면 2개… 차트… 유틸 클래스"
[^27]: @[03:44] "데이터 쪽… 로컬 리모트… dto… 맵퍼… csv 파싱…"
[^28]: @[03:50] "…다양한 예제… 강의에서 만나도록 하겠습니다"