
문제: 비슷한 기능을 세 번 만들 때마다 처음부터 다시 짠다

같은 성격의 기능을 여러 번 추가해 본 사람은 안다. 두 번째, 세 번째를 만들 때도 매번 저장 로직·리포트·초기화 코드를 다시 짜게 된다. 겉보기엔 '조금 다른' 기능처럼 보이지만, 실제로 다른 부분은 극히 일부이고 나머지는 매번 복사·수정하는 반복 작업이다.
실제 개발 기록에서 이 문제를 정면으로 마주친 사례가 있다. 스캘핑 가상매매(섀도우) 기능을 세 시장 — KR(분봉 돌파), US(시세샘플 돌파), Coin(눌림목 반등) — 에 동시에 추가해야 했다. 각각 2,000만원 가상 장부와 장마감 리뷰가 필요했다.
결과적으로 설계(SCALPING_SHADOW_DESIGN.md)부터 3레포 병렬 구현, 리뷰·테스트(총 151건 신규, KR 전체 956 pass), push까지 하루에 끝났다. 각 레포에서 실제로 새로 건드린 파일은 약 10개뿐이었다. 이 속도의 주요 배경은 기존 4장부 인프라를 슬러그만 바꿔 전면 재사용할 수 있었기 때문이다. 공통 인프라가 이미 전략과 분리돼 있었던 것이다.
왜 위험한가: 인프라가 전략에 섞이면 복제가 강제된다

장부(book_report), 자산 그래프(equity_graph), 초기화(reset), 리뷰 전달(review_delivery) — 이 네 가지는 어떤 전략을 쓰든 필요하다. 문제는 이 공통 부분을 전략 로직 안에 섞어 짜는 순간, 새 전략을 만들 때마다 인프라까지 통째로 복제해야 한다는 점이다.
- 복제된 인프라는 각자 조금씩 달라지고, 버그 수정이 한 곳에만 반영된다.
- 테스트도 전략마다 중복 작성해야 해서 커버리지 관리가 어려워진다.
- '조건만 바꾼 새 전략'인데도 항상 대규모 작업이 된다.
반대로 인프라를 계약(contract)으로 고정해두면, 전략은 그 계약을 만족하는 플러그인이 된다. 실제 기록에서는 슬러그(shadow_scalp) 하나만 바꿔 기존 4장부 인프라를 전면 재사용했고, 신규 코드는 전략(rules)·비용(engine)·데이터 어댑터에 집중됐다.
핵심 개념: 무엇을 계약으로 고정하고, 무엇을 플러그인으로 남길까
재사용의 핵심은 '변하지 않는 것'과 '변하는 것'을 선으로 나누는 것이다. 이번 사례의 실제 경계선은 아래와 같다.
| 계약(고정 인프라) | book_report · equity_graph · reset · review_delivery | 슬러그만 바꿔 재사용 |
| 플러그인(신규 코드 집중 영역) | rules(전략) · engine(비용) · 데이터 어댑터 | 새 코드가 여기에 집중됨 |
이 경계 덕분에 시장별 데이터 격차도 '어댑터'라는 플러그인 슬롯 안에서만 해결됐다. 실제로 세 시장은 데이터를 각자 다른 방식으로 가져왔다.
- Coin: 분봉 API를 직접 호출.
- KR: 당일 분봉 TR을 쓰되
since를 좁혀max_pages=2로 제한. - US: 시세 폴링을 링버퍼에 쌓아 돌파를 판정.
세 방식이 이렇게 다른데도 장부·리뷰·리셋 코드는 손대지 않았다. 데이터 획득 방식이 어댑터 뒤에 숨어 있고, 그 어댑터가 계약이 요구하는 형태로만 결과를 넘겨줬기 때문이다.
적용 절차: 인프라를 계약으로 분리하는 6단계
- 공통으로 반복되는 것을 먼저 목록화한다. 이번 경우 장부·리뷰·리셋·자산 그래프가 그것이었다. '전략이 무엇이든 항상 필요한가?'를 기준으로 골라낸다.
- 인스턴스 식별자를 파라미터로 뺀다. 여기서는 슬러그(
shadow_scalp). 인프라가 특정 전략 이름을 하드코딩하지 않고, 슬러그만 받으면 어떤 전략이든 붙일 수 있게 한다. - 구현 전에 설계 문서를 먼저 쓴다. 이번엔 설계 문서(
SCALPING_SHADOW_DESIGN.md)를 먼저 작성한 뒤 3레포 병렬 구현에 들어갔다. (일반 원칙으로, 전략이 인프라에 넘겨야 할 데이터 형태를 글로 고정해두면 여러 사람·여러 레포가 같은 기준으로 병렬 작업하기 쉬워진다.) - 변하는 부분을 슬롯으로 정의한다. rules(전략 조건), engine(비용 모델), 데이터 어댑터 세 가지가 슬롯이었다.
- 테스트로 검증한 뒤 push한다. 이번엔 총 151건의 테스트를 신규로 추가했고, KR 레포는 전체 956건이 통과하는지 확인한 뒤 push했다. (권장 절차로, 변하는 슬롯마다 독립 테스트를 붙이면 한 전략의 실패가 다른 전략을 오염시키지 않는다.)
- 계약이 검증되면 플러그인만 갈아끼운다. (권장 절차로, 계약이 안정된 상태라면 새 전략 추가는 rules·engine·어댑터 슬롯만 교체하는 작업으로 좁혀진다.)
체크리스트: 지금 만드는 코드가 계약인가 복제인가
- 이 기능은 전략이 바뀌어도 항상 필요한가? (그렇다면 계약 후보다)
- 전략 이름·인스턴스 이름이 인프라 코드에 하드코딩돼 있지 않은가?
- 전략이 인프라에 넘기는 데이터 형태가 문서로 고정돼 있는가?
- 변하는 부분(조건·비용·데이터 획득)이 명확한 슬롯으로 분리돼 있는가?
- 새 전략을 붙일 때 인프라 파일을 수정하지 않고 끝낼 수 있는가?
- 슬롯마다 독립 테스트가 있어 한 전략의 실패가 다른 전략을 오염시키지 않는가?
이 항목들에 '아니오'가 많다면 지금 만드는 것은 계약이 아니라 다음 복제의 원본일 가능성이 높다.
잘못 나눴을 때 어떻게 되는가
경계선을 잘못 그으면 두 가지 방향으로 실패한다. 첫째, 계약이 너무 좁으면 — 예를 들어 장부 저장 안에 특정 시장의 데이터 형식 가정이 들어가면 — US의 링버퍼 방식이나 Coin의 분봉 API 방식을 넣을 때 인프라를 뜯어고쳐야 한다. 그 순간 '한 곳만 고치면 되는' 장점이 사라지고 세 배의 수정 지점이 생긴다.
둘째, 계약이 너무 넓으면 — 전략별로 달라질 수 있는 비용 모델까지 인프라가 떠안으면 — 인프라가 모든 예외를 알아야 해서 조건문이 계속 늘어난다. 일반 원칙으로, 비용(engine)처럼 변동 가능성이 있는 부분은 계약이 아니라 슬롯으로 남겨두는 편이 이 함정을 피하는 데 유리하다. 이번 사례에서도 비용은 신규 코드가 집중된 플러그인 쪽에 있었다.
실무에서는 처음부터 완벽한 경계를 긋기 어렵다. 그래서 계약이 요구하는 데이터 형태를 설계 단계에서 미리 문서로 고정해두는 편이 안전하다. 이번에도 설계 문서를 먼저 쓴 뒤 3레포를 병렬 구현했고, 리뷰·테스트(151건 신규, KR 956 pass)를 마친 상태에서 push했다.
한계와 주의사항
이 글에서 말하는 '하루에 3종 완료'는 인프라가 이미 계약으로 존재했기 때문에 가능했던 결과다. 계약을 처음 설계하는 비용은 여기에 포함돼 있지 않다. 이전 설계(4장부 도구)에 들인 시간이 이번 속도의 전제였다는 점을 분리해서 봐야 한다.
또한 이 사례는 가상매매(섀도우) 구현이다. 가상 장부로 기록·리뷰한 것이며, 특정 전략의 수익성·성과를 검증하거나 보장하는 내용이 아니다. 아키텍처의 재사용성과 전략의 실전 성능은 완전히 별개의 문제다.
마지막으로, 파일 수(레포당 ~10파일)나 테스트 수(151건 신규)는 이 특정 프로젝트의 실측값이다. 프로젝트 성격에 따라 계약과 플러그인의 경계는 달라지므로, 숫자보다 '무엇을 고정하고 무엇을 슬롯으로 남겼는가'라는 판단 기준을 가져가는 편이 유용하다.
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
'실전 원칙' 카테고리의 다른 글
| 달러 자산을 원화로 볼 때 수익률이 헷갈리는 이유와 표시를 분리하는 법 (0) | 2026.08.14 |
|---|---|
| 자동화가 사람 개입 후 멈추는 문제: 중복 없이 다시 태우는 재개 경로 설계법 (0) | 2026.08.13 |
| AI가 만든 '성공' 판정, 부호만 맞으면 통과시키는 함정 — 최소격차·표본 가드로 막는 법 (0) | 2026.08.10 |
| 스캘핑 전략을 시작하기 전에: 비용·데이터·레이턴시부터 계산하는 법 (0) | 2026.08.09 |
| 자동화에 판단을 맡길 때 '긴급도'와 '실행 권한'을 반드시 분리해야 하는 이유 (0) | 2026.08.09 |