CI는 고쳐야 할 문제가 아니라, 말을 걸어오는 방식이다

배포가 성공했다는 건, 사실 끝이 아니라 시작이다.

특히 혼자 만들고, 혼자 배포하고, 혼자 책임지는 프로젝트라면 더 그렇다.

healthnote는 며칠 전 무사히 프로덕션에 올라갔다.
도메인도 붙었고, 모바일에서도 접속된다.
겉으로 보면 “이제 되는 것처럼” 보인다.

하지만 진짜 일은 그다음부터 시작됐다.

CI가 말을 걸어오기 시작했기 때문이다.


“로컬에서는 되는데요?”

CI 에러의 시작은 늘 이 문장이다.

로컬에서는 되는데요?

이번에도 그랬다.
테스트는 통과했고, 코드도 문제없어 보였다.

그런데 CI에서는 계속 실패했다.

  • system test에서 자바스크립트 이벤트가 잡히지 않고
  • validation 로직은 의도와 다르게 동작했고
  • 환경변수 하나가 없다는 이유로 앱이 부팅조차 되지 않았다

처음엔 짜증이 났다.
“왜 나한테만 이러나” 싶기도 했다.

그런데 로그를 차분히 다시 보니,
CI는 사실 굉장히 정직하게 말하고 있었다.


CI는 버그가 아니라, 기준이다

이번에 확실히 느낀 건 이거다.

CI는 버그를 찾는 도구가 아니라
코드베이스가 스스로를 점검하는 기준이다.

  • 로컬 환경에만 의존한 테스트
  • 암묵적으로 통과하던 validation
  • “지금은 안 쓰니까” 넘겨버린 환경변수

이 모든 걸 CI는 정확히 집어냈다.
사람처럼 눈치 보지 않고, 타협도 하지 않는다.

그래서 귀찮지만, 신뢰할 수 있다.


Skip은 도망이 아니라, 기록이다

이번 CI 과정에서 system test 일부는 skip 처리했다.
솔직히 말하면, 처음엔 찜찜했다.

하지만 중요한 건 왜 skip 했는지를 남기는 것이었다.

# NOTE:
# This test is skipped in CI due to JavaScript timing issues.
# Covered by integration tests instead.
# Revisit when Playwright is introduced.

이 주석은 나를 위한 메모이자,
미래의 나에게 남기는 약속이다.

지금 안 고친다고 해서
영원히 안 고칠 건 아니라는 표시.


한 줄 테스트가 프로젝트를 살린다

이번 CI 이슈의 핵심 중 하나는 validation이었다.

“마켓플레이스 글이 아닐 때는 상품 검증을 하지 말아야 한다.”

이 의도를 코드에만 담아두면,
언젠가는 다시 깨진다.

그래서 테스트로 못을 박았다.

test "non-marketplace post does not validate product fields" do
  post = posts(:question_post)
  product = Product.new(post: post, name: nil, price: nil)
  assert product.valid?
end

이 테스트 하나로,
같은 종류의 사고는 다시 일어나기 어려워졌다.

CI는 이렇게 기억을 대신해 주는 장치가 된다.


배포 이후에야 비로소 개발이 보인다

이번 작업을 하면서 깨달은 게 있다.

배포에 성공해야
내가 어떤 개발자인지가 보인다.

로컬에서는 다 되는 코드,
하지만 기준을 통과하지 못하는 코드.

CI는 그 차이를 명확하게 보여준다.

그리고 그 차이를 하나씩 메워가는 과정이
개발의 밀도라는 생각이 들었다.


오늘의 결론

오늘 CI 문제를 해결하면서
새로운 기능은 하나도 추가하지 않았다.

하지만 대신 얻은 게 있다.

  • 다시 터지지 않게 만드는 구조
  • 기록으로 남은 판단
  • “왜 이렇게 했는지”에 대한 설명

이게 쌓이면,
프로젝트는 혼자서도 오래 갈 수 있다.

healthnote는 이제
조금 더 단단해졌다.

그리고 나도,
조금 더 개발자다워졌다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다