MyStock은 처음에는 KIS Open API를 이용해 계좌 잔고와 보유 종목을 확인하는 개인 투자 관리 도구로 시작했다.
- 계좌 잔고 조회
- 보유 종목 확인
- 평가 금액 확인
그리고 필요에 따라 계좌 및 지수 정보를 갱신 주기를 설정할 수 있도록 하였는데, 이것은 최초 설계 단계에서 구상한 기능이 아니라 검증 단계에서 자동 갱신 기능이 있으면 좋겠다는 내 의견을 반영하여 Codex가 추가한 기능이다. 기능 구현 당시에는 자동 갱신이 잘 되는지 확인이 중요 관점이었고, 그 외 다른 부분은 고려대상이 아니었다.
그런데 어제 클라우드 싱크 기능 제거 후, MyStock 동작상에 문제가 없는지 확인 과중 중에 한가지 이상한 부분을 발견하였다. 대시보드나 시황정보에만 자동 갱신 Interval을 설정하게 되어있고, 대시보드와 투자현황의 내 계좌정보는 동일하고 단지 세부 정보 출력에서 차이가 있을 뿐인데 투자현황에는 자동 갱신 기능이 없을까? 하는 의문이 들었다.
그래서 ChatGPT와 왜 자동 갱신은 대시보드에서 설정하고 전체 탭에 적용하면 되는 것이 아니냐고 확인한 결과, 당연히 나와 동일한 의견이라 Codex에게 코드를 확인한 결과 엄청난 문제점을 발견하게 되었다.
MainWindow가 모든 것을 알고 있는 구조
Codex는 내가 예상한 것과 다른 이상한 형태에 현재 구조를 아래와 같이 보여주고 있었다. 초기 개발 단계에서는 주식이나 금융 지식이 전무한 상태에서 내가 원하는 기능이 가능한지에 초점을 두고 ChatGPT와 논의하면서 Codex에게 가능성 여부를 확인하면서 개발하는 구조였다. 즉, 내 요구사항을 정확히 반영한 소프트웨어 구조가 아닌 필요에 따라 Codex는 현재 구조에서 최선의 선택으로 구현한 것 같다.
그래서 Codex가 내 요구에 따라 구현한 MyStock의 구조는 아래와 같았으며, ChatGPT는 작은 PySide6 프로그램을 구현할 때 자연스러운 방식이라고 말했다. 즉, 화면에서 요청을 받고 Worker를 실행하고 결과를 표시하는 구조였다.
기존 MyStock 구조
┌──────────────────────────┐
│ MainWindow │
│ │
│ View 관리 │
│ 데이터 상태 관리 │
│ Cache 관리 │
│ Pending 관리 │
│ Worker/QThread 관리 │
│ KIS 호출 흐름 │
│ 종료 처리 │
│ │
└──────────┬───────────────┘
│
▼
KIS API / Service
하지만 본문 서두에 작성한 것과 같은 구조의 자동 갱신을 추가하려는 순간 문제가 보였다. MainWindow가 화면 관리뿐 아니라 각 기능의 상태와 실행 흐름까지 관리하는 구조가 되고 있었다.
문제는 여기서부터이다. MyStock은 금융 및 주식 지식이 가지고 있지 않는 내가 필요에 의해 개발되고 있으며, 한정된 기능을 목표로 개발되는 것이 아니라 필요에 따라 지속 개발되어질 프로젝트로 생각하고 진행하는 프로젝트인데, 지금 이 구조를 제대로 설계하지 않으면 앞으로 신규 기능 추가함에 있어 불필요한 추론과 디버깅 과정이 많이 발생한 할 것으로 판단되었다.
AI가 제안한 구조와 실제 프로젝트의 차이
나는 ChatGPT와 함께 View, Controller, Service, Store로 나누는 구조를 검토했다. 그래서 ChatGPT와 검토한 결과를 Codex에게 현 구조에서 신규 구조로 전환 했을 때의 가능성 여부 및 전체 코드 리뷰를 시켰는데, 좀 황당한 경험을 하게 되었다.
Codex가 전체 코드를 리뷰한 결과, 우리가 제안한 방식은 전체 설계를 변경해야 되는 것을 우려하여 타협한 구조를 다시 역제안을 하였다.
나 & ChatGPT 제안
전체 Feature 이동
+
QThread 공통화
+
Store 전면 도입
↓
Codex 의견은 좋은 구조지만 현재 단계에서는 위험
최종 선택
기존 기능 유지
+
신규 기능부터 Feature 적용
+
필요할 때 점진 이동
그리고 MyStock 검증 과정에서 불특정하게 발생하는 Segment fault로 인해 PySide6 QThread 종료 과정은 여러 시행착오 끝에 안정화된 영역이다. 따라서 Worker lifecycle을 다시 만드는 대신, 기존 동작은 유지하고 책임 위치만 이동하는 방향으로 판단했다.
첫 번째 분리 대상은 AccountFeature
MainWindow의 슬림화를 위한 첫 번째 분리 대상으로 AccountFeature를 선택했다. 계좌 데이터는 Dashboard, 투자현황, 투자분석 등 여러 화면에서 공유되는 MyStock의 핵심 데이터이기 때문이다. 지금은 MainWindow가 계좌 조회부터 Worker 실행, 조회 결과 보관, 각 화면으로 데이터 전달까지 모두 담당하고 있다. 이 구조에서는 자동 갱신이나 리밸런싱 같은 계좌 기반 기능이 추가될 때마다 MainWindow에 관련 상태와 처리 흐름이 계속 늘어나게 된다.
따라서 계좌 조회와 상태 관리를 AccountFeature로 분리해 AccountController가 조회 흐름을 관리하고, AccountStore가 최신 계좌 상태를 보관하며, 각 화면은 동일한 AccountSnapshot을 사용하도록 만드는 것이 첫 번째 목표다.
AccountFeature
Controller
│
┌────────┼────────┐
│ │ │
Service Store Worker
│ │
KIS API QThread
AccountSnapshot, AccountStore, AccountController 구조를 먼저 만들되, 이미 안정화된 계좌 조회 Worker와 QThread의 동작 방식은 최대한 유지한다. Codex 제안대로 구조를 새로 만드는 것이 아니라, MainWindow가 가지고 있던 계좌 관련 책임을 AccountFeature로 옮기는 것이 이번 작업의 핵심이다.
신규 기능은 새로운 구조에 추가한다
목표 방향
MainWindow
│
┌────────────┴────────────┐
│ │
AccountFeature WatchlistFeature
│ │
Controller Controller
Store Service
Service
│
KIS API
기존 기능
↓
필요할 때 Feature 단위로 점진 이동
중요한 것은 기존 코드를 모두 다시 작성하는 것이 아니다. 앞으로 추가되는 기능이 다시 MainWindow를 비대하게 만들지 않는 구조를 만드는 것이다.
AI 협업에서 중요한 것은 제안된 구조를 그대로 적용하는 것이 아니라, 현재 시스템 상태와 변경 위험을 함께 판단하는 것이다. MyStock은 이제 기능을 계속 추가하는 단계에서 벗어나, 앞으로 추가될 기능이 기존 구조를 다시 흔들지 않도록 확장 방향을 정하는 단계로 넘어가고 있다.
