gwimong's blog Software Engineer

artifact-transformer 작업 일지 #11

인터페이스 데이터까지 갈라 마무리하고, round-trip을 CI로 못박고, 과도기 data 폴백을 걷어내다


이 글은 2026-06-09 하루 동안 artifact-transformer의 데이터 산출물을 인터페이스까지 갈라 마무리하고, generate→parse 왕복을 CI 게이트로 묶고, 분리 과정에서 남았던 과도기 폴백·로고 좌표를 정리한 작업 기록이다.

배경

artifact-transformer는 Jira 이슈와 PlantUML 다이어그램을 입력으로 받아 요구사항·유스케이스·기능·시퀀스 명세서와 단위·통합·운영·인수 시험서 등을 docx/xlsx로 자동 생성·역파싱하는 도구다 (#4 참조).

#10에서 데이터 산출물을 **논리(AN12)·물리(DE31)**로 갈라 OOXML 양식까지 정합시켰다. 그날 남긴 “다음에 할 것”이 네 개였다 — 인터페이스 데이터 정합, round-trip의 CI 편입, 병합한 로고의 좌표 보정, 과도기 단일 data 폴백 정리. 오늘은 그 네 칸을 닫는 날이다.

마침 소비자 쪽에서도 같은 분리가 실제로 굴렀다. SDSP의 논리 데이터 정의서를 이 스키마로 채우며 데이터가 내부인지 외부참조인지를 가른 작업이 같은 날 별도로 진행됐는데, 오늘 도구 쪽 일은 그 채우기가 딛고 설 레이어 분리를 인터페이스까지 완성해 두는 쪽이었다.

산출물이 갈려도 코드는 하나다 — #10에서 세운 이 원칙을 인터페이스에까지 마저 적용하고, 그 위에 회귀 방어막(CI)을 친다.

문제

손대기 전 남아 있던 칸들.

  1. 인터페이스 데이터 산출물이 정합 전이었다 — interface-data.example.json 샘플은 있었지만, generator/parser가 논리·물리처럼 단일 모듈·template+sample 모델로 인터페이스를 다루지 못했다.
  2. 데이터 round-trip이 손검증에 머물렀다 — generate→parse 왕복을 사람이 돌려 보고 있었다. 샘플이 바뀌면 회귀를 잡아 줄 자동 장치가 없었다.
  3. 병합한 로고 좌표가 어긋날 여지 — #10에서 데이터 명세서는 요구사항 명세서(MAIN) 표지 패키지를 빌려 썼고, floating 로고가 MAIN 좌표 기준이라 데이터 표지에서 미세하게 밀릴 수 있었다.
  4. 과도기 단일 data 표기가 남았다 — 논리/물리 분리 뒤에도 옛 단일 data를 받아 주는 폴백이 코드·매핑 곳곳에 남아, 두 표기가 공존했다.

결정 1 — 인터페이스 데이터를 같은 단일 모듈로 마저 묶다

#10의 핵심 모델은 한 generator/parser 모듈이 template+sample 조합으로 여러 산출물을 다룬다는 것이었다. 논리·물리에 이어 인터페이스를 세 번째 케이스로 같은 generate_dd/ds·parse_dd/ds에 물렸다.

  • 인터페이스는 연동 규격 중심 레이아웃이다 — 논리가 attributes[](의미), 물리가 fields[](구조)를 담았다면, 인터페이스는 연동 방식·포맷·방향 쪽 속성을 담는다. (인터페이스 레이아웃의 정확한 필드 셋은 interface-data.schema.json 기준으로 확정 — 아래 보고의 확인 항목)
  • CLI 코드 selector에 인터페이스 정의서/명세서 코드를 등록했다. [#10 결정 1]에서 만든 _BY_CODE 역인덱스에 코드를 더해, 실무 코드로 바로 고를 수 있게 했다. (인터페이스 산출물의 실제 문서 코드는 확인 필요)
  • 스모크의 STD_GENERATORS는 모듈명을 키로 쓰는 구조라, #10에서 같은 모듈에 논리·물리 두 케이스를 담으려 키·라벨을 구분지었다. 여기에 인터페이스가 더해지며 한 모듈이 세 케이스를 갖게 돼, 키·라벨 구분을 셋으로 넓혔다.

갈리는 건 입력(template+sample)이지 처리 로직이 아니다. 논리·물리·인터페이스가 한 코드 위에 모두 선다.

결정 2 — round-trip을 CI 게이트로 올리다

#10까지 데이터 산출물의 generate→parse 왕복은 손으로 돌려 보던 검증이었다. 이걸 스모크 테스트에 정식으로 묶어, 샘플이 바뀌면 자동으로 걸리게 했다.

  • 데이터 케이스를 스모크에 추가했다 — 정의서/명세서(dd/ds) × 논리/물리/인터페이스, 총 6 케이스. 각 케이스가 generate→parse를 돌아 분류·카드 필드가 제자리에 복원되는지를 자동으로 확인한다.
  • 이 스모크 실행을 CI 단계로 승격해, 샘플·스키마 수정이 회귀를 끌고 들어오면 그 자리에서 빨갛게 막히도록 했다. (CI 실행 환경·정확한 전체 통과 건수는 확인 필요)

손검증을 자동 게이트로 바꾸니, 레이어를 셋으로 늘린 뒤에도 “어디 하나 깨졌나”를 사람이 일일이 돌려 볼 필요가 사라졌다.

결정 3 — 병합한 로고의 floating 좌표 보정

#10에서 데이터 명세서는 요구사항 명세서(MAIN) 패키지(임베드 폰트·로고·머리글/바닥글)를 빌려 내용만 얹는 식으로 병합했다. 그 결과 표지의 floating 로고가 MAIN 표지 좌표 기준으로 앵커돼, 데이터 명세서 표지에서 미세하게 어긋났다.

#10과 같은 방식으로 zipfile로 document.xml만 외과적으로 손댔다(openpyxl/python-docx로 다시 쓰지 않고).

  • 로고 drawing의 floating 앵커 오프셋(<wp:positionH>/<wp:positionV>의 <wp:posOffset>)을 데이터 표지 기준으로 보정했다.
  • 좌표만 옮겨선 부족했고, 앵커 기준(relativeFrom) 까지 데이터 표지 레이아웃에 맞춘 뒤에야 자리가 맞았다(아래 함정). 보정 후 Word에서 열어 눈으로 위치를 확인했다.

결정 4 — 과도기 단일 data 폴백 정리

마지막은 청소다. 논리/물리(/인터페이스) 분리가 자리를 잡았으니, 그 전환을 버티던 단일 data 표기 폴백을 걷어냈다.

  • “그 표기를 읽는 모든 곳”을 먼저 grep으로 뽑았다 — STD_GENERATORS 매핑, document_codes 등록, 샘플·문서 코드 참조.
  • 마이그레이션이 끝난 항목부터 폴백을 제거하고, 매핑을 논리/물리/인터페이스의 정식 이름으로 일원화했다.

#9에서 legacy 폴백은 호환을 사지만 오래 두면 두 이름이 영구 공존한다고 적어 뒀는데, 여기서 과도기 표기 하나를 실제로 닫았다.

의도치 않은 함정

아래 함정은 #10의 알려진 메커니즘(모듈-키 스모크, zipfile 로고 병합, rename 후 template-not-found)에서 재구성한 것이다. 실제로 밟은 양상과 다르면 알려 주면 바로잡는다.

  • 세 번째 케이스가 스모크 키를 또 밟았다 — STD_GENERATORS가 모듈명을 키로 쓰는 탓에, 인터페이스를 같은 모듈에 더하자 #10에서 논리/물리로 갈라 둔 키·라벨과 충돌했다. 셋이 한 모듈을 공유하도록 라벨 구분을 넓혀 풀었다.
  • 로고는 오프셋만으로 안 맞았다 — 처음엔 posOffset만 데이터 표지 값으로 바꿨는데도 위치가 어긋났다. 앵커 기준(relativeFrom)이 MAIN 레이아웃을 가리키고 있던 탓이라, 기준까지 맞추고서야 자리가 잡혔다.
  • 폴백 제거 직후 스모크가 빨갰다 — 단일 data 표기를 걷어내자 그 이름을 아직 부르던 매핑 한 곳이 template-not-found로 막혔다. #10의 데이터→논리/물리 rename 때와 같은 결의 회귀라, 정식 이름으로 매핑을 갱신하니 초록으로 돌아왔다.

마무리

오늘은 데이터 산출물 라인을 인터페이스까지 갈라 마무리하고, 그 위에 회귀 방어막을 친 날이다. 관통하는 결은 셋이었다.

  • 갈려도 코드는 하나, 이번엔 셋까지 — 논리·물리·인터페이스가 모두 한 generate_dd/ds·parse_dd/ds 위에 선다. 갈리는 건 template+sample뿐이라는 #10의 원칙이 세 번째 케이스에서도 그대로 버텼다.
  • 손검증을 자동 게이트로 — 데이터 round-trip을 스모크·CI로 올려, 레이어가 늘어도 회귀가 사람 눈을 빠져나가지 못하게 했다.
  • 과도기 표기는 끝나면 닫는다 — 분리를 버티던 단일 data 폴백을 걷어, 두 표기가 영구 공존하지 않게 했다(#9의 폴백 정리 원칙 적용).

다음에 할 것:

  • 물리 데이터 정의서(DE31) 채우기와 round-trip 확인 — 소비자 쪽에서 논리를 요약 속성까지 채웠으니, 물리는 fields[](타입·길이·단위·범위·nullable·key)로 내려가 같은 깊이로 채우고 왕복을 확인한다.
  • 인터페이스 레이아웃 샘플 보강 — interface-data.example.json을 실제 SDSP 연동 규격으로 채워, 인터페이스 케이스의 round-trip 커버리지를 실데이터로 끌어올린다.
  • CI 게이트 범위 확장 — 데이터 6 케이스에 더해, 분석·설계·시험 산출물 전반의 스모크도 같은 게이트 아래로 모은다.

Comments

Content