SYDESYDE
SYDESYDE
  • 피드
  • 쇼케이스
  • 블로그
  • 모임
SYDESYDE© 2026 SYDE. All rights reserved.
SYDE 소개문의하기
Kakao
SYDE 오픈채팅
Instagram
Instagram
Threads
Threads
커뮤니티 가이드라인협업문의이용약관개인정보처리방침
커뮤니티 가이드라인협업문의이용약관개인정보처리방침

© 2026 SYDE. All rights reserved.

팀원마다 다른 AI 툴 — 컨벤션 문서로 AI 협업의 일관성 맞추기

jJT Kim· 11일 전· 해프닝·회고
목차
  • 들어가며
  • 문제: 도구가 다르면 테스트의 결도 달라진다
  • 계기: AWS Summit Seoul 2026 삼성전자 발표
  • 방법: docs에 컨벤션 문서를 두고 AI가 참고하게 했다
  • AI에게 넘긴 테스트 규칙
  • 1. 테스트 파일명에는 유스케이스 번호를 넣는다
  • 2. 레이어별로 테스트를 나누고, 책임을 섞지 않는다
  • 3. 테스트 대역: Unit은 Fake, API는 Stub
  • 4. 테스트 상수 prefix
  • 5. 파일 구조와 AAA 흐름
  • 6. 기준은 최신 문서, 오래된 주석은 믿지 않는다
  • 달라진 점
  • 문서가 올라온 날, 테스트가 정리됐다
  • 다른 도구, 같은 테스트
  • 리뷰에서 스타일 이야기가 빠졌다
  • 문서도 같이 자랐다
  • 아쉬웠던 점
  • 마치며

목차

  • 들어가며
  • 문제: 도구가 다르면 테스트의 결도 달라진다
  • 계기: AWS Summit Seoul 2026 삼성전자 발표
  • 방법: docs에 컨벤션 문서를 두고 AI가 참고하게 했다
  • AI에게 넘긴 테스트 규칙
  • 1. 테스트 파일명에는 유스케이스 번호를 넣는다
  • 2. 레이어별로 테스트를 나누고, 책임을 섞지 않는다
  • 3. 테스트 대역: Unit은 Fake, API는 Stub
  • 4. 테스트 상수 prefix
  • 5. 파일 구조와 AAA 흐름
  • 6. 기준은 최신 문서, 오래된 주석은 믿지 않는다
  • 달라진 점
  • 문서가 올라온 날, 테스트가 정리됐다
  • 다른 도구, 같은 테스트
  • 리뷰에서 스타일 이야기가 빠졌다
  • 문서도 같이 자랐다
  • 아쉬웠던 점
  • 마치며

들어가며

현대오토에버 모빌리티 SW스쿨 과정에서 팀 프로젝트를 진행했다. 인프라 중심 프로젝트라 애플리케이션 코드의 비중이 크지는 않았고, AI 코딩 도구는 주로 테스트 코드를 작성하는 데 썼다.

문제는 팀원마다 쓰는 AI 도구가 달랐다는 점이다. 누구는 Claude Code를, 누구는 Codex를 썼고, 에이전트 없이 채팅으로만 쓰는 팀원도 있었다. 도구야 각자 편한 걸 쓰면 되지만, 테스트 코드는 결국 같은 레포에 모인다.

이 글은 서로 다른 AI 도구를 쓰는 팀이 컨벤션 문서 하나로 AI가 짜는 테스트 코드를 맞춘 과정에 대한 기록이다.

문제: 도구가 다르면 테스트의 결도 달라진다

같은 코드베이스를 보더라도 AI마다 이해하는 방식과 제안하는 코드가 다르다. "이 기능 테스트 짜줘"라고 똑같이 요청해도 결과물의 모양은 제각각이다.

실제로 우리 팀도 그랬다. 각자 맡은 유스케이스의 단위 테스트를 먼저 짜기 시작했는데, 며칠 만에 레포에는 이런 파일들이 섞여 있었다.

test_create_qr_session.py
test_get_parking_fee.py
test_register_pre_notify.py
test_verify_and_tokenize_card.py

이름만으로는 어떤 유스케이스를 검증하는지, 어느 도메인 소속인지 알기 어려웠다. API 테스트를 어디에 둘지도 정해지지 않아서 tests/integration/api/ 아래에 폴더가 먼저 만들어져 있었다.

사람끼리 협업할 때는 회의와 코드 리뷰를 거치면서 "우리 팀은 이렇게 한다"는 감각이 공유된다. 하지만 AI는 그 감각을 모른다. 팀원 머릿속에만 있는 규칙은 AI에게 전달되지 않는다.

계기: AWS Summit Seoul 2026 삼성전자 발표

방향을 잡게 된 건 AWS Summit Seoul 2026에서 본 삼성전자의 발표 덕분이었다. 핵심은 이랬다. AI에게 그냥 만들라고 시키는 대신, 조직의 암묵지와 규칙을 함께 넣어서 만들라고 시켰더니 결과물의 일관성이 유지됐다는 것이다.

우리 팀이 겪던 문제와 정확히 같은 이야기였다. AI 도구가 달라서 결과물이 흔들린다면, 도구를 하나로 통일하는 것보다 모든 AI가 같은 규칙을 참고하게 만드는 것이 답일 수 있겠다고 생각했다. 그래서 발표를 보고 바로 팀에 테스트 컨벤션을 문서로 만들어 AI에게 넘기자고 제안했다.

방법: docs에 컨벤션 문서를 두고 AI가 참고하게 했다

제안이 받아들여졌고, 팀원이 머릿속에 있던 "우리 팀은 테스트를 이렇게 짠다"를 꺼내 문서로 정리했다. 단위 테스트 컨벤션과 API 테스트 컨벤션, 두 개의 문서를 레포의 docs/conventions/ 아래에 두었다.

docs/conventions/
  unit-testing-conventions.md
  api-testing-conventions.md

AI에게 넘기는 방식은 팀원이 쓰는 도구에 따라 달랐다.

  • 에이전트를 쓰는 팀원은 테스트를 짜기 전에 AI에게 이 파일을 읽으라고 지시했다.

  • 채팅으로만 쓰는 팀원은 문서 내용을 대화에 붙여넣고 시작했다.

방식은 달라도 AI가 보는 기준은 같은 파일 하나였다. 이렇게 하니 좋은 점이 몇 가지 있었다.

  • 도구가 달라도 기준은 하나다. Claude Code든 Codex든 채팅이든 같은 문서를 본다.

  • 사람과 AI가 같은 문서를 본다. 팀원이 리뷰할 때 보는 기준과 AI가 코드를 짤 때 보는 기준이 같다.

  • 규칙을 바꾸면 한 곳만 고치면 된다. 문서를 수정하면 다음 작업부터 모든 팀원의 AI에 반영된다.

AI에게 넘긴 테스트 규칙

문서에 담은 규칙 중 AI의 결과물을 맞추는 데 효과가 컸던 것들을 정리했다.

1. 테스트 파일명에는 유스케이스 번호를 넣는다

test_uc_{domain}_{number}_{use_case_name}.py

test_uc_auth_001_create_qr_session.py
test_uc_pay_001_get_parking_fee.py

파일명만 봐도 어떤 도메인의 몇 번 유스케이스를 검증하는지 알 수 있게 했다. 반대로 구현 파일은 다른 코드에서 import되므로 create_qr_session.py처럼 기능명으로 짓는다. 테스트와 구현의 이름 규칙을 다르게 둔 이유까지 문서에 적어두니, AI가 구현 파일에 UC 번호를 붙이는 일이 없었다.

2. 레이어별로 테스트를 나누고, 책임을 섞지 않는다

테스트 종류

검증 대상

위치

Unit Test

비즈니스 로직

tests/unit/

API Test

HTTP 계약 (endpoint, status code, auth guard)

tests/api/

Integration Test

실제 DB / Redis / 외부 client 연동

tests/integration/

E2E Test

핵심 사용자 흐름

tests/e2e/

가장 중요하게 정한 원칙은 Unit Test에서는 HTTP status code를 검증하지 않는다는 것이다. 유스케이스 문서에 "400 반환"이라고 적혀 있어도, Unit Test는 서비스가 에러를 던지는지만 본다. 그게 HTTP 400으로 바뀌는지는 API Test에서 따로 본다.

이런 경계는 사람이라면 리뷰를 몇 번 거치며 익히는 암묵지에 가깝다. 하지만 AI는 팀의 암묵지를 알 수 없다. 문서에 명시하고 나서는 어떤 AI가 짜든 테스트가 같은 층위에 놓였다.

(E2E는 기준만 정해두고, 이번 프로젝트에서는 실제로 작성하지 못했다.)

3. 테스트 대역: Unit은 Fake, API는 Stub

  • Unit Test에서는 실제 DB, Redis, 외부 API 대신 Fake{역할} 클래스를 쓴다. 메모리 dict나 list로 필요한 동작만 흉내 내고, 테스트는 Fake에 남은 상태를 검증한다.

  • API Test에서는 service 계층을 Stub 클래스로 바꾼다. Stub은 성공이나 실패만 돌려주는 최소 구현이고, 비즈니스 로직을 넣지 않는다.

class FakeQrSessionStore:
    def __init__(self):
        self.saved_sessions = {}

    def save_pending_session(self, *, session_id: str, vin_hash: str, ttl_seconds: int):
        self.saved_sessions[session_id] = {
            "session_id": session_id,
            "vin_hash": vin_hash,
            "status": "pending",
            "ttl_seconds": ttl_seconds,
        }

이 규칙이 없으면 AI마다 unittest.mock을 쓰기도 하고 직접 객체를 만들기도 해서, 같은 저장소를 대체하는 코드가 테스트 파일마다 달라진다. 규칙을 정한 뒤 4개 서비스의 테스트 어디에도 unittest.mock은 쓰이지 않았고, 모든 대역이 Fake 또는 Stub 이름 규칙을 따랐다.

4. 테스트 상수 prefix

prefix

의미

VALID_

정상 입력값

INVALID_

잘못된 입력값

EXPIRED_

만료된 값

OTHER_

다른 사용자, 차량, 세션 등 비교용 값

테스트 데이터는 파일 상단에 상수로 선언하고, 본문에서 같은 값을 반복해서 직접 쓰지 않는다. 상수 이름만 보고도 이 값이 어떤 시나리오를 위한 것인지 알 수 있다.

5. 파일 구조와 AAA 흐름

테스트 파일은 docstring → import → 상수 → Fake → fixture → 테스트 클래스 → 테스트 함수 순서로 쓴다. 테스트 함수명은 영어 snake_case로 쓰고, 무엇을 검증하는지는 한글 docstring으로 적는다. 본문은 Arrange → Act → Assert 흐름을 따른다.

class TestCreateQrSession:
    """UC-AUTH-001 - POST /auth/qr-session"""

    def test_valid_request_stores_pending_session(
        self,
        create_qr_session_service,
        fake_qr_session_store,
    ):
        """유효한 요청이면 QR 세션을 pending 상태로 저장한다."""
        # Arrange
        command = CreateQrSessionCommand(
            login_session_id=VALID_SESSION_ID,
            vin_hash=VALID_VIN_HASH,
        )

        # Act
        create_qr_session_service.execute(command)

        # Assert
        saved = fake_qr_session_store.saved_sessions[VALID_SESSION_ID]
        assert saved["status"] == "pending"
        assert saved["ttl_seconds"] == 15 * 60

6. 기준은 최신 문서, 오래된 주석은 믿지 않는다

AI 협업에서 의외로 중요했던 규칙이다. 테스트의 API 경로와 요청·응답 형식은 항상 docs/api/의 OpenAPI 스펙과 docs/use-cases/ 문서를 기준으로 하고, 테스트 파일에 남아 있는 오래된 주석이나 docstring은 기준으로 삼지 않는다고 명시했다.

AI는 눈앞에 있는 코드와 주석을 그대로 믿는 경향이 있다. 스펙이 바뀌었는데 예전 주석이 남아 있으면, AI는 그 주석을 근거로 틀린 테스트를 짠다. 어느 문서가 진실의 원천인지 정해두는 것만으로 이런 일을 줄일 수 있었다.

달라진 점

문서가 올라온 날, 테스트가 정리됐다

컨벤션 문서가 올라온 날, 팀원들이 각자 자기 테스트 파일을 규칙에 맞게 정리했다. test_get_parking_fee.py는 test_uc_pay_001_get_parking_fee.py가 됐고, tests/integration/api/에 있던 API 테스트 폴더는 tests/api/로 옮겨졌다. 누가 일일이 지적하지 않아도, 기준 문서 하나로 정리가 끝났다.

다른 도구, 같은 테스트

API 테스트 컨벤션이 올라온 다음 날에는 여러 팀원이 각자 맡은 유스케이스의 API 테스트를 하루 만에 올렸다. 쓰는 AI 도구도, 문서를 넘기는 방식도 달랐지만 결과물은 같은 구조였다. 4개 서비스의 테스트가 모두 같은 파일명 규칙, 같은 디렉터리 구조, 같은 Fake·Stub 패턴을 따랐다. 발표에서 말한 "일관성 유지"를 우리 팀 규모에서도 확인할 수 있었다.

리뷰에서 스타일 이야기가 빠졌다

테스트 구조와 이름이 맞춰지자 리뷰는 "컨벤션을 지켰는가"를 확인하는 일로 단순해졌다. 스타일 이야기를 할 필요가 없으니, 테스트가 정말 필요한 경우를 검증하고 있는지에 집중할 수 있었다.

문서도 같이 자랐다

컨벤션 문서는 한 번 쓰고 끝나지 않았다. 예를 들어 API 테스트에서 dependency_overrides를 복구하는 fixture는 처음에는 단순히 yield 뒤에 원래 값을 되돌려 놓는 형태였는데, 테스트가 중간에 실패해도 원래 값이 확실히 복구되도록 try/finally로 감싸는 기준이 나중에 문서에 추가됐다. 문서가 바뀐 뒤 기존 API 테스트도 같은 형태로 정리됐고, 결과적으로 override를 쓰는 모든 API 테스트가 같은 복구 패턴을 따르게 됐다. 규칙을 바꿀 때 팀원 모두에게 일일이 알릴 필요 없이 문서 한 곳만 고치면 됐다.

아쉬웠던 점

효과를 수치로 남겨두지 못한 것이 가장 아쉽다. 리뷰 시간이 얼마나 줄었는지 기록해 뒀다면 이 글이 훨씬 설득력 있었을 것이다.

또 컨벤션을 지키는 일을 사람과 AI의 성실함에 맡겼다. 다음에는 테스트 파일명이나 디렉터리 위치처럼 기계적으로 확인할 수 있는 규칙을 린터나 CI로 검사해 보고 싶다.

마치며

AI를 팀으로 쓸 때 중요한 건 어떤 도구를 쓰느냐보다 모든 도구가 같은 기준을 보게 만드는 것이었다. 사람 사이에서는 말하지 않아도 공유되던 규칙도 AI에게는 적어서 넘겨야 한다. 팀의 암묵지를 문서로 꺼내 레포에 두는 일이 결국 AI 협업의 출발점이었다.

  • #ai
13
J
JT Kim인프라 엔지니어를 목표로 하는 신입

댓글 0

My avatar