3기 김태영
1시간 전•

10월 29일 일지

10월 29일

오늘 공부에 투자한 순수한 시간: 5시간

학습한 개념 : 구독관리앱의 데이터 아키텍처 및 단계별 학습

## 1. 데이터 아키텍처

### 1.1 주요 데이터 모델

`Service`, `Subscription`, `ScanResult`, `Candidate` 등

CatalogService -> CatalogRepository가 이 Db의 서비스 행과 패키지 행을 합쳐서 생성하고, 스캔 대상이 되고, Scan 시트의 검색과 등록 form에서 사용된다.

ScanResult -> CatalogService를 Android가 스캔해서 스캔 시각, 사용 기록 권한 여부, 설치가 확인된 앱, 패키지별 사용 기록 데이터를 담는 데이터 모델이다. -> 실제 후보 계산과 Scan시트의 권한을 안내하는 기능에서 사용된다.

Candidate -> 계산을 통해서 후보시트에 담길 서비스앱들의 ID, 이름, 카테고리, 점수, lidely와 installed 두 그룹의 데이터를 담는 데이터 모델 -> Scan후보시트를 그릴때 이 데이터를 보고 목록을 그린다.

Subscription -> 사용자가 확정한 서비스의이름, 금액, 통화, 결제주기 및 일자, 카테고리 메모 데이터를 담고, create로 SQLite행 수정하고, Repository의 _fromRow()가 Dart 데이터 객체로 변환한다.

DB 테이블은 디스크에 저장할(영속성 보장) 열과 관계의 정의이고, Dart 모델은 앱이 계산, 표시할 떄 쓰는 메모리 객체이다. 둘사이의변환을 Repository가 맡는다.

SQLite의 subscriptions 테이블이 변경되면, Drift의 query.watch()가 쿼리를 다시 실행하고, 조회 결과를SubscriptionRow 목록으로 받고, Repository의 _fromRow()가 각 행을 Subscription으로변환하고, 이 데이터 모델들의행을 전부 모아 놓은 List<Subscription>을 subscriptionsProvider에 전달하는 것이다.

Repository가 DB 행을 앱의 Dart 모델로 변환해 제공함으로써, 화면과 계산 코드가 DB 구현에 직접 의존하지 않도록 경계를 만들기 위한 것이다.

### 1.2 저장 구조

- 카탈로그 JSON과 SQLite

-> Catalog.json은 앱에 포함되어 배포되는 원본 데이터이다. 앱 시작시 seeder가 Json의 catalogversion과 DB의catalog_mete 버전을 비교한다. 버전이 다르면 카탈로그 관련 세 테이블을 트랜잭션 안에서 갱신하고, 같으면 다시 쓰지 않는다.

따라서 "JSON은 배포할 서비스 명단이고 SQlite의 카탈로그행은 앱이 실행중 조회할 형태 라고 할 수 있다."

또한 catalogRepository가 SQlite의 서비스 및 패키지 행을 읽어서 CatalogService 데이터모델을 만든다.

- 구독 원본 데이터

-> 구독 원본 데이터는 사용자가 구독 서비스앱을 추가하거나 수정하는 데이터를 저장하는 subscriptions SQLite 데이터 테이블이고, subscription Dart 데이터 모델은 DB의 데이터 행을 Repository가 Dart 데이터 모델로 변환해서 화면 부분에서 사용할 수 있도록 만든 데이터 모델이다.

- 메모리 상태 및 계산 결과

-> 사용자가 확정한 구독은금액과 결제일을 포함하므로 앱을 다시 열어도 남아야 한다.

하지만 ScanResult는기기의 현재 상태에서 다시 얻을 수 있으므로 DB 테이블로 저장하지 않는다. 기기의현재 상태에서 매번 다시 얻을 수 있는 이유는 ScanResult는 후보 계산에 쓰이는 일시적인 조회 결과이기 때문에 DB에 저장하지 않아도 되는 것이고, 이로 인해 스캔을 요청할때 Android에 다시 물어 새 결과를 만들어서 ScanResult에는 조회 시각, 설치 앱 목록, 사용 기록 권한 여부, 조회 가능한 사용 기록이 저장될 수 있다.

- 설정 데이터

### 1.3 데이터의 원본과 생명주기

각 데이터의 생성, 조회, 변경, 삭제, 재생성 조건

Catalog.json과 SQLite의 네가지 테이블이 이 앱에서의 가장 근원적이고, 사라지지 않는 원본 데이터이다.

사용자가 등록한 구독 데이터들의 원본은 전부 SQLite에 저장된다. 또한 설치 앱 및 사용 기록 데이터의 원본은 조회 시점에 Android가 제공하는 데이터이다. 마지막으로 알림 설정기능에 입력값으로 들어가는 데이터의 원본은 SharedPreferences에 저장된 데이터이다.

이 원본 데이터들이 앱에서 어떤 형태로 사용이 되는지를 아는 것은 굉장히 중요하다, Repository 디자인 패턴과 Provider 라이브러리를 통해 원본의 형태를 Dart 데이터 델로 변환해서 앱이 사용하기 때문이다.

catalog.json이 원본인 서비스 카탈로그 데이터는 SQLite에 옮겨 둔 서비스 데이터를 CatalogRepository가 서비스행과 패키지 행을 합쳐서 CatalogService라는 Dart데이터 객체로 변환해서 앱이 사용한다.

SQLite이 subscriptions 테이블이 원본인 사용자가 등록한 구독 데이터는 Repository가 읽어서 Subscription Dart 데이터 모델로 변환해서 앱이 데이터를 사용한다.

Android가 제공하는 데이터가 원본인 설치 앱 및 사용 기록 데이터는 ScanResult라는 메모리 데이터 모델에 담아서 Scan 후보 시트에 구독 서비스 목록을 반영할때 ScanResult 데이터를 사용한다.

SharedPreferences에 저장된 데이터값을 원본으로 하는 알림 설정 데이터는 NotificationSetting라는데이터 모델로 변환되어서 앱이 해당 데이터를사용한다.

마지막으로 후보, 대시보드, 합계, 통계 데이터는 거의 모든 원본 데이터들을 Dart 데이터 모델 각가의 데이터들이 입력값으로 전달되어 순수계산 함수를 통한 결과값으로 사용된다.

---

# PART II. 1~4단계 심층 분석

목적: 각 단계에 동일한 세 가지 분석 관점을 적용하여 구조, 작동, 연결을 체계적으로 설명한다.

## 2. 제1단계 — 프로젝트 기반과 카탈로그 구축

### 2.1 구조와 책임

- 초기 프로젝트 구조

-> 프로젝트를 실행할 기반을 만들고, 내장 카탈로그(catalog.json)를 SQLite에서 조회할 수 있게 준비하는 것이다.

- catalog\_seeder, catalog\_repository의 역할

둘 다 AppDatabase를 사용하지만 역할이 다르다.

catalog_seeder는 앱 시작 때 DB사본을 준비해서 SQlite에서 데이터를 조회할 수 있게 해주고, Repository는 이 DB SQLite를 읽어서 Dart 데이터 모델 객체로 변환해서 앱이 데이터를 사용할 수 있도록 해주는역할이다.

- 모델과 Provider의 관계

-> 모델은 “데이터가 어떤 모습인가”를 정하고, Provider는 “그 데이터를 앱의 필요한 곳에 어떻게 제공할까” 이다.

CatalogService에는 서비스 ID, 이름, 카테고리, 패키지 이름 목록 같은 필드가 정의돼 있고, 스스로 DB를 읽거나 화면에 전달하지 않는다. 반면 catalogServicesProvider는 Repository의 getAll()을 호출해서 그모델들의 목록을 제공한다.

DB행을 CatalogService로 변환하는 일은 Provider가 아니라 Repository에서 하는 것이다.

### 2.2 데이터와 실행 흐름

- JSON → SQLite 시드 과정

-> seedIfNeeded()가 catalog.json을 String으로 읽고, jsonDecode로 Map<String, dynamic> 형태로 해석한다. 여기서 catalogVersion은 int, services는 JSON 항목들의 목록으로 꺼낸다.

- 카탈로그 버전 확인 및 갱신

-> catalogversion은 int, services는 JSON 항목들의 목록으로 꺼내고, 그 다음 SQLite의 catalog_meta에서 catalog_version을 읽는다.

버전이 같으면 카탈로그 행을 다시 쓰지않고 종료하고, 버전이 다르거나 기록이 없으면, 트랜잭션 안에서 기존 카탈로그용 세 테이블의 내용을 지우고 JSON 항목들을 다시 넣는다.

- Repository를 통한 조회

-> 시드가 끝나면 main()은 그 ApDatabase 객체를 ProviderScope에 연결한다. 이후 catalogServicesProvider가 사용되면 catalogRepositoryProvider가 DB 객체를 받아 catalogRepository를 만들고 getAll()을 호출한다.

여기서 geAll()은 services와 service_packages를 각각 조회한다. 조회 결과는 Drft가 만든 ServiceRow, ServicePackageRow 같은 DB행 객체이다. Repository는 ServiceId를 기준으로 패키지 이름들을 모아서 CatalogService라는 Dart 데이터 모델로 변환한다.

- 데이터를 모델로 전달하는 과정

-> catalogServicesProvider는Repository가 반환한 List<CatalogService>를 제공하는 FutureProvider이다.

화면은 이를 읽으며 로딩, 데이터, 오류 상태를 다룰 수 있고, 스캔 쪽 코드는 .future로 목록이 준비될 깨까지 기다린다.

### 2.3 연결과 영향

- 2단계 스캔에 제공하는 데이터

-> 카탈로그의 package를 모아 Android에 설치 여부, 사용 기록을 조회할 이름으로 잔달해준다. 전달해주는 주체는 Provider이다.

- 3단계 점수 계산에 제공하는 데이터

-> 카탈로그 서비스, 스캔결과, 등록된 구독을 합쳐 후보를 계산하기 위한 입력값으로 들어가고, 카탈로그의 likelihood도 점수 입력 데이터로 전달된다.

- 이후 구독 관리 기능에서 재사용되는 DB 구조

사용자가 구독 금액을 수정하면 카탈로그가 바귀는 것이 아니라 subscription의 해당 행이 바뀐다. subscriptionRepository.watch()이 새 목록을 제공하고 subscriptionsProvider가 이를 받는다. 그 목록을 사용하는 홈, 대시보드, 달려, 통계가 새 값으로 표시 및 계산된다.

여기서 등록 서비스 ID가 달라지면 후보 목록의 제외 여부도 다시 계산된다.

- 카탈로그 변경 시 영향을 받는 구성 요소

-> 카탈로그에서의 서비스 이름이나 검색어를 바꾸면 시트 검색, 자동완성 기능에 영향으로 주고, likelihood를 바꾸면 후보 점수에 영향을 분다.

반면 기존 사용자 구독의 이름과 금액은 카탈로그 시드가 다시 써 주지 않는다. 왜냐하면 그 값들은 subscriptions행에 별도로 저장돼 있기 때문이다.

## 3. 제2단계 — Android 설치 앱 스캔

2단계는 카탈로그의 Android 앱 설치 여부와, 권한이 있을 때 사용 기록을 조회한다. 결과인 ScanResult는 3단계 후보 계산에 넘긴다. 설치만으로 유료 구독이 확인되지 않으므로 subscriptions에는 저장하지 않는다.

### 3.1 구조와 책임

- Flutter와 Kotlin

-> Flutter는 조회할 패키지를 준비하고 요청을 관리한다. Kotlin `DeviceScanImpl`은 설치·사용 기록을 읽는다. 구독 가능성은 이후 Dart 코드가 판단한다.

- Pigeon과 Repository

-> pigeonsdevicescan는 네 호출(getInstalled, hasUsagePermission, openUsageSettings, getUsage)과 전달 값 InstalledApp·UsageInfo를 정한다. 생성된 Dart device_scan_api.dart와 Kotlin DeviceScanApi.g.kt가 호출을 잇고 MainActivity.kt가 구현체를 등록한다. PigeonDeviceScanRepository는 전송 값을 ScanResult로 조립하고 권한·캐시·실패를 다룬다.

- Android 조회 도구

-> PackageManager는 요청된 패키지의 설치 및 활성화 여부를, UsageStatsManager는 권한이 있을 때 30일 사용 시간과 7일 활동일을 조회한다.

### 3.2 데이터와 실행 흐름

- 조회 목록 만들기

-> scanResultProvider는 catalogServicesProvider.future를 기다리고 CatalogService.packages를 펼쳐 중복을 제거한다. 이렇게 만든 List<String>에는 서비스 이름 대신 com.netflix.mediaclient 같은 패키지 이름이 들어간다. MainShell이 Provider를 관찰해 스캔을 시작한다.

- Flutter에서 Android까지

-> DeviceScanRepository.scan()은 진행 중인 요청이 있으면 같은 Future를 돌려준다. 새 요청은 권한·캐시를 확인하고 Pigeon의 getInstalled(packageNames)를 await한다. Kotlin이 설치 앱을 반환하면, 권한이 있을 때 설치된 패키지만 getUsage()로 조회한다. 두 호출은 Kotlin의 백그라운드 작업이다.

카탈로그 패키지 → scanResultProvider → Repository → Pigeon → Kotlin → Android API → ScanResult

- 결과 만들기와 기록 없음의 의미

-> Repository는 Pigeon 값을 앱 모델 InstalledApp·UsageInfo로 옮기고 조회 시각·권한·설치 앱·사용 기록을 ScanResult에 담는다. 정상 조회한 0인 기록과, 권한이 없거나 조회에 실패해 usageData == null인 상태는 다르다. 뒤의 경우를 3단계에서 0점으로 판단하면 안 된다.

- 10분 캐시와 실패

-> Repository는 결과를 메모리에서 10분 미만 재사용한다. 패키지나 권한이 바뀌면 재조회한다. 설치 조회 실패는 빈 목록, 사용 기록 조회 실패는 설치 목록을 유지한 usageData == null로 표현한다. 캐시는 재시작하면 사라진다.

### 3.3 연결과 영향

- 카탈로그, 스캔, 후보의 관계

-> 카탈로그가 조회 대상을 정하고 `ScanResult`가 기기의 사실을 담는다. 3단계는 등록 구독과 합쳐 후보를 만든다. 설치와 구독은 다른 사실이므로 설치 앱을 바로 subscriptions에 넣지 않는다.

- 권한 변경과 앱 복귀

-> 권한이 없어도 설치 여부는 조회한다. 권한 변경 후 앱에 돌아오면 MainShell이 scanResultProvider를 무효화해 새 결과를 후보 계산에 전달한다.

## 4. 제3단계 — 구독 후보 점수 계산 엔진

3단계는 설치·사용 기록을 등록 후보로 바꾼다. 설치가 결제의 증거는 아니므로 카탈로그·사용 기록·등록 구독을 함께 보고 `likely`와 `installed` 목록을 만든다.

### 4.1 구조와 책임

- 점수를 계산하는 함수

-> calculateCandidateScore()는 카탈로그 likelihood, 합산된 UsageInfo, now로 L·최근 사용 R·30일 사용 시간 U·7일 활동 빈도 F를 계산한다. Android나 DB에는 접근하지 않는다.

- 후보를 만들고 분류하는 함수

-> buildCandidateGroups()는 List<CatalogService>, ScanResult, List<Subscription>, now를 받는다. 설치되고 아직 등록되지 않은 서비스를 골라 여러 패키지 사용량을 합치고 점수를 계산해 CandidateGroups에 분류한다. 점수 함수는 가능성의 크기, 후보 함수는 목록 소속을 정한다.

- 상수와 Provider

-> scoring_constants.dart는 계수·가중치·likely 기준 0.4를 보관한다. currentCandidateGroupsProvider는 카탈로그·스캔·구독 Provider를 관찰하고 candidateGroupsProvider의 계산 결과를 제공한다.

### 4.2 데이터와 실행 흐름

- 세 입력이 합쳐지는 순서

-> catalogServicesProvider는 서비스 ID·패키지·likelihood, scanResultProvider는 설치·사용 기록, subscriptionsProvider는 등록 구독을 제공한다. 패키지로 앱과 서비스를 연결하고 등록된 serviceId는 제외한다. 금액·결제일은 사용하지 않는다.

카탈로그 + ScanResult + 등록 구독 → buildCandidateGroups() → CandidateGroups → Scan 시트

- L·R·U·F를 점수로 만드는 과정

-> 실제 공식은 `L × (0.3R + 0.4U + 0.3F)`이다. L은 사용 기록을 구독 근거로 얼마나 믿을지 정하는 계수로 `exclusive` 1.0, `ambiguous` 0.3이다. R은 마지막 사용이 1·3·7·14일 이내면 차례로 1.0·0.8·0.6·0.3, 이후는 0이다. U는 30일 사용 시간이 10시간 이상 1.0, 2시간 이상 0.7, 1시간 이상 0.4, 그 미만은 0이다. F는 최근 7일 중 사용한 날짜 수÷7이다.

예를 들어 exclusive 서비스를 하루 이내, 30일간 15시간, 최근 7일 중 5일 사용했다면 1 × (0.3×1 + 0.4×1 + 0.3×5/7) ≈ 0.914286으로 likely다. ambiguous의 최고 점수는 0.3이므로 likely가 될 수 없다.

- 여러 패키지와 기록이 없을 때

-> 여러 패키지는 최근 사용 시각의 최댓값, 사용 시간의 합계, 활동일의 비트 OR로 합친다. 같은 날 두 앱을 써도 하루이다. usageData == null이면 0점 대신 점수 없는 installed에 둔다. 점수와 sortOrder로 정렬해 Scan 시트에 보인다.

### 4.3 연결과 영향

- 등록·삭제 후 후보가 바뀌는 경로

-> 등록 시 SubscriptionRepository.create()가 DB에 쓰면 watchAll()이 새 목록을 subscriptionsProvider에 제공한다. 이를 관찰하는 currentCandidateGroupsProvider가 다시 계산해 등록 서비스를 후보에서 뺀다. 삭제 후에도 설치돼 있다면 다시 나타난다.

- 입력과 기준이 바뀌는 경우

-> 패키지 목록은 서비스 연결, likelihood는 L, 새 스캔은 R·U·F를 바꾼다. 가중치·0.4 기준도 분류를 바꿀 수 있다. 구독 금액은 점수 입력이 아니다.

## 5. 제4단계 — 홈 화면과 대시보드

4단계는 저장된 구독을 홈 목록과 금액으로 보여준다. 구독 목록은 원본이고 이번 달·이번 주 금액은 목록과 날짜로 만든 계산 결과이다.

### 5.1 구조와 책임

- Repository와 Provider

-> SubscriptionRepository.watchAll()은 subscriptions 테이블을 감시하고 Drift 행을 _fromRow()로 Dart Subscription에 바꾼다. subscriptionRepositoryProvider가 AppDatabase를 Repository에 연결하고 subscriptionsProvider가 목록을 화면에 제공한다. 화면은 SQL을 직접 다루지 않는다.

- 계산과 화면

-> dashboardProvider는 목록과 날짜를 calculateDashboard()에 넣어 DashboardSummary를 얻는다.

MainShell은 탭, HomeScreen은 날짜·사용자 동작, HomeContent는 카드·목록 조립, DashboardCard는 표시를 맡는다. 정렬·필터·달력은 후속 단계가 반영된 현재 모습이다.

### 5.2 데이터와 실행 흐름

- DB에서 대시보드까지

-> DB 변경 후 query.watch()가 새 행을 내보내면 Repository가 Subscription으로 변환한다. subscriptionsProvider의 새 목록을 받은 HomeContent는 전체 목록과 today를 dashboardProvider에 넣고, 계산된 요약을 카드에 전달한다. 순서는 SQLite → Drift watch → Repository._fromRow() → subscriptionsProvider → HomeContent → dashboardProvider → DashboardCard`이다.

- 다음 결제일과 금액

-> nextBillingDate(subscription, referenceDate)는 기준일 당일 또는 이후의 월간·연간 결제일을 구한다. 31일 구독은 2월 계산에서만 말일로 맞추고 DB의 billingDay = 31은 유지한다. calculateDashboard()는 월초~다음 달 월초 전, 월요일~다음 월요일 전의 결제를 합산한다. 기간 시작일을 기준으로 하므로 이미 지난 이번 달 결제와 해당 기간의 연간 결제도 포함한다. 연간 예상액은 월간 금액×12와 연간 금액의 합이며, 원화·달러는 따로 센다.

- 전체 목록과 표시 목록

-> 대시보드는 items 전체로 계산한다. 정렬·필터된 visible은 목록과 달력에 사용하므로 특정 카테고리만 보여도 대시보드의 전체 금액은 변하지 않는다.

### 5.3 연결과 영향

- 등록·수정·삭제 후 화면 갱신

-> 1단계 구독 테이블이 출발점이다. 5·6단계의 create()·update()·deleteById()가 DB를 바꾸면 Drift watch()가 새 행을 읽는다. Repository가 새 구독 목록을 만들고 `subscriptionsProvider`가 전달하면 HomeContent가 대시보드를 다시 계산한다. 카드 숫자를 직접 고치지 않고 변경된 구독 원본 전체에서 결과를 다시 만든다.

- 날짜와 후속 기능

-> DB가 그대로여도 날짜가 바뀌면 기간 범위가 달라진다. HomeScreen은 자정과 앱 복귀에 갱신하고, 7단계 달력과 8단계 통계도 같은 Subscription·nextBillingDate()를 사용한다.

키워드

ㄴ꼬리질문1 CatalogService는 어떤 흐름을 거쳐서 만들어지는 데이터 모델인거야?

ㄴ꼬리질문2 그럼 Catalogservice는 스캔이 일어나기 전의 데이터 모델인거야?

ㄴ꼬리질문3 SQLite의 service와 service_package 부분을 합쳐서 Dart 모델로 변환하기 위해서인거지? 또한 이렇게 Dart 모델로 바꾼 이유는 화면 쪽이 이 데이터가 어디에서온 데이터인지 모를 수 있도록 하기 위한 것 맞지?

ㄴ꼬리질문4 화면과 스캔 기능이 같은 형태의 서비스데이터를 사용하게 한다는게 무슨 말이야?

ㄴ꼬리질문5 같은 데이터 모델에서 서로 다른 데이터를 필요로 한다는 것으로 이해해도 되는거야?

ㄴ꼬리질문6 subscriptions가 SQLite테이블이고, subscription은 뭔지 설명해줘

ㄴ꼬리질문7 SubscriptionRow 는 subscriptionRepository안에 있는 메서드인거야?

ㄴ꼬리질문8 DB데이터와 Dart 데이터 객체로 바꾸는 이유가 의존성을 최대한 지키기 위해 설계한것이지?

ㄴ꼬리질문9 SQLite의 테이블이 변하면 Drift의 SubscriptionRow로 읽히고, 이를 Repository가 _fromRow()을 통해서 DB의 문자열 데이터를 Dart의 데이터 모델로 변환하고, 이를 watch()가읽고 이 목록을 Provider한테 전달해준다.

이 흐름 맞는지 점검해줘

ㄴ꼬리질문10 앱 메모리·Riverpod 상태가 앱을 다시 시작하면 실행중 상태는 사라지고 필요한 값은 다시 읽거나 계산한다는게 무슨 말이야?

ㄴ꼬리질문11 ScanResult가 기기의 현재 상태에서 다시 얻을수 있다는 말이 무슨 말이야?

ㄴ꼬리질문12 ScanResult에는 조회 시각, 설치 앱 목록, 사용 기록 권한 여부, 조회 가능한 사용 기록이 담기는 것이 ScanResult를 Db에 영구 저장하지 않아도 되는 이유 근거가 될 수 있느거야?

인과관계가 뒤바뀐 느낌이 들어

ㄴ꼬리질문13 Android에서 설치 앱과 조회 가능한 사용 기록 데이터도 어딘가에 저장이 되는거야?

ㄴ꼬리질문14 그리고 좀 더 근본적인 질문인데 굳이 catalog.json을 앱 시작할시 seeder로 SQLite로 저장하는 이유가 뭔지 궁금해

ㄴ꼬리질문15 Repository패턴에서는 데이터의 원본과 메모리 데이터의 구분이 필연적인거야?

ㄴ꼬리질문16 같은 데이터를 여러 형태로 변환하는 것이 데이터에 접근하는 경계를 만드는 Repository 패턴의 핵심인거 아니었어?

ㄴ꼬리질문17 그럼 Repository 패턴을 통해서 경게를만들때 데이터 형태를바꾸지 않고 경계를형성할 수도 있어?

ㄴ꼬리질문18 DB 인스턴스 가 뭐고, ProviderScope이 뭔지 설명해줘

ㄴ꼬리질문19 AppDatabase()는 그러면 SQLite에 접근해서 조회, 검색 등등을 할 수 있도록 해주는 객체인거야?

ㄴ꼬리질문20 왜 굳이 이 객체를 이용해서 DB에 접근하는거야? 그냥 다이랙트로 DB에 접근하면 더 편한거 아니야?

ㄴ꼬리질문21 appDatabaseProvider는 어떤 역할을 하는 거야?

ㄴ꼬리질문22 provider들도 DB에 접근을해야 하는거야? Repository가 Provider한테 데이터를 주면 되는거 아니야?

ㄴ꼬리질문23 DB 객체를 Repository에 연결하는 Provider가 Repository를 만드는 거지?

ㄴ꼬리질문24 Pigeon 계약의 InstalledApp·UsageInfo 값은 스캔을 하고, 아직 Flutter로 넘어오지 않은 데이터인거야?

ㄴ꼬리질문25 DeviceScanRepository에 스캔 결과를 요청하는 로직도 있다고 했는데, 이 부분은 호출하는 쪽에 전달되면 어떻게 작동되는거야?

...

AI 대화 내역 링크:

chatGPT: https://chatgpt.com/s/cx_6ae31f459d548191949b83900cb590f2

오늘 잘한 점: 앱에서 움직이고 흐른는 전체적인 데이터 구조에 대해 먼저 공부를 하려고 했고, 이렇게 생각한 것이 잘한 것 같다. 전체적인 데이터 구조를 알면, 깊게 들어갔을때, 전체적인 방향을 잃지 않고 공부를 할 수 있다고 새각을 했다. 깊게 들어가다 보면 그 내용에 꽃힐 수 있는 문제를 방지하기 위해서인 이유도 있다.

오늘 부족했던 점: 코드를 내가 짠 것이 아니고, 초반 설계 과정도 AI의 도움을 너무 많이 받아서 그런지 생각보다 과정을 이해하는게 쉽지만은 않은 것 같다. 이번에는 단계마다 이해할때 3가지의 관점을 토대로 이해해보려고 노력했다.

오늘 총평: AI를 극한으로 잘 쓰는 경지가 어떤 경지일까 생각을 해보았는데, 내가 생각하기에 결론은 하나인 것 같다. 그냥 "실력"이 좋으면 장땡인 것 같다. 이는 기본적인 피지컬의 영역이라고 생각한다. 이 영역은 효율적으로 할 수는 있어도 단기간에 빠르게 하는건 쉽지 않아 보인다.

그동안 에이전트를 사용하는 뽕맛? 에 너무 과하게 노출이 된 것 같다.

초심을 좀 다잡을 필요가 있어보인다.

1
0

여기에 파일을 드롭하세요