MVP를 완성하고 나서 저장소를 공개하기로 했을 때, 코드가 잘 동작한다는 것과 별개로 한 가지를 다시 점검해야 했다. 실제 연동 대상 서비스의 명칭, 예시 데이터에 들어간 제품명·기관명이 코드 곳곳에 남아있었다. 개발 중에는 실제 값을 써야 테스트하기 편하지만, 공개 저장소에는 남기면 안 되는 정보였다.
정책은 단순했다. 연동 로직과 도메인 지식은 그대로 두고, 특정 서비스·기업을 특정할 수 있는 고유명사만 걷어낸다.
| 항목 | 처리 |
|---|---|
| 외부 API 클라이언트/설정 클래스명 | 특정 서비스명이 들어간 구체적 이름 → BidNoticeApiClient처럼 일반화된 이름으로 리네이밍 |
| API 엔드포인트, 오퍼레이션 ID | 코드에서 완전히 제거, 환경변수로만 주입 (BID_API_BASE_URL, BID_API_OPERATION, BID_API_SERVICE_KEY) |
| 예시 데이터의 제품명 | 가상 제품명(NGIPS-2000)으로 교체 |
| 예시 데이터의 기관명 | A기관, B기관처럼 익명화 |
| 화면 문구·문서의 외부 링크 | 전부 제거, "공공 입찰공고 Open API"로 일반화 |
| CC인증 등급, 보안적합성 검증 여부 같은 도메인 용어 | 그대로 유지 |
마지막 항목이 중요하다. "CC인증 EAL 등급"이나 "보안적합성 검증필" 같은 용어는 특정 기업이나 서비스를 가리키는 고유명사가 아니라 요구사항 유형 자체다. 매칭 엔진의 판정 규칙이 이 용어를 근거로 동작하기 때문에, 이걸 지우면 코드의 의미 자체가 사라진다. "무엇을 지울지"를 정할 때 "식별 가능한 고유명사"와 "도메인 지식"을 구분하는 게 핵심이었다.
가장 확실한 방법은 애초에 코드에 엔드포인트나 인증키를 하드코딩하지 않는 것이다.
# application.yml
bid-api:
enabled: false
base-url: ${BID_API_BASE_URL:}
operation: ${BID_API_OPERATION:}
service-key: ${BID_API_SERVICE_KEY:}
값이 비어있으면 호출 자체를 시도하지 않고 명시적으로 실패하도록 만들어서(4편 참고), 설정 누락이 조용히 묻히는 일도 막았다.
작업 파일만 고치는 걸로는 부족하다. git 히스토리에는 이전 커밋의 내용이 그대로 남아있다. 익명화 커밋을 새로 하나 얹어도, git log -p로 과거 커밋을 보면 원래 값이 그대로 드러난다.
이 프로젝트는 아직 커밋이 몇 개 안 됐던 시점이라 히스토리를 재작성하기로 했다.
git reset --soft <초기 커밋>
git commit -m "..." # 익명화가 반영된 내용으로 새로 커밋
git push --force-with-lease origin main
이후 전체 히스토리를 다시 스캔해서 식별 가능한 문자열이 하나도 남지 않았는지 확인했다.
git log -p main | grep -c "제거 대상 키워드1\|제거 대상 키워드2\|..."
# 0
force-with-lease를 쓴 이유는 force와 달리 "내가 마지막으로 본 원격 상태와 실제 원격 상태가 같을 때만" 덮어쓴다. 다른 브랜치나 CI가 그 사이 뭔가를 푸시했다면 실패하고 멈춘다 — 히스토리를 재작성하는 위험한 작업일수록 이런 안전장치가 필요하다.
배포를 검토하면서 "지금 바로 배포할 수 있나"를 점검하다가, 실제로는 준비가 안 된 부분들을 발견했다.
docker-compose.yml을 작성은 했지만 실제로 docker compose up을 돌려본 적이 없다는 걸 인정해야 했다. "파일이 있다"와 "동작을 확인했다"는 다른 이야기다.SAMPLE_DATA, BID_API_ENABLED)을 추가해서, 인증키 없이도 MySQL 기동을 확인할 수 있게 했다.이 점검을 하면서 얻은 교훈은, "README에 Dockerfile과 compose 파일이 있다"는 것만으로는 배포 준비가 됐다고 말할 수 없다는 것이다. 실행해서 확인한 것과 작성만 해둔 것은 명확히 구분해서 스스로에게 말해야 한다.
작업 도중, 배포 준비 관련 커밋이 담긴 브랜치를 병합하기 전에 먼저 내용을 검토하는 과정을 거쳤다. 실무에서도 당연한 절차지만, 개인 프로젝트라고 생략하지 않으려 했다.
체크한 항목은 이랬다.
git merge-base --is-ancestor main <검토대상브랜치> && echo "fast-forward 가능"
혼자 개발하는 프로젝트라도 "이 변경을 왜 받아들이는지"를 매번 설명할 수 있어야 한다고 생각한다.
배운 점
다음 단계
여기까지가 이 프로젝트의 개발 기록이다. 전체 흐름을 다시 정리하면: 문제를 자동화 대상과 사람 판단 대상으로 명확히 쪼개고(1편), 그 핵심을 도메인 규칙으로 구현하고(2편), API와 트랜잭션 정책으로 정합성을 지키고(3편), 외부 의존성의 실패를 격리하고(4편), 그 결과를 사람이 읽기 좋게 보여주고(5편), 여러 층위에서 검증하고(6편), 마지막으로 공개 가능한 상태로 정리했다(7편).
이 시리즈는 개인 학습 프로젝트 개발 기록입니다. 코드에 등장하는 기관명·제품명은 전부 가상이며, 실제 연동 대상 서비스의 명칭·엔드포인트는 기술적 세부사항 보호를 위해 일반화해서 서술합니다.