gwimong's blog Software Engineer

artifact-transformer 작업 일지 #20

제 단위로 — 유스케이스를 사용자 목표로 묶고, 인증을 제 소관으로 돌려보내고, 같은 파일을 두 번 헛디디다


이 글은 2026-06-25 하루 동안 artifact-transformer와 그 산하 도메인 저장소들에서 무엇을 어떤 단위로 묶고 가를지를 바로잡은 작업 기록이다. 유스케이스는 기능이 아니라 사용자 목표 단위로, 시퀀스는 데이터 유형 단위로, 인증은 제 소관으로 돌려보냈다. 그리고 그 사이 두 번 — 진단이 파일을 덮어썼고, 남이 이미 한 일을 다시 했다.

배경

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

#19에서 경계를 긋고 끊긴 관계를 이었다. C4를 boundary로 쪼개 OVERVIEW로 묶고, JWT 인증을 IAMS로·Keycloak을 Keycloak으로 갈라 보내고, ERD의 끊긴 FK를 메웠다. 그날 남긴 빚은 레벨 간 정합 검사 실전 확대와 인증 분리의 잔여 저장소 전개였다.

오늘은 그 분리를 마저 밀고, 한 발 더 안쪽으로 들어갔다. 어제가 “선을 긋는” 날이었다면, 오늘은 “무엇을 한 덩어리로 볼 것인가” — 산출물을 묶고 가르는 단위 자체를 손본 날이다. 늘 그렇듯 도메인을 들여다보니 도구가 아직 못 하는 일이 보였고, 그래서 오늘도 도메인 바깥과 도구 안쪽을 번갈아 손댔다.

문제

손대기 전, 네 가지 어긋남이 보였다.

  1. 유스케이스가 기능 단위로 쪼개져 있었다 — SULAS의 유스케이스가 사용자 목표가 아니라 기능 하나하나에 대응해 28개로 불어 있었고, relatedFn 연결도 군데군데 어긋나 고아 기능이 22개 떠 있었다.
  2. 인증 책임이 아직 FDSP 안에 남아 있었다 — 어제 SDSP·IAM에서 인증을 갈라 보냈는데, FDSP에는 Keycloak·API 토큰 검증이 그대로 박혀 있었다.
  3. 아키텍처 다이어그램의 손질이 산출물로 돌아오지 않았다 — 다이어그램 level 2/3을 손으로 고쳤는데, 그 변경이 participant.json 같은 산출물에 반영될 길이 없었다.
  4. 표현의 단위가 제각각이었다 — 시퀀스는 데이터 유형이 순차 조회처럼 그려졌고, 테스트는 기능 단위로 흩어졌고, logical-data의 이름은 physical-data·ERD와 어긋나 있었다.

결정 1 — 유스케이스는 기능이 아니라 사용자 목표 단위로

오늘의 가장 큰 도메인 작업이었다. SULAS의 유스케이스를 기능 단위(28) → 사용자 목표 단위(11) 로 통합·재채번했다.

  • 운영 시나리오를 먼저 읽고, 업무 흐름도(BPDG) 8종을 신설했다(표시 전용, 렌더 검증 OK). 흐름이 먼저 서야 “이 흐름에서 사용자가 이루려는 목표가 무엇인가”가 보이고, 그게 곧 유스케이스의 단위가 된다.
  • 그 단위에 맞춰 유스케이스를 11개로 묶고, 잘못 걸려 있던 relatedFn을 정정해 고아 기능을 22 → 4 로 줄였다. 연결이 끊겨 떠 있던 기능 대부분은 “기능 단위 유스케이스”가 남긴 부산물이었다.
  • 재지정 여파로 SQDG 26·UCDG 4종을 따라 갱신했다. ucdg·sqdg 라운드트립 [+0 -0 ~0], 추적성 0/0.

유스케이스를 기능 수만큼 만들면 추적은 깔끔해 보이지만, 그건 유스케이스가 아니라 기능 목록의 사본이다. 유스케이스의 단위는 시스템이 제공하는 기능이 아니라 사용자가 이루려는 목표다 — 한 목표를 위해 여러 기능이 엮이는 게 정상이고, 그 엮임이 relatedFn이다.

usecase·sequence는 major를 올려 3.0.0으로 커밋했고(b55e640), 다이어그램은 분리 커밋했다(5714c8f).

결정 2 — 인증·Keycloak을 FDSP에서 걷어내 IAMS로

#19에서 시작한 분리의 FDSP 판이다. 인증은 IAMS의 책임이지 데이터 플랫폼이 떠안을 구조가 아니다.

  • COM-001 토큰 검증 수직 7종을 걷어냈다. participant.json의 keycloak·tokenValidator·middleware 경계와 keycloak 관계 3건, 용어집 2종까지 함께 제거했다.
  • 다만 이벤트 전파(COM-101/102)는 남겼다. 인증을 IAMS로 보낸다고 시스템 간 이벤트까지 사라지는 건 아니다 — 인증·인가의 결과를 받아 흐르는 이벤트는 FDSP의 책임으로 남는다. 인증이 섞여 있던 혼합 시나리오 4종은 토큰 검증을 들어내고 이벤트만 남기도록 reframe했다.
  • 다이어그램은 3개를 삭제하고 8개를 수정했다. 이때 participant.json의 boundaries[]·relationships[]도 C4 편집과 같은 손에서 동기화해야 했다 — 안 그러면 cdg 인덱스가 밀려(index shift) 정합 검사가 가짜 드리프트를 잡는다.
  • 결과적으로 check가 cdg까지 포함해 완전 통과([+0 -0 ~0]). 변경은 27파일 단일 커밋(aca7008, revise minor 1.6.0)으로 묶었다.

이어서 FDSP의 C4도 손봤다. CNTDG partial을 FDSP-CNTDG-SDSP → FDSP-CNTDG-FDSP로 재명명(엉뚱한 시스템 이름이 박혀 있었다)하고, CMPDG의 ETL pipe를 Container_Boundary로 승격한 뒤 parse cdg --reset으로 participant.layers를 ['A','P'](api·pipe)에 동기했다(a31dd77).

무언가를 “내 소관이 아니다”라고 가르는 일은 엔티티 몇 개를 지우는 게 끝이 아니다. 그 엔티티에 매달려 있던 관계·경계·용어·이벤트까지 따라가서, 남길 것(이벤트)과 보낼 것(검증)을 한 줄씩 갈라야 모델이 자기 책임만큼으로 줄어든다.

결정 3 — 다이어그램의 손질을 산출물로 되돌리고, 그 일을 명령으로 박는다

아키텍처 다이어그램의 level 2/3을 일부 손으로 고쳤다. 그걸 확인해서 산출물에 반영하고, 같은 일을 반복할 명령까지 만들어 달라.

낮 무렵 들어온 요청이다. 일회성 반영으로 끝내지 않고 sync-cdg.py라는 전용 명령으로 박았다 — 결정적 단계는 사람의 손질이 아니라 도구가 책임진다는 #13의 연장이다.

  • 다이어그램에서 손본 컨테이너·컴포넌트 구조를 읽어 participant.json으로 역반영한다. 다이어그램이 데이터·구조의 또 다른 표현인 한, 어느 쪽을 손대도 반대쪽이 따라와야 한다.
  • FDSP 규약에 맞춰 컨테이너를 box로 표출하고 그 안에 컴포넌트까지 그렸다. 컴포넌트는 한 덩어리가 아니라 기능 영역 단위로 — 컨트롤러·서비스·리포지토리, 그리고 영속화 데이터(ORM)별로 — 갈라 보강했다.

여기서 한 가지 분명히 해 둔 규약: 컴포넌트를 기능 영역으로 묶는 것도 결국 결정 1과 같은 질문이다. “무엇을 한 단위로 볼 것인가.” 다이어그램의 box, 유스케이스의 목표, 시퀀스의 흐름 — 단위를 잘못 잡으면 그 아래 모든 산출물이 잘못된 결을 물려받는다.

결정 4 — 표현의 단위를 제자리로: 시퀀스·테스트·이름

오후~저녁은 흩어진 표현 단위를 한 줄로 맞추는 잔손질이었다.

  • 시퀀스는 데이터 유형 단위로 — SDSP-SQDG-DAT-001-01에서 METAR·TAF·AMOS가 마치 순차 조회처럼 그려져 있었다. 실제로는 동시·독립 조회이므로, 같은 시퀀스 모양을 반복하는 대신 데이터 유형별 조회로 묶어 표현을 바꿨다.
  • 단위 시험은 ERD 기준, 통합 시험은 컴포넌트 기준 — 테스트케이스가 기능 단위로 흩어져 있던 걸, 단위 시험은 ERD(데이터 구조)에, 통합 시험은 컴포넌트에 맞춰 정합을 다시 잡았다.
  • 이름은 논리 이름으로 — logical-data의 이름이 physical-data·ERD와 어긋나 있었다. 물리 이름이 논리 자리에 새어 들어온 것들을 논리적 이름으로 되돌리고, 그 변경이 다른 산출물에 미치는 영향까지 따라가 반영했다.

이름 하나를 바꿔도 그게 어느 산출물까지 번지는지를 매번 되짚어야 했다 — 한 층의 이름은 그 자체로 끝나지 않고 추적 체인을 타고 흐른다.

의도치 않은 함정

오늘은 두 번 발을 헛디뎠다. 둘 다 “같은 파일을 두 번 건드린” 사고였다.

  • 진단이 파일을 덮어썼다. ERD↔physical-data 정합을 비파괴로 보려고 parse_erd.convert()를 호출했는데, 이 함수는 진단 호출도 결과를 저장한다 — output_path 기본값이 실제 physical-data.json이다. 임시 경로를 주면 그 temp가 existing으로 잡혀 머지 없는 raw 투영이 나오고, 경로를 비우면 실제 파일을 ERD 73엔티티로 통째로 덮어쓴다. 미스테이징 상태이던 워킹트리 편집이 그렇게 날아갔다(스테이징된 분은 git show :file로 복구). 정답은 저장 함수를 부르지 않는 것 — parse_erd_diagram(text)와 _merge(existing, parsed, env)를 in-memory로 호출해 결과를 비교만 한다.

    “확인만 하려던” 명령이 파일을 바꾼다면, 그건 진단이 아니라 변환이다. 비파괴 점검의 첫 번째 조건은 아무것도 저장하지 않는 것이고, 그건 함수 시그니처에서 출력 경로가 사라져야 보장된다.

  • 남이 이미 한 일을 다시 했다. 이 산출물 저장소들은 세션이 도는 동안 다른 병렬 프로세스가 같은 파일을 동시에 편집·push한다. “FDSP에서 keycloak을 모두 제거하라”는 지시를 받아 조사하니 병렬 작업이 이미 제거·커밋을 끝낸 상태였다(할 일 없음). LORAS에서는 더 크게 부딪혔다 — 유스케이스 CRUD 통합을 로컬에서 38→21로 재구성했는데, origin/master가 6커밋 앞서 동일한 통합을 이미 push해 둔 상태였다. 로컬은 stale 베이스가 되어 대규모 충돌, 결국 작업을 전량 폐기하고 git reset --hard origin/master.

    여기서 규칙 하나를 세웠다: 산출물 작업 시작 전 반드시 git fetch + git status -sb·git log HEAD..@{u}로 원격 진척을 먼저 본다. behind인데 미커밋 변경이 있으면 커밋·push 금지 — 먼저 원격 상태를 보고하고 폐기/리베이스를 정한다.

마무리

오늘 관통한 결은 “무엇을 한 단위로 볼 것인가” 였다.

  • 유스케이스를 사용자 목표 단위로 — 기능 단위 28을 목표 단위 11로 통합·재채번, BPDG 8종 신설, 고아 기능 22→4.
  • 인증을 제 소관으로 — FDSP에서 Keycloak·토큰 검증을 걷어내 IAMS로, 단 이벤트 전파는 남기고 혼합 시나리오는 이벤트만 reframe.
  • 다이어그램의 손질을 산출물로 — sync-cdg.py로 C4 역반영을 명령화, 컴포넌트를 기능 영역(컨트롤러·서비스·리포지토리·ORM) 단위로 보강.
  • 표현 단위를 제자리로 — 시퀀스는 데이터 유형 단위, 테스트는 ERD·컴포넌트 단위, 이름은 논리 이름.
  • 두 번의 헛디딤 — 진단이 파일을 덮어썼고(비파괴는 in-memory로), 남이 이미 한 일을 다시 했다(작업 전 git fetch로 behind 확인).

#19가 경계를 긋는 날이었다면, 오늘은 그 경계 안에서 무엇을 한 덩어리로 묶을지를 바로잡는 날이었다. 도구는 그 과정에서 sync-cdg.py라는 역반영 명령을 얻었고, 나는 “확인만 하려던 명령이 파일을 바꿀 수 있다”는 비싼 교훈을 하나 더 챙겼다.

다음에 할 것:

  • 비파괴 진단 경로 고정 — parse_erd처럼 저장을 겸하는 함수에서 진단용 in-memory 경로를 분리해, “확인”이 파일을 못 바꾸게 시그니처 차원에서 막는다.
  • 병렬 편집 가드 도구화 — 작업 전 git fetch+behind 확인을 스킬/명령 진입점에 박아, 같은 파일을 두 번 건드리는 사고를 사람 기억이 아니라 절차로 막는다.
  • 유스케이스 단위 재정렬 잔여 저장소 전개 — SULAS에서 한 “기능 단위 → 사용자 목표 단위” 통합을, 같은 증상이 남은 나머지 도메인 저장소까지 확대한다.

Comments

Content