MyStock의 첫 리팩토링을 마무리하며 버전은 0.1.0으로 올렸다. 앞으로 새기능을 위한 사전 밑작업이기 때문에 티도 안나고 시간과 토큰만을 잡아먹는 작업이었다. 미래를 위한 투자라고 생각하고 진했지만, 정말 가장 무료하고 재미없는 작업이었다.
MyStock은 대시보드를 시작해 시황분석, 투자현황, 투자분석으로 기능이 계속 늘어났고, 기능이 늘어날수록 MainWindow에는 Worker와 QThread, cache, 요청 상태, 갱신 처리 같은 책임도 함께 쌓였다. 당장은 동작했지만 이 상태에서 기능을 계속 추가하면 변경 범위와 영향 관계를 매번 다시 추적해야 했다.
특히 나는 ChatGPT와 구조와 요구사항을 검토하고 실제 코드 분석과 구현은 Codex를 통해 진행한다. 구조가 불명확하면 기능 하나를 추가할 때마다 Codex는 넓은 코드를 다시 읽고 상태의 주인과 영향 범위를 다시 찾아야 한다. 결국 이번 리팩토링의 목적은 코드를 보기 좋게 만드는 것이 아니라 책임의 경계를 만들어 앞으로의 분석 범위와 토큰 사용량을 줄이는 것이었다.
계획했다고 전부 만들지는 않았다
Phase 1부터 5까지 Account, Refresh, Analysis, Market, Quote, ETF, Trade와 관련된 책임을 단계적으로 분리했다. 그 과정에서 한 가지 원칙이 생겼다. 계획에 있다고 구현하지 않는다. 현재 코드에 실제 문제가 남아 있을 때만 구현한다. 이 원칙 때문에 Phase 6과 7은 예상과 다르게 끝났다.
PortfolioStore, InvestmentStatusController, 공통 QThread 구조, KIS 공통 Client와 전역 Rate Limiter 같은 후보를 다시 점검했지만 앞선 작업으로 필요한 책임이 이미 상당 부분 정리돼 있었다. 새 구조를 더 만드는 것이 오히려 다시 책임을 묶거나, 현재 발생하지 않는 문제를 미리 해결하는 일이 될 수 있었다. 그래서 두 Phase 모두 추가 구현 없이 점검으로 종료했다. 리팩토링을 하면서 처음 계획한 구조를 끝까지 만드는 것보다 만들 필요가 없다는 것을 확인하고 멈추는 것도 중요한 작업이라는 판단이 생겼다.
끝내기 전에 exit 139는 확인하고 싶었다
구조 정리는 끝났지만 테스트 과정에서 보이던 exit 139와 일부 Qt 테스트의 exit 134가 찝찝하게 남았다. 이번에 QThread 관련 구조를 많이 건드렸기 때문에 그냥 PySide6 문제라고 넘기지 않고, 리팩토링을 끝내기 전에 두 문제를 분리해서 확인하기로 했다.
조사 결과 exit 134는 테스트 fixture에서 QCoreApplication과 QWidget 환경이 잘못 섞인 문제였다. 이 부분은 QApplication을 사용하도록 수정했고 반복 테스트에서도 정상 종료했다. 반면 exit 139는 active QThread가 없어도 재현됐다. 반복해서 MainWindow를 생성하고 제거하는 비정상적인 GC 조건에서 PySide6/Shiboken의 native wrapper 정리 과정에서 발생했고, 정상적인 단일-window 실행과 Controller의 QThread lifecycle에서는 같은 문제가 확인되지 않아 139를 피하기 위한 production 우회 코드는 넣지 않았다. 문제를 발견했다고 반드시 코드를 고쳐야 하는 것은 아니었다. 현재 제품 코드의 책임인지 확인한 뒤 아니라면 건드리지 않는 것도 하나의 결정이었다.
이번주 일요일 저녁부터 시작한 리팩토링 작업은 금요일에 마무리가 되었다. 퇴근 후 하루에 2-3시간 남짓한 시간으로 작업한 내용을 보면 상당량은 진행한 것 같은데, 나에게 있어서 "티도 안나는 일은 괜히 시켰나..."라는 생각과 MyStock 작업이 지체되는 답답함이 스며들 즈음, 문득 회사에서 내가 리팩토링할 때 작업이 늦어진다고 타 부서나 연구소장에게 갈굼당하던 상황이 떠올랐다.
아... 이런 느낌이었겠구나...!!!
그래서 Codex가 열심히 작업하면서 올리는 진행 상황판을 열심히 읽었다. 난 그들과 다르다는 것을 보여주어야겠다는 신념으로 무료함을 달래기 위해 Codex가 작업 진행 상황을 아무 소리하지 않고 지켜만 보고 있었을 뿐이다... ㅋㅋㅋ
확실히 리팩토링은 재미없다. 작업량은 많은데 결과는 눈에 잘 보이지 않는다. 그렇다고 없어서도 안 될 작업이다.
0.1.0으로 첫 리팩토링은 끝났다. 그런데 대시보드, 투자현황, 투자분석을 다시 보니 다음 질문이 생겼다. 계좌 정보, 보유 종목, 현재가, 거래 내역처럼 여러 화면에서 공유할 수 있는 데이터가 많다.
UI와 Data 영역을 분리할 것인가, 말 것인가.
이번에도 처음부터 분리한다고 결정하지 않을 생각이다. 각 View가 어떤 데이터를 쓰고 어디서 가져오는지, 중복 조회는 없는지, 갱신 주기와 API 제한은 어떤지 먼저 확인한 뒤 실제 이득이 있을 때 구조를 결정하려고 한다. 첫 리팩토링에서 얻은 원칙을 그대로 가져가면 된다.
구조를 만들 수 있다는 이유로 만들지 않는다. 필요한 이유가 확인되면 그때 만든다.
첫 리팩토링은 끝났다. 그리고 또 다른 설계가 시작된다.
