시리즈: AI 협업 개발기: 사주명리 프로젝트
키워드: 도메인 모델링, TypeScript, 만세력, 절기, 진태양시, 데이터 설계
설계 문서를 코드로 옮기는 시간
docs/ 폴더에 네 개의 설계 문서가 완성됐다. 이제 진짜 코드다. 가장 먼저 손을 댄 곳은 02-DOMAIN-MODEL.md에 정의된 기초 데이터 구조를 TypeScript로 구현하는 것이었다.
설계 문서가 있으니 이 과정은 놀라울 정도로 매끄러웠다. Claude Code에서 @docs/02-DOMAIN-MODEL.md를 로드하고 "이 문서의 천간 타입과 데이터를 구현해줘"라고 하면, 문서에 정의된 인터페이스를 그대로 코드로 변환해준다. 설계 문서 없이 "천간 데이터를 만들어줘"라고 했을 때와는 출력의 정확도와 일관성이 확연히 달랐다.
22개 글자 안에 담긴 시스템
천간(天干)은 甲, 乙, 丙, 丁, 戊, 己, 庚, 辛, 壬, 癸의 10개 글자다. 단순히 문자열 배열로 만들면 안 되는 이유가 있다. 각 천간에는 음양과 오행이 매핑되어 있고, 이 속성들이 이후 모든 분석의 기반이 된다. 甲은 양목(陽木), 乙은 음목(陰木), 丙은 양화(陽火)... 이런 식이다.
TypeScript 인터페이스로 정의하면 한자, 한글, 음양, 오행, 순서를 포함하는 구조체가 된다. 여기서 핵심적인 설계 결정이 as const를 사용한 불변성 보장이었다. 사주학의 기초 데이터는 수천 년 전에 정해진 것이 지금도 그대로다. 이 특성을 타입 시스템이 반영하게 만든 것이다.
지지(地支)는 12개 글자인데 천간보다 훨씬 복잡하다. 한자, 한글, 음양, 오행 외에 띠(쥐, 소, 호랑이...), 대응하는 월, 시진(時辰)의 시작/종료 시간, 계절, 그리고 지장간(地藏干)이 포함된다.
지장간은 사주학에서 가장 독특한 개념이다. 각 지지 "안에" 숨어 있는 천간이 있다는 것이다. 寅(인, 호랑이) 안에는 戊, 丙, 甲이 숨어 있다. 이것은 명식표에 보이지 않는 "숨은 관계"를 파악하는 근거가 된다.
Claude는 12개 지지 각각의 지장간을 정확하게 제시했다. 하지만 여기서 첫 번째 학파 차이를 만났다. 子(자) 안의 지장간을 壬과 癸로 보는 쪽과 癸만으로 보는 쪽이 있었다. 설계 문서에서 "가장 보편적인 기준을 기본값으로, 학파별 차이는 명시적으로 기록"이라고 정해둔 원칙이 여기서 바로 작동했다.
관계의 그물망: 오행, 십신, 합충형파해
기초 글자를 정의한 후에는 글자들 사이의 관계를 코드로 옮겨야 했다.
오행(五行, 木火土金水)의 상생과 상극을 어떻게 표현할 것인가. 두 가지 방법이 있다. 매핑 테이블("木 → 火 = 생")과 인덱스 연산(상생은 (i+1)%5, 상극은 (i+2)%5). 둘 다 구현했다. 인덱스 연산은 계산용, 매핑 테이블은 가독성과 검증용이다. 내가 AI에게 "다른 개발자가 (i+2)%5를 보고 상극이라는 걸 바로 알겠느냐"고 물었고, 결과적으로 둘 다 유지하기로 했다.
십신(十神) 분석은 사주 해석의 핵심 엔진이다. 일간(日干, 일주의 천간 = "나 자신")을 기준으로, 다른 7개의 천간/지지와의 관계를 10가지로 분류한다. 같은 오행이면 비견/겁재, 내가 생하는 오행이면 식신/상관, 내가 극하는 오행이면 편재/정재, 나를 극하는 오행이면 편관/정관, 나를 생하는 오행이면 편인/정인. 음양이 같으면 "편", 다르면 "정". 이 규칙은 깔끔하게 함수로 구현된다.
합충형파해(合沖刑破害)는 규칙 테이블의 집합이다. 천간합 5쌍, 삼합 4조, 방합 4조, 육합 6쌍, 육충 6쌍, 형 3유형, 파 6쌍, 해 6쌍. AI가 이 모든 테이블을 한 번에 정확하게 제공했고, 나는 인터넷의 만세력 사이트와 대조하여 검증했다. 기본적인 것은 모두 정확했지만, 형(刑)의 분류에서 미묘한 차이를 발견했다. 또 다시 학파 차이.
12운성(十二運星)에서는 가장 큰 논쟁을 만났다. 양간의 순행은 확정적인데, 음간(乙, 丁, 己, 辛, 癸)을 역행으로 보는 학파와 순행으로 보는 학파가 있다. AI는 "현대 명리학에서는 음간도 순행이 다수"라는 의견을 제시했지만, 이건 "다수"의 문제가 아니라 "어느 쪽을 채택하느냐"의 문제다. 순행을 기본값으로, 역행을 옵션으로 남겨두었다.
이 에피소드들이 보여주는 것은 하나다. AI가 아무리 똑똑해도 "학술적 입장 차이에서의 최종 선택"은 사람의 몫이라는 점이다.
만세력: 달력이라는 예상 밖의 벽
도메인 데이터를 코드로 옮기는 것은 설계 문서 덕분에 비교적 수월했다. 진짜 전쟁은 만세력 모듈에서 시작됐다.
핵심 문제는 사주가 양력도 음력도 아닌 절기력(節氣曆)을 기준으로 한다는 점이다. 연주(年柱)는 1월 1일이 아니라 입춘(立春)에 바뀐다. 입춘은 양력 2월 3~5일 사이인데 매년 다르고, 시각까지 따져야 한다. 2024년 입춘이 2월 4일 16시 27분이라면, 16시 26분 출생과 16시 28분 출생의 연주가 다르다.
월주(月柱)는 더 까다롭다. 음력 1월이 아니라, 입춘부터 경칩 전날까지가 사주의 "1월"이다. 24절기 중 "절(節)" 12개가 사주의 월 경계를 결정한다. 양력, 음력, 사주월이 전부 다른 체계인 것이다.
JavaScript/TypeScript 생태계의 만세력 라이브러리를 조사했다. 하나의 라이브러리로 모든 것을 해결할 수 없었다. 조합 전략을 세웠다. korean-lunar-calendar로 양력-음력 변환, KASI 데이터로 절기 정밀 시각, 진태양시 보정은 자체 구현, 사주 계산과 분석 엔진은 완전 자체 구현. 이 전략을 한 시간 안에 세울 수 있었던 것은 AI가 각 라이브러리의 장단점을 비교 분석해서 표로 정리해줬기 때문이다.
절기 데이터는 한국천문연구원(KASI)에서 확보했다. 빌드 타임에 1920~2050년 데이터를 일괄 수집해서 JSON으로 저장하는 방식이다. 오프라인 동작, API 장애 무관, 즉각적 응답이라는 세 가지 이점 때문에 이 방식을 선택했다.
시주를 바꾸는 보정들
시주(時柱) 계산에서 진태양시(True Solar Time) 보정이라는 벽을 만났다. 한국 표준시는 동경 135도 기준인데 서울의 경도는 약 127도다. 이 8도 차이가 약 32분이고, 여기에 날짜별 균시차(±16분)까지 합치면 최대 48분의 차이가 생긴다. 시주는 2시간 단위이므로, 이 보정이 시주 자체를 바꿀 수 있다.
서머타임도 처리해야 했다. 한국은 1948~1951년, 1955~1960년, 1987~1988년에 서머타임을 시행했다. 출생신고 시간에서 1시간을 빼야 실제 태양시가 된다.
야자시(23:00~00:00) 처리도 있다. 같은 자시(子時, 23:00~01:00) 안에서 일주가 바뀌는 모순을 피하기 위해 야자시설(23:00 이후는 익일)을 기본으로 채택하되, 설정으로 전환 가능하게 했다.
이 모든 보정을 구현하면서 느낀 것은, 사주 계산의 핵심 난이도가 "알고리즘의 복잡도"가 아니라 "규칙의 모호함"에 있다는 것이다. 정답이 하나가 아닌 영역에서 개발자의 역할은, 합리적 기본값을 설정하고 다른 해석을 허용하는 유연한 구조를 만드는 것이다.
이 과정에서 배운 것
첫째, "계산 가능한 것"과 "테이블로 관리해야 하는 것"을 구분하는 것이 도메인 모델링의 핵심이다. 십신 판정은 함수, 지장간은 테이블, 삼합/육충은 테이블. 이 구분이 코드의 구조를 결정한다.
둘째, 외부 데이터의 신뢰 등급을 의식적으로 구분해야 한다. KASI 공식 데이터와 개인 블로그 데이터의 신뢰도는 다르다. 정밀도가 곧 품질인 도메인에서는 데이터 소스의 권위가 앱의 가치를 좌우한다.
셋째, 라이브러리 조합 전략은 AI와의 대화로 빠르게 세울 수 있다. 각 라이브러리를 설치하고 테스트하는 대신, AI와 장단점을 비교 분석하는 것이 훨씬 효율적이다.
넷째, 정답이 여러 개인 도메인에서는 기본값 설정과 유연한 구조가 핵심이다. 하나만 맞다고 하드코딩하면 사용자의 절반이 "이 앱은 틀렸다"고 느낀다.
다음 편 예고
사주 네 기둥이 계산되고 룰 기반 분석이 끝났다. 이제 이 구조화된 데이터를 AI에 넘겨서 "사람이 읽을 수 있는 해석"으로 바꿔야 한다. 룰 엔진과 AI 해석을 어떻게 결합했는지, 프롬프트에 궁통보감 데이터를 넣으면 어떤 마법이 일어나는지, 4편에서 이어진다.
이 글은 "AI 협업 개발기: 사주명리 프로젝트" 시리즈의 3편입니다.
'개발' 카테고리의 다른 글
| 5편: 완성 그리고 회고 — 복잡한 도메인에서 AI 협업이 빛나는 순간 (0) | 2026.02.17 |
|---|---|
| 4편: 룰 엔진과 AI 해석의 하이브리드 — 두 마리 토끼를 잡다 (0) | 2026.02.17 |
| 2편: 설계 문서가 먼저다 — docs/ 폴더로 시작하는 개발 (0) | 2026.02.17 |
| 1편: 사주를 코드로 만들 수 있을까 — 도메인 탐색과 아키텍처 결정 (0) | 2026.02.17 |
| ☯️ AI와 함께 사주 웹앱을 만들다 — 시리즈 개요 (0) | 2026.02.17 |
