Devin.KR

AI 와 함께 디버깅하기 - 재현·가설·확인

개발자KR 조회 0

이 장에서 배우는 것

앞 장에서 테스트를 통해 코드가 맞는다는 증거를 요구했다. 이번에는 그 증거가 실패했을 때 무엇을 해야 하는지 다룬다. 디버깅(debugging)은 프로그램이 예상과 다르게 움직이는 원인을 찾아 고치는 과정이다. AI에게 “오류를 고쳐 달라”라고 말하는 것도 시작은 될 수 있다. 그러나 입력과 실행 순서가 빠져 있으면 AI는 실제 문제 대신 짐작한 문제를 고칠 수 있다.

혼자 쓰는 할 일 관리 도구에 마감일을 추가했다고 생각해 보자. 날짜를 저장하는 기능은 짧지만, 연도·월·일의 순서를 한 번 바꾸면 정상적으로 보이는 잘못된 날짜와 실행을 멈추는 오류가 함께 생긴다. 이 장에서는 두 증상을 같은 재현 테스트로 묶고, 원인에 관한 가설을 하나씩 확인한다.

  • 오류 메시지, 입력, 실행 절차, 기대 결과를 구분해 AI에게 전달한다.
  • 추측에 따른 수정과 증거에 따른 수정을 구별한다.
  • 실패를 먼저 테스트로 재현하고 같은 테스트로 수정 결과를 확인한다.
  • 같은 수정이 반복될 때 멈추고 관찰 자료를 다시 모은다.
  • 날짜 해석 오류를 고치기 전과 후의 결과를 한 프로그램으로 비교한다.

문제 상황

할 일 관리 도구는 사용자가 입력한 마감일을 날짜 값으로 바꾼다. 이런 변환을 파싱(parsing)이라고 한다. 문자열 “2026-03-08”을 연도 2026, 월 3, 일 8로 해석해 날짜 객체로 만드는 일이다. 객체는 여기서 연도·월·일을 함께 담고 날짜 관련 기능을 제공하는 값이라고 이해하면 된다.

“책상 정리”의 마감일에 2026-03-08을 입력하자 도구는 2026-08-03을 표시한다. 다른 할 일에 2026-03-14를 넣으면 이번에는 실행이 멈춘다. 오류 메시지에는 “month must be in 1..12”가 나온다. 입력한 월은 3인데 왜 월의 범위를 벗어났다고 하는지 처음에는 납득하기 어렵다.

두 현상을 별개로 생각하면 화면 표시 형식을 바꾸거나, 오류가 나면 오늘 날짜를 넣는 수정을 할 수 있다. 그러면 첫 번째 입력의 잘못된 날짜는 남고 두 번째 입력의 오류만 감춰진다. 먼저 해야 할 일은 수정이 아니라, 어떤 입력이 어떤 결과를 만드는지 고정하는 일이다.

AI에게 처음 보내는 자료는 다음처럼 구성한다. 실제 작업에서는 경로와 줄 번호를 포함한 전체 오류 기록도 그대로 붙인다. 아래 메시지는 두 증상을 설명하는 요청 예시다.

할 일 도구의 날짜 변환 함수에서 문제가 발생한다. 실행 환경은 Python 3.12 이상이다. 날짜 입력 규칙은 YYYY-MM-DD이며, 입력한 날짜를 그대로 마감일로 보존해야 한다.

재현 절차는 다음과 같다. 날짜 변환 함수에 “2026-03-08”을 전달한 뒤 반환값을 출력한다. 기대 결과는 “2026-03-08”인데 실제 결과는 “2026-08-03”이다.

같은 함수에 “2026-03-14”를 전달하면 ValueError가 발생한다. 오류 메시지 원문은 “month must be in 1..12”다.

먼저 두 증상을 함께 설명할 수 있는 가설을 제시하라. 아직 코드를 수정하지 말고, 가설을 확인할 입력과 관찰할 값을 알려 달라.

ValueError는 함수에 전달한 값이 그 함수가 받아들일 수 있는 조건을 만족하지 않을 때 발생하는 예외다. 예외는 실행 중 문제가 생겼음을 알리는 신호다. 오류 메시지는 월로 전달된 값이 범위를 벗어났다고 알려 줄 뿐, 그 값이 왜 잘못 전달됐는지까지 설명하지는 않는다.

오류를 해석하기 전에 재현을 고정한다

재현은 같은 조건에서 같은 문제를 다시 만드는 일이다. “가끔 날짜가 이상하다”는 보고보다 “2026-03-08을 넣으면 2026-08-03이 나온다”는 보고가 더 유용하다. AI도 사람도 같은 입력을 실행하고 결과를 비교할 수 있기 때문이다.

오류가 발생했을 때 출력되는 호출 경로를 트레이스백(traceback)이라고 한다. 어떤 함수가 어떤 함수를 호출하다가 문제가 생겼는지 보여 준다. 마지막 줄의 예외 이름과 메시지만 보내면 문제가 드러난 위치는 알 수 있어도, 그 위치로 값이 들어온 경로를 놓칠 수 있다. 개인 정보나 비밀값이 없다면 오류 기록 전체를 전달하고, 필요한 부분을 AI가 짚게 하는 편이 낫다.

비밀값이 포함된 경우에는 해당 값만 가리고 경로와 오류 문장은 가능한 한 보존한다. 무엇을 가렸는지도 짧게 적는다. 메시지를 자연스럽게 고쳐 쓰는 과정에서 따옴표, 입력 형식, 예외 이름이 달라지면 원인을 판단하는 자료가 바뀔 수 있다.

재현 요청에 포함할 자료와 그 역할
자료이 예제에서 전달할 내용확인할 수 있는 것
환경Python 3.12 이상, 표준 라이브러리실행 조건의 차이
입력과 절차날짜 함수에 2026-03-14 전달실패를 다시 만드는 방법
기대 결과2026년 3월 14일 반환사용자가 정한 성공 기준
실제 결과ValueError와 오류 메시지 원문관찰된 실패의 형태

기대 결과와 실제 결과는 분리해서 적는다. “날짜 함수가 잘못됐다”는 판단이고, “8월 3일을 반환했다”는 관찰이다. 판단만 전달하면 AI가 그 판단을 전제로 다른 곳을 수정할 수 있다. 관찰을 먼저 주면 판단을 다시 검토할 수 있다.

재현 절차는 짧을수록 비교하기 쉽지만, 필요한 조건까지 없애서는 안 된다. 화면에서만 문제가 생긴다면 화면 입력부터 실행해야 한다. 반대로 날짜 함수에 문자열을 직접 전달해도 같은 문제가 생긴다면 화면과 파일 저장을 제외하고 그 함수부터 조사할 수 있다. 이 장의 예제는 함수 호출만으로 두 증상을 재현한다.

입력과 기대 결과와 실제 결과를 고정해야 수정 전후를 같은 기준으로 비교할 수 있다

가설 하나씩 확인하고 반복 수정에는 멈춤 기준을 둔다

가설은 아직 확인하지 않은 원인 설명이다. “월과 일이 바뀌었다”는 가설이고, 실제 호출에서 월 자리에 14가 들어간 것을 확인하는 일은 검증이다. AI가 자연스럽게 설명했다고 해서 가설이 관찰된 사실로 바뀌지는 않는다.

이번 문제의 첫 가설은 날짜를 만드는 함수에 월과 일을 반대로 전달했다는 것이다. 2026-03-08이 2026-08-03으로 바뀐 현상과 2026-03-14에서 월 범위 오류가 난 현상을 함께 설명한다. 반면 “입력에 공백이 있다”는 가설은 두 증상을 함께 설명하기 어렵다. 우선 설명력이 높은 가설부터 작은 확인을 한다.

AI의 답 예시: 월과 일이 뒤바뀌었을 가능성이 있다. 문자열을 나눈 직후의 year, month, day 값과 날짜 생성 함수에 전달하는 순서를 확인하면 된다. 입력이 2026-03-14일 때 변수는 2026, 3, 14인데 호출이 date(year, day, month)라면 월 자리에 14가 전달된다.

확인할 지점이 정해졌으므로, 실제 코드를 읽고 인수 순서를 살핀다. 인수는 함수를 호출할 때 전달하는 값이다. 변수 이름이 올바르게 붙어 있어도 전달 순서가 틀릴 수 있다. AI의 설명을 읽은 뒤 “그래서 원인은 월·일 순서다”라고 곧바로 결론 내리지 말고, 코드의 해당 표현과 실행 결과를 연결해야 한다.

한 번에 여러 가설을 반영하면 어떤 변경이 문제를 해결했는지 알기 어렵다. 날짜 함수, 화면 출력, 저장 형식을 동시에 바꾸고 테스트가 통과해도 원인을 설명할 근거가 약해진다. 먼저 한 가설을 확인하고 그 결과에 따라 다음 행동을 정한다. 가설이 틀렸다면 틀렸다는 관찰도 기록한다.

수정 요청에도 범위를 넣는다. 이 예제의 날짜 규칙은 구분자와 자릿수를 포함한 YYYY-MM-DD다. 월·일 순서를 고치는 과정에서 구분자 없는 날짜나 다른 형식까지 허용하면 기능의 약속이 달라진다. 수정 후에는 변경된 부분을 보여 주는 diff를 읽고, 원인과 관계없는 변경이 섞였는지 확인한다.

월과 일을 전달하는 순서가 뒤집혀 있음을 확인했다. 날짜 규칙 YYYY-MM-DD를 유지하면서 날짜 변환 함수만 고쳐 달라. 기존 재현 테스트의 입력과 기대값은 유지하라. 수정 뒤에는 테스트 결과와 변경 부분을 보여 주고, 두 증상이 같은 원인에서 생긴 이유를 설명하라.

같은 수정이 반복되면 작업을 잠시 멈춘다. 예를 들어 월·일 순서를 바꿨다가 되돌리는 제안이 다시 나오거나, 같은 입력에서 같은 실패가 계속되는데 주변 코드만 달라진다면 새로운 정보 없이 수정하고 있을 가능성이 있다. “한 번 더 고쳐 달라”를 반복하기 전에 현재 코드를 기준으로 재현을 다시 실행한다.

멈춘 뒤에는 실행 중인 파일이 실제로 수정한 파일인지, 전달한 오류 기록이 현재 코드에서 나온 것인지, 입력이 보고한 값과 같은지 확인한다. 실패를 설명하는 가설 하나와 그것을 확인할 관찰 하나가 없다면 추가 수정을 보류한다. 멈춤의 목적은 포기가 아니라, 비교 기준을 회복하는 데 있다.

실패를 테스트로 남기고 원인을 내 말로 설명한다

고치기 전에 테스트가 실제로 실패해야 한다. 그래야 수정 뒤의 통과가 의미를 가진다. 실행이 멈춘 입력만 검사하면 2026-03-08처럼 잘못된 날짜를 정상 반환하는 문제를 놓친다. 따라서 예외 발생 여부와 반환값의 정확성을 함께 검사한다.

이번 테스트는 네 가지 입력을 사용한다. 월과 일이 모두 12 이하인 정상 날짜, 일이 12보다 큰 정상 날짜, 존재하지 않는 날짜, 규칙과 다른 구분자다. 앞의 두 개는 발견한 문제를 재현한다. 뒤의 두 개는 수정 과정에서 잘못된 입력을 받아들이지 않는지 확인한다.

발견한 오류가 다시 생기지 않는지 확인하기 위해 남겨 두는 테스트를 회귀 테스트(regression test)라고 한다. 같은 함수의 인수 순서를 나중에 다시 바꾸더라도 이 테스트가 잘못된 결과를 알려 준다. 다만 네 입력이 통과한다고 모든 날짜 처리가 확인된 것은 아니다. 이 테스트가 제공하는 증거의 범위는 네 입력과 지정한 날짜 규칙이다.

수정 전 실패한 테스트를 그대로 다시 실행해야 수정 후 통과가 해결의 증거가 된다

AI에게 디버깅을 통째로 맡기면 결과물을 더 빨리 받을 수 있는 경우가 있다. 그러나 원인을 세우고 관찰값을 고르고 예상과 비교하는 연습은 AI가 대신 수행한다. 코드가 고쳐진 것과 내가 원인을 이해한 것은 서로 다른 결과다. 화면에 나타난 오류 문장을 읽기만 하고 다음 단계가 무엇인지 늘 AI에게 맡기면, 비슷한 문제에서도 직접 조사할 실마리를 얻기 어렵다.

모든 수정을 손으로 할 필요는 없다. AI가 재현용 코드를 만들고 변경안을 작성해도 된다. 대신 나는 “이 가설이라면 어떤 값이 나와야 하는가”를 먼저 적고, 실행 뒤에는 “어떤 관찰로 가설을 확인했는가”를 다시 쓴다. 이 두 문장이 있으면 AI의 답을 내 판단과 연결할 수 있다.

이번 문제를 내 말로 설명하면 다음과 같다. 문자열을 나누는 단계는 연도·월·일을 올바르게 얻었다. 날짜를 만드는 호출에서 월과 일의 위치가 바뀌었다. 일이 8이면 월로도 유효해서 잘못된 날짜가 반환되고, 일이 14이면 월로 유효하지 않아 예외가 발생했다. 서로 다른 증상이 같은 호출 순서에서 나왔다.

완성 코드

다음 내용을 main.py로 저장한다. 외부 패키지, 파일 입력, 네트워크, 현재 시각을 사용하지 않는다. 프로그램은 버그가 있는 함수와 수정한 함수에 같은 테스트를 적용한 뒤, 수정한 함수로 할 일 두 개의 마감일을 출력하고 종료한다. 수정 전 함수는 비교를 위한 예제이며 실제 할 일 처리에는 수정한 함수만 사용한다.

기대값이 None인 사례는 날짜를 반환하는 대신 ValueError를 발생시켜야 한다는 뜻이다. 테스트 실행기는 ValueError만 처리한다. 그 밖의 예외는 프로그램을 멈추게 하여 예상하지 못한 문제를 드러낸다.

from datetime import date


def parse_date_before(text):
    year, month, day = map(int, text.split("-"))
    return date(year, day, month)


def parse_date_after(text):
    parsed = date.fromisoformat(text)
    if parsed.isoformat() != text:
        raise ValueError("날짜 형식은 YYYY-MM-DD여야 한다")
    return parsed


CASES = (
    ("월과 일 구별", "2026-03-08", date(2026, 3, 8)),
    ("12보다 큰 일", "2026-03-14", date(2026, 3, 14)),
    ("없는 날짜 거부", "2026-02-30", None),
    ("다른 구분자 거부", "2026/03/08", None),
)


def run_tests(parser, label):
    passed = 0
    print(f"[{label}]")

    for name, text, expected in CASES:
        try:
            actual = parser(text)
        except ValueError:
            ok = expected is None
            detail = "ValueError 발생"
        else:
            ok = expected is not None and actual == expected
            detail = actual.isoformat()

        if ok:
            passed += 1
            print(f"통과: {name}")
        else:
            wanted = (
                "ValueError"
                if expected is None
                else expected.isoformat()
            )
            print(f"실패: {name} | 기대={wanted} | 실제={detail}")

    print(f"결과: {passed}/{len(CASES)} 통과")
    return passed == len(CASES)


def main():
    before_ok = run_tests(parse_date_before, "수정 전")
    print()
    after_ok = run_tests(parse_date_after, "수정 후")

    if before_ok:
        raise RuntimeError("수정 전 함수에서 버그가 재현되지 않았다")
    if not after_ok:
        raise RuntimeError("수정 후 함수에 실패한 테스트가 있다")

    tasks = (
        ("책상 정리", "2026-03-08"),
        ("메모 분류", "2026-03-14"),
    )

    print()
    print("[수정 후 할 일]")
    for title, due_text in tasks:
        due = parse_date_after(due_text)
        print(f"{title} | 마감일={due.isoformat()}")


if __name__ == "__main__":
    main()

줄별 해설

첫 줄의 from datetime import date는 표준 라이브러리에서 날짜를 다루는 date를 가져온다. 날짜 객체를 만들 때는 연도, 월, 일을 이 순서로 전달한다. 프로그램의 실패 원인을 이해하려면 이 순서와 수정 전 함수의 호출을 직접 대조해야 한다.

parse_date_before 안의 text.split("-")는 문자열을 하이픈 기준으로 나눈다. map(int, ...)는 나눈 문자열 각각에 int를 적용한다. 결과를 year, month, day에 차례로 넣는 부분까지는 의도에 맞는다. 다음 줄의 date(year, day, month)가 월과 일을 뒤집어 전달한다.

parse_date_after의 date.fromisoformat(text)는 날짜 문자열을 읽어 날짜 객체를 만든다. 다만 이 메서드가 받아들이는 형식은 우리 도구의 입력 규칙보다 넓다. 따라서 변환된 날짜를 isoformat()으로 다시 문자열로 만들고 원래 입력과 비교한다. 다시 만든 문자열은 YYYY-MM-DD 형태다. 서로 다르면 도구에서 허용한 표현이 아니므로 ValueError를 발생시킨다.

이 비교는 날짜 자체의 유효성 검사와 형식 검사를 나눈다. 존재하지 않는 날짜는 fromisoformat에서 거부된다. 날짜로 해석할 수 있더라도 원래 입력이 지정한 표현과 다르면 그다음 조건에서 거부된다. 수정 함수는 수동으로 나눈 숫자의 순서를 전달하는 부분을 없애면서 기존 형식 규칙도 명시한다.

CASES에는 이름, 입력, 기대값을 한 묶음씩 넣는다. 정상 날짜의 기대값은 날짜 객체로 직접 만든다. 잘못된 입력의 기대값에는 None을 넣는다. 잘못된 함수가 내놓은 결과를 기대값으로 복사하지 않았다는 점이 중요하다. 기대값은 사용자의 날짜 규칙에서 나온다.

테스트 실행기의 각 표현이 판정하는 내용
표현실행되는 상황역할
actual = parser(text)각 사례를 검사할 때전달받은 날짜 함수를 실제 실행한다
except ValueError날짜 함수가 입력을 거부했을 때거부가 기대한 결과인지 확인한다
expected is not None and actual == expected날짜 함수가 값을 반환했을 때정상 입력이며 정확한 날짜인지 확인한다
passed == len(CASES)모든 사례를 검사한 뒤전체 사례의 통과 여부를 반환한다

run_tests의 parser는 검사할 함수를 받는 매개변수다. 함수를 값처럼 전달할 수 있으므로 같은 검사 절차를 수정 전후에 그대로 사용할 수 있다. label은 출력 제목에만 쓰며 판정에는 영향을 주지 않는다.

try 안에서는 날짜 함수를 실행한다. ValueError가 발생하면 except 부분으로 이동한다. 기대값이 None이면 거부해야 하는 입력이므로 통과다. 정상 날짜를 기대했는데 예외가 발생했다면 실패다. 여기서 예외를 처리하는 목적은 실패를 감추는 것이 아니라, 나머지 사례도 실행해 결과를 모으는 것이다.

예외가 발생하지 않으면 try에 붙은 else 부분이 실행된다. 기대값이 정상 날짜인지 먼저 확인하고 실제 날짜와 비교한다. 이 조건 때문에 “오류가 나지 않았다”만으로 통과하지 않는다. 2026-03-08을 넣고 2026-08-03을 반환한 경우도 실패로 잡는다.

통과한 사례는 passed를 하나 늘린다. 실패한 사례는 wanted에 기대 결과를 담아 실제 결과와 함께 출력한다. 예외 원문 전체 대신 “ValueError 발생”을 표시한 것은 예제의 출력 형식을 일정하게 유지하기 위해서다. 실제 디버깅 요청에는 앞서 설명한 것처럼 원래 오류 기록을 별도로 전달해야 한다.

main은 두 함수를 같은 CASES로 검사한다. before_ok가 참이면 의도한 버그가 테스트에서 드러나지 않았다는 뜻이므로 예제를 중단한다. after_ok가 거짓이어도 중단한다. 이 두 조건은 수정 전의 실패와 수정 후의 통과를 모두 확인하게 만든다.

마지막 반복문은 수정한 함수를 실제 할 일 데이터에 적용한다. 테스트 결과만 보고 끝내지 않고, 도구가 표시할 마감일도 확인한다. 마지막 두 줄은 이 파일을 직접 실행했을 때 main을 호출한다.

실행 결과

macOS 또는 Linux의 터미널에서 main.py가 있는 디렉터리로 이동한 뒤 다음 명령을 실행한다.

python3 main.py

예상 출력은 다음과 같다. 수정 전의 실패 두 개는 프로그램이 보여 주려는 재현 결과다. 수정 후 네 사례가 통과하고, 두 할 일의 마감일이 입력한 날짜와 일치한다.

[수정 전]
실패: 월과 일 구별 | 기대=2026-03-08 | 실제=2026-08-03
실패: 12보다 큰 일 | 기대=2026-03-14 | 실제=ValueError 발생
통과: 없는 날짜 거부
통과: 다른 구분자 거부
결과: 2/4 통과

[수정 후]
통과: 월과 일 구별
통과: 12보다 큰 일
통과: 없는 날짜 거부
통과: 다른 구분자 거부
결과: 4/4 통과

[수정 후 할 일]
책상 정리 | 마감일=2026-03-08
메모 분류 | 마감일=2026-03-14

수정 전에도 잘못된 입력 두 개는 거부한다. 이 사실은 날짜 함수 전체가 옳다는 뜻이 아니다. 정상 입력을 잘못 해석하는 문제와 잘못된 입력을 거부하는 동작이 함께 존재한다. 통과 개수만 보지 말고 어떤 사례가 실패했는지 읽어야 한다.

완성 코드에는 수정 전 함수를 남겨 비교한다. 실제 프로젝트에서는 고친 함수를 사용하고 재현 테스트를 보존하면 된다. 변경 검토에서는 날짜 변환 부분이 원인에 맞게 달라졌는지, 기대값이 그대로인지 확인한다. 코드 검토와 실행 결과가 같은 설명을 뒷받침할 때 수정에 대한 근거가 생긴다.

실무에서 자주 틀리는 것

월과 일이 같은 입력으로만 확인한다

2026-03-03은 월과 일을 뒤집어도 결과가 같다. 이런 입력만 사용하면 수정 전 함수도 통과한다. 아래의 틀린 검사는 실제로 실행되지만 오류를 구별할 능력이 없다.

from datetime import date

year, month, day = 2026, 3, 3
actual = date(year, day, month)
print(actual == date(2026, 3, 3))

고친 검사에서는 월과 일이 다른 날짜를 사용한다. 잘못된 호출을 그대로 둔 상태에서 False가 나오는 것을 먼저 확인한다. 그다음 호출 순서를 고쳐 True가 되는지 확인한다.

from datetime import date

year, month, day = 2026, 3, 8
actual = date(year, day, month)
print(actual == date(2026, 3, 8))
actual = date(year, month, day)
print(actual == date(2026, 3, 8))

예외가 나면 임의의 날짜로 바꾼다

틀린 코드는 입력 실패를 다른 정상 날짜로 바꾼다. 프로그램은 계속 실행되지만 사용자는 자신이 입력하지 않은 마감일을 받는다. 이런 처리는 원인을 해결하지 않고 관찰할 증거를 없앤다.

from datetime import date

text = "2026-02-30"
try:
    due = date.fromisoformat(text)
except ValueError:
    due = date(2026, 1, 1)
print(due.isoformat())

고친 코드는 입력을 거부했음을 분명히 출력한다. 사용자에게 다시 입력받는 도구라면 이 지점에서 입력을 요청할 수 있다. 이 예제에서는 한 번 실행하고 종료하므로 거부 결과만 표시한다.

from datetime import date

text = "2026-02-30"
try:
    due = date.fromisoformat(text)
except ValueError:
    print("마감일 입력 거부")
else:
    print(due.isoformat())

실제 결과에 맞춰 기대값을 바꾼다

테스트가 실패하자 AI가 기대값을 바꾸는 수정안을 제시할 수도 있다. 기대값이 잘못됐다는 근거가 있다면 수정해야 하지만, 통과시키기 위해 실제 결과를 복사하면 테스트가 문제를 숨긴다. 아래 코드는 뒤집힌 날짜를 스스로 정답으로 삼는다.

from datetime import date

actual = date(2026, 8, 3)
expected = actual
print(actual == expected)

고친 검사는 입력 규칙에서 정한 기대값을 사용한다. 아직 수정하지 않은 실제 결과와 비교하므로 False가 나온다. 실패를 유지하는 것이 이 단계에서는 올바른 동작이다.

from datetime import date

actual = date(2026, 8, 3)
expected = date(2026, 3, 8)
print(actual == expected)

AI의 변경안에 테스트 수정이 포함되면 특히 주의해서 읽는다. 요구사항이 바뀌었는지, 기존 기대값에 오류가 있었는지, 아니면 구현에 맞춰 기대값을 움직였는지 구별한다. 이유를 설명할 수 없는 기대값 변경은 받아들이기 어렵다.

한눈에 보기

디버깅 단계마다 남겨야 할 판단 근거
단계할 일남길 근거
재현입력과 실행 절차를 고정한다기대 결과와 실제 결과
가설관찰을 설명하는 원인을 하나 고른다가설이 맞을 때 예상할 값
확인관련 변수와 호출을 조사한다예상과 비교한 관찰값
수정원인에 맞는 범위로 변경한다변경 부분과 유지한 입력 규칙
재검사같은 테스트를 다시 실행한다수정 전 실패와 수정 후 통과
반복 중단새 관찰 없이 같은 수정이 나오면 멈춘다현재 코드에서 다시 얻은 재현 자료

AI는 가설을 제안하고 코드 변경을 도울 수 있다. 그 제안이 현재 문제에 맞는지는 입력, 실행, 테스트, 변경 검토로 확인한다. 다음에 같은 문제를 만나도 사용할 수 있는 설명과 재현 테스트가 남아야 디버깅 결과를 이어 갈 수 있다.

연습 문제

  1. 2026-03-08에서 잘못된 날짜가 반환되고 2026-03-14에서 예외가 발생하는 이유를, 수정 전 함수의 호출 순서와 연결해 세 문장 이내로 설명하라.
  2. CASES에 “2026-03-03”을 추가하면 수정 전후 모두 통과한다. 이 사례가 기존 두 정상 날짜 사례를 대신할 수 없는 이유를 설명하고, 버그를 드러내는 정상 날짜 하나를 추가하라.
  3. CASES에 “2026-02-29”를 추가해 입력이 거부되는지 검사하라. 이어서 “2028-02-29”를 추가해 정상 날짜로 처리되는지 검사하라. 수정 전후 통과 개수가 어떻게 달라질지 먼저 예상하라.
  4. AI가 월·일 순서를 바꿨다가 되돌리는 수정을 반복한다. 추가 수정을 요청하기 전에 보낼 메시지를 작성하라. 현재 재현 입력, 기대 결과, 실제 결과, 다음 확인 한 가지를 포함하라.

정답과 해설

  1. date는 연도·월·일 순서로 값을 받는데 수정 전 함수는 연도·일·월 순서로 전달한다. 일이 8이면 월 자리에 8이 들어가 8월 3일이라는 유효하지만 잘못된 날짜가 만들어진다. 일이 14이면 월 자리에 14가 들어가 ValueError가 발생한다.
  2. 월과 일이 모두 3이면 순서를 바꿔도 날짜가 같으므로 버그를 구별하지 못한다. 예를 들어 입력 “2026-04-09”와 기대값 date(2026, 4, 9)를 추가할 수 있다. 수정 전 함수는 9월 4일을 반환하므로 실패하고, 수정 후 함수는 4월 9일을 반환하므로 통과한다. 이 사례만 추가하면 수정 전은 2/5, 수정 후는 5/5 통과다.
  3. 2026년 2월에는 29일이 없으므로 기대값은 None이다. 2028년 2월 29일은 존재하므로 기대값은 date(2028, 2, 29)다. 수정 전 함수는 두 입력 모두 월 자리에 29를 전달해 거부한다. 따라서 첫 추가 사례는 통과하고 두 번째는 실패한다. 원래 네 사례에 이 두 사례를 추가하면 수정 전은 3/6, 수정 후는 6/6 통과다.
  4. 메시지는 수정 반복보다 관찰을 요구해야 한다. 아래 예시처럼 현재 코드와 현재 실행 결과를 기준으로 조사할 지점을 한 가지 지정할 수 있다.

월·일 순서를 바꾸고 되돌리는 수정이 반복되어 추가 변경을 잠시 멈춘다. 현재 코드를 기준으로 입력 “2026-03-14”를 다시 실행했다. 기대 결과는 “2026-03-14”지만 실제로는 ValueError가 발생했고, 오류 메시지는 “month must be in 1..12”다.

먼저 날짜 생성 호출에 전달되는 세 값과 그 순서를 확인하라. 관찰 결과를 설명한 뒤 다음 수정안을 제시하라. 기존 재현 테스트의 입력과 기대값은 유지하라.

연습의 핵심은 예상과 관찰을 따로 적는 데 있다. AI의 설명이 맞아 보일 때도 실행할 입력과 기대 결과가 있어야 확인할 수 있다. 고친 뒤에는 “잘 된다” 대신 어떤 실패가 사라졌고 어떤 입력 규칙이 유지됐는지 설명한다.

댓글 0

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

댓글을 남기려면 로그인이 필요합니다.