Devin.KR

취업·면접 · 실무

국비 과정 수료 후 개발자 취업 로드맵 - 6개월 실행 계획

팀 프로젝트 다듬기 2 - 테스트·README·배포 기록

핵심 기능 테스트 몇 개부터, README 에 들어갈 것(실행 방법·구조·내 기여·결정 근거), 배포 과정과 장애 기록, 완성 코드는 README 필수 항목 점검기

개발자KR · 원고 갱신

이 장에서 배우는 것

앞 장에서 내가 맡은 기능을 다시 짰다면, 이제 그 기능을 다른 사람이 확인할 수 있게 만들 차례다. 코드가 돌아간다는 사실만으로는 실행 조건, 바뀐 동작, 문제 발생 시 대응 방법까지 전달되지 않는다. 짧은 기간에 팀으로 서비스를 완성한 경험은 이미 중요한 자산이다. 여기에 테스트와 문서, 배포 기록을 보태면 일정 안에 어떤 판단을 했는지까지 설명할 수 있다.

이 장에서는 프로젝트 전체를 새로 만들지 않는다. 내가 수정한 핵심 기능 하나를 골라 정상 동작과 실패 조건을 확인하고, 처음 보는 사람이 실행할 수 있도록 README를 고친다. 배포에 성공한 순간뿐 아니라 실패를 발견하고 복구한 과정도 남긴다. 마지막에는 README의 필수 항목을 찾아 누락을 알려 주는 작은 Python 도구를 만든다.

  • 핵심 기능에서 먼저 확인할 정상·경계·거절 상황을 고른다.
  • README에 실행 방법, 구조, 내 기여, 결정 근거를 구체적으로 적는다.
  • 배포 전후 확인과 장애 대응을 재현 가능한 기록으로 남긴다.
  • 표준 라이브러리만 사용하는 README 필수 항목 점검기를 완성한다.

문제 상황

팀으로 만든 예약 서비스에서 중복 예약을 막는 기능을 수정했다고 하자. 내 컴퓨터에서는 정상적으로 동작한다. 그런데 팀원이 저장소를 내려받아 실행하자 필수 환경 변수가 없어 서버가 시작되지 않는다. README에는 “설정 후 실행”이라는 문장만 있다. 어떤 설정이 필요한지, 예제 값은 어디서 구하는지, 데이터베이스를 먼저 준비해야 하는지 알 수 없다.

설정을 맞춘 뒤에는 다른 문제가 드러난다. 이미 예약된 시간을 요청했을 때 오류 응답이 나오지만, 예약 데이터도 하나 늘어난다. 화면에 오류가 표시된 것만 보고 실패 처리가 끝났다고 판단한 탓이다. 수정 이후 배포한 버전도 분명하지 않다. 로컬에서 확인한 코드와 서버에서 실행 중인 코드가 같은지 설명하기 어렵다.

이 상황에서 필요한 것은 문서의 분량이 아니다. 실행 조건, 기대한 결과, 실제 확인 결과를 연결하는 일이다. “중복 예약 방지 구현”이라는 한 줄을 “중복 요청을 거절하며 저장 건수가 늘지 않는 테스트를 추가했고, 해당 변경을 포함한 버전을 배포한 뒤 같은 조건을 확인했다”로 바꿀 수 있어야 한다. 그 문장을 뒷받침하는 자료가 이번 작업의 결과물이다.

핵심 기능 테스트는 위험한 약속부터 고른다

테스트(test)는 특정 조건에서 프로그램이 지켜야 하는 약속을 자동으로 확인하는 코드다. 모든 파일에 같은 수의 테스트를 붙이는 방식으로 시작할 필요는 없다. 내가 수정한 기능에서 잘못되면 사용자의 데이터나 다음 동작에 영향을 주는 약속을 먼저 찾는다. 예약 기능이라면 “가능한 시간에는 한 건만 저장한다”, “이미 예약된 시간에는 추가 저장하지 않는다”가 출발점이다.

테스트를 쓰기 전에 입력, 실행 전 상태, 기대 결과를 한 문장씩 적는다. “중복 예약 테스트”라는 이름만 붙이면 무엇을 확인할지 흐려진다. “예약 한 건이 있는 시간에 같은 요청을 보내면 충돌을 나타내는 응답을 반환하고 저장 건수는 한 건을 유지한다”처럼 관찰할 결과를 정한다. 응답과 저장 상태를 함께 보는 이유도 여기에 있다.

예약 기능에서 먼저 남길 세 가지 테스트
상황준비 상태기대 결과확인 증거
정상 요청해당 시간 예약 없음예약 한 건 생성응답과 저장 내용
경계 입력종료 시각과 시작 시각이 같음입력 거절, 저장 없음오류 종류와 저장 건수
중복 요청같은 시간 예약 한 건 존재추가 생성 거절거절 응답과 기존 데이터 유지

이 표의 상황은 서로 다른 실패를 찾는다. 정상 요청은 기능의 기본 경로를 확인한다. 경계 입력은 허용 범위의 기준을 확인한다. 중복 요청은 기존 상태가 있을 때의 약속을 확인한다. 이 세 가지를 통과했다고 동시에 들어오는 모든 요청까지 안전하다고 말할 수는 없다. 동시 요청을 다루는 검증은 별도로 필요하다. 확인한 범위를 정확하게 쓰는 것도 테스트 작업의 일부다.

테스트마다 필요한 데이터를 스스로 준비하고 실행 뒤 정리한다. 다른 테스트가 먼저 예약을 만들어 주기를 기대하면 실행 순서에 따라 결과가 달라진다. 현재 시각이나 임의의 입력에 의존하는 경우도 피한다. 날짜가 필요하면 고정된 값을 쓰고, 외부 시스템이 필요한 검증은 실행 조건을 별도로 문서화한다. 프로젝트의 기존 Java나 JavaScript 테스트 도구를 사용하면 되며, Python으로 서비스를 다시 작성할 필요는 없다.

핵심 기능의 약속을 정상·경계·거절 상황으로 나누고 각각 관찰 가능한 결과를 확인한다

실패한 테스트는 수정의 출발점이 된다. 먼저 고치려는 조건에서 테스트가 실패하는지 확인하고, 코드를 수정한 뒤 같은 테스트를 다시 실행한다. 처음부터 통과하는 테스트만 추가했다면 새로 만든 검증이 실제 문제를 잡는지 한 번 더 살펴본다. 테스트를 통과시키기 위해 기대 결과를 느슨하게 바꾸었다면 기능의 약속도 바뀐 것인지 설명해야 한다.

서재의 《클린 코드 노하우》는 준비·실행·검증의 역할이 드러나도록 테스트 이름과 구성을 다듬을 때 연결한다. 《코드 리뷰 실무》는 변경한 동작과 추가한 검증을 함께 보여 주는 검토 요청에 활용한다. 자료를 읽은 시간보다 프로젝트에 반영한 테스트와 그 이유를 남기는 편이 이번 주의 목적에 맞는다.

README는 실행하는 사람의 순서로 쓴다

README는 저장소를 처음 여는 사람이 프로젝트를 이해하고 실행하는 안내문이다. 소개 이미지가 있어도 실행 순서를 알 수 없으면 확인이 멈춘다. 이 장에서는 필수 항목을 실행 방법, 구조, 내 기여, 결정 근거의 네 가지로 정한다. 실제 저장소에 이미 정해진 문서 형식이 있다면 그 형식에 맞춰 같은 내용을 담으면 된다.

실행 방법에는 필요한 실행 환경의 버전, 설정 파일 준비, 데이터베이스 준비, 실행 명령, 정상 시작을 확인하는 방법을 순서대로 적는다. 테스트 실행 명령과 테스트용 데이터 준비도 덧붙인다. 명령을 어느 디렉터리에서 실행하는지 밝히고, 개인 컴퓨터의 절대 경로는 제거한다. 비밀 값은 기록하지 않고 변수 이름과 안전한 예제 값을 안내한다.

구조에는 폴더 목록을 길게 복사하기보다 요청이 어디로 들어와 어떤 역할을 거쳐 저장되는지 적는다. 예를 들어 예약 요청을 받는 부분, 예약 가능 여부를 판단하는 부분, 데이터를 저장하는 부분을 연결한다. 내가 수정한 파일이 이 흐름에서 무엇을 맡는지 보이면 충분하다. 저장소의 실제 이름과 문서의 이름도 일치시킨다.

내 기여에는 팀 전체 결과와 내가 수행한 작업을 구분해 적는다. “예약 서비스 개발”보다 “예약 시간 검증을 수정하고 경계 입력 테스트를 추가했다”가 확인하기 쉽다. 함께 작업했다면 역할을 나눠 적는다. 예를 들어 규칙은 팀원이 제안했고, 나는 구현과 테스트를 맡았다고 쓰면 된다. 협업의 사실을 지우지 않아도 개인의 기여는 드러난다.

결정 근거에는 문제, 비교한 방법, 선택 이유, 남은 제약을 담는다. “유지보수를 위해 분리했다”만으로는 어느 문제가 줄었는지 알기 어렵다. 같은 검증이 두 경로에서 달라졌고, 공통 규칙으로 모아 변경 지점을 줄였다고 쓰면 선택의 이유가 보인다. 추가 검증이 필요한 상황이 있다면 함께 적는다.

이 네 항목은 제목의 유무와 내용의 품질을 나누어 확인해야 한다. 아래 점검기는 제목과 최소한의 본문만 검사한다. 잘못된 실행 명령이나 과장된 기여까지 판단하지 못한다. 도구의 통과 결과를 받은 다음에는 다른 사람이 안내 순서대로 실행하고, 적힌 구조와 결정 근거를 실제 코드와 대조해야 한다.

서재의 《개발자를 위한 컴퓨터 사이언스》와 《비전공자를 위한 컴퓨터공학 지도》는 구조를 설명하다 요청 처리나 프로세스 개념이 막힐 때 필요한 주제만 확인하는 데 쓴다. 《데이터베이스 개론》과 SQL 연구소는 저장 결과나 트랜잭션 경계를 검증할 근거를 보충할 때 연결한다. 《논리로 푸는 알고리즘》과 코드패스에서 다룬 경계 입력은 프로젝트의 입력 조건을 고르는 연습에 연결할 수 있다. 《개발자 실무 면접》은 기록한 결정 근거가 질문을 받아도 설명 가능한지 점검할 때 활용한다. 각 자료의 예제를 옮기지 않고 자신의 기능과 데이터로 확인한다.

배포와 장애는 변경 전후를 이어서 기록한다

배포(deployment)는 확인한 변경을 실행 환경에 반영하는 작업이다. 배포 기록에는 시도한 시각, 대상 환경, 코드의 커밋 식별자, 설정 변경 여부, 수행 순서, 배포 후 확인 결과를 남긴다. 로컬 테스트를 통과한 사실과 배포 환경에서 기능을 확인한 사실은 구분해서 쓴다. 두 환경은 설정이나 데이터가 다를 수 있기 때문이다.

배포 전에는 되돌아갈 버전과 복구 절차를 확인한다. 롤백(rollback)은 이전에 확인한 상태로 되돌리는 작업이지만 코드만 되돌리면 항상 해결되는 것은 아니다. 데이터 구조를 바꿨다면 이전 코드가 바뀐 구조를 읽을 수 있는지도 확인해야 한다. 이 장의 작업에서는 내가 실제로 검증한 복구 범위와 아직 확인하지 못한 부분을 기록한다.

배포 뒤에는 서버가 시작됐다는 메시지에 그치지 않고 수정한 기능을 확인한다. 예약 생성, 잘못된 입력 거절, 중복 요청 거절처럼 앞에서 정한 약속을 기준으로 삼는다. 확인에 사용하는 계정과 데이터가 다른 사람의 작업에 영향을 주지 않도록 범위를 정한다. 결과 화면만 저장하기보다 대상 버전과 확인 조건을 함께 적는다.

배포 기록은 대상 버전과 사전 확인에서 시작해 반영 후 확인 또는 복구 결과까지 연결한다

장애 기록에는 관찰한 현상, 영향 범위, 원인 가설, 확인 근거, 조치, 재확인 결과, 후속 작업을 남긴다. “설정 문제로 실패했다”는 문장만으로는 다시 대응하기 어렵다. 필수 환경 변수 누락으로 시작이 중단됐고, 오류 메시지와 실행 설정을 대조했으며, 변수를 추가한 뒤 시작과 예약 기능을 재확인했다고 적는다. 추측 중인 원인은 확정한 사실과 구분한다.

장애가 없었다면 일부러 실제 서비스에 장애를 만들 필요는 없다. 로컬에서 필수 설정을 뺀 실행을 시도하는 등 영향이 제한된 복구 연습을 하고, 기록에 “로컬 복구 연습”이라고 표시한다. 로그를 남길 때는 비밀 값과 개인 정보를 제거한다. 성공 횟수를 늘리는 것보다 실패를 알아차린 근거와 복구 뒤 확인한 결과가 중요하다.

이번 주에 할 일과 완료 증거
완료 확인할 일완료 증거확인 기준
□핵심 기능 테스트 세 개 추가테스트 코드와 실행 결과정상·경계·거절 조건 명시
□README 필수 항목 보완문서 변경 내역다른 사람이 순서대로 실행
□배포 또는 로컬 배포 연습버전과 확인 결과가 있는 기록반영 전후 조건 추적 가능
□장애 대응 또는 복구 연습 기록현상·근거·조치·재확인 기록관찰과 추측을 구분

이번 주의 완료 증거는 테스트 결과 하나로 끝나지 않는다. 테스트가 포함된 변경, 실행을 확인한 README, 대상 버전을 적은 배포 기록, 복구 과정을 적은 기록을 한곳에서 찾을 수 있어야 한다. 기록의 위치를 README에 연결하면 다음에 수정할 때도 같은 출발점을 사용할 수 있다.

완성 코드

다음 코드를 main.py로 저장한다. 외부 파일을 읽지 않고 코드 안의 예제 README를 검사하므로 macOS와 Linux에서 같은 결과가 나온다. Python 3.12 이상과 표준 라이브러리만 사용하며 네트워크에 접속하지 않는다. 실제 문서를 점검하려면 README_TEXT의 문자열을 자신의 내용으로 교체한다.

이 도구의 문서 규칙은 의도적으로 좁다. 필수 항목은 정확히 같은 이름의 두 번째 수준 제목으로 작성한다. 제목 뒤에는 공백 한 칸을 둔다. 본문 중 빈 줄과 TODO, 작성 예정만 있는 줄은 내용으로 세지 않는다. 백틱 세 개만 단독으로 놓인 줄은 코드 블록의 시작과 끝으로 취급한다. 코드 블록 속 제목은 필수 항목으로 인식하지 않지만, 이미 열린 항목 안의 코드 내용은 본문으로 인정한다.

REQUIRED = ("실행 방법", "구조", "내 기여", "결정 근거")
PLACEHOLDERS = {"TODO", "작성 예정"}

README_TEXT = """# 예약 서비스

## 실행 방법
Python 3.12 이상에서 python3 main.py를 실행한다.

## 구조
main.py가 문서 분리와 필수 항목 점검을 수행한다.

## 내 기여
필수 제목을 찾고 누락을 출력하는 함수를 작성했다.

## 결정 근거
TODO
"""


def has_content(lines: list[str]) -> bool:
    return any(
        line.strip() and line.strip() not in PLACEHOLDERS
        for line in lines
    )


def collect_sections(text: str) -> dict[str, list[str]]:
    sections: dict[str, list[str]] = {}
    current: str | None = None
    in_code = False

    for raw_line in text.splitlines():
        line = raw_line.strip()

        if line == "```":
            in_code = not in_code
            continue

        if in_code:
            if current is not None:
                sections[current].append(raw_line)
            continue

        if line.startswith("# "):
            current = None
        elif line.startswith("## "):
            title = line[3:].strip()
            current = title
            sections.setdefault(title, [])
        elif line.startswith("#"):
            continue
        elif current is not None:
            sections[current].append(raw_line)

    return sections


def inspect_readme(text: str) -> list[tuple[str, str]]:
    sections = collect_sections(text)
    results: list[tuple[str, str]] = []

    for title in REQUIRED:
        if title not in sections:
            status = "제목 없음"
        elif not has_content(sections[title]):
            status = "내용 보완"
        else:
            status = "확인"
        results.append((title, status))

    return results


def run_checks() -> None:
    assert inspect_readme("")[0] == ("실행 방법", "제목 없음")
    assert inspect_readme("## 실행 방법\nTODO")[0][1] == "내용 보완"
    assert inspect_readme("## 실행 방법\n실행 명령")[0][1] == "확인"

    example = "```\n## 실행 방법\n예시\n```"
    assert inspect_readme(example)[0][1] == "제목 없음"

    nested = "## 실행 방법\n### 준비\n작성 예정"
    assert inspect_readme(nested)[0][1] == "내용 보완"

    command = "## 실행 방법\n```\npython3 main.py\n```"
    assert inspect_readme(command)[0][1] == "확인"


def main() -> None:
    run_checks()
    results = inspect_readme(README_TEXT)

    print("README 필수 항목 점검")
    for title, status in results:
        print(f"{title}: {status}")

    passed = sum(status == "확인" for _, status in results)
    print(f"확인: {passed}/{len(REQUIRED)}")
    print("주의: 제목과 본문 유무만 검사하며 정확성은 직접 검토한다.")


if __name__ == "__main__":
    main()

줄별 해설

REQUIRED는 검사할 제목과 출력 순서를 튜플로 고정한다. 문서에서 항목이 등장하는 순서와 관계없이 결과는 이 순서로 출력된다. PLACEHOLDERS는 작성이 끝났다고 보지 않을 문자열의 집합이다. 대소문자나 표현을 자동으로 바꾸지 않으므로 todo까지 제외하려면 규칙을 추가해야 한다.

README_TEXT는 검사 대상이다. 예제의 결정 근거에는 의도적으로 TODO만 넣었다. 프로그램이 정상 실행되더라도 문서 점검에서는 보완할 항목이 나올 수 있다는 점을 보여 준다. 여기서 “확인”은 내용의 타당성까지 보증하는 표현이 아니라 최소한의 본문이 발견됐다는 상태다.

has_content()의 lines는 한 항목에 속한 본문 줄 목록이다. strip()은 앞뒤 공백을 제거한다. 공백을 제거한 문자열이 비어 있지 않고 작성 예정 표시도 아니라면 해당 줄을 내용으로 인정한다. any()는 조건을 만족하는 줄이 하나라도 있는지 반환한다. 빈 목록을 받으면 거짓을 반환한다.

collect_sections()의 sections는 제목을 키로, 본문 줄 목록을 값으로 보관한다. current는 지금 읽고 있는 항목이다. 처음에는 어떤 항목도 열리지 않았으므로 None으로 둔다. in_code는 현재 코드 블록 안에 있는지 나타낸다. 이 두 상태를 나누면 예제 코드에 나온 제목을 실제 제목과 구분할 수 있다.

splitlines()로 문서를 한 줄씩 읽고, 비교할 때 사용할 line을 만든다. 백틱 세 개만 있는 줄을 만나면 not으로 코드 블록 상태를 뒤집는다. 구분선 자체는 본문에 넣지 않는다. 코드 블록 안에서는 제목을 해석하지 않으며, 열린 항목이 있을 때만 원래 줄을 본문에 추가한다.

# 로 시작하는 줄은 최상위 제목이므로 현재 항목을 닫는다. ## 로 시작하면 앞의 세 글자를 제외한 부분을 제목으로 삼는다. setdefault(title, [])는 처음 만난 제목에 빈 목록을 준비한다. 같은 제목을 다시 만나면 기존 목록을 유지해 두 구간의 본문이 합쳐진다. 중복 제목을 오류로 판단하는 기능은 포함하지 않았다.

그 밖에 #으로 시작하는 줄은 하위 제목 등을 본문 내용으로 세지 않고 건너뛴다. 따라서 하위 제목만 있는 항목은 통과하지 않는다. 일반 줄은 current is not None일 때만 저장한다. 소개 문단에 “실행 방법”이라는 말이 있어도 필수 항목으로 처리하지 않는 이유다.

inspect_readme()는 필수 제목마다 제목 없음, 내용 보완, 확인 중 하나를 고른다. 제목이 없는 경우를 먼저 확인한 뒤 본문을 조회하므로 존재하지 않는 키에 접근하지 않는다. 결과를 튜플 목록으로 반환해 검사와 화면 출력을 분리했다. 같은 검사 결과를 나중에 다른 형식으로 표현하기도 쉽다.

run_checks()에는 여섯 가지 검증이 있다. 제목 누락, 작성 예정 표시, 정상 본문, 코드 블록 속 가짜 제목, 내용 없는 하위 제목, 실행 명령만 있는 본문을 확인한다. assert는 기대와 실제가 다르면 실행을 멈춘다. 여기서는 개발 중 회귀를 확인하는 용도로 사용한다. 최적화 옵션을 주면 생략될 수 있으므로 실제 문서의 판정은 이 검증문에 맡기지 않고 inspect_readme()가 수행한다.

main()은 내부 검증을 마친 뒤 문서를 검사하고 결과를 출력한다. sum()은 “확인”인 상태의 개수를 센다. 날짜, 임의 값, 파일 목록에 의존하지 않으므로 입력 문자열이 같으면 출력도 같다. 마지막 조건문은 이 파일을 직접 실행했을 때만 main()을 호출한다.

실행 결과

main.py가 있는 디렉터리에서 다음 명령으로 문법과 컴파일 경고를 확인한다. 경고가 발생하면 오류로 취급하도록 설정했다. 명령이 성공하면 출력 없이 끝나며 컴파일 캐시가 생성될 수 있다.

python3 -W error -m py_compile main.py

프로그램 실행 명령은 다음과 같다. 별도 입력을 기다리지 않고 결과를 출력한 뒤 종료한다.

python3 main.py

예상 출력은 다음과 같다.

README 필수 항목 점검
실행 방법: 확인
구조: 확인
내 기여: 확인
결정 근거: 내용 보완
확인: 3/4
주의: 제목과 본문 유무만 검사하며 정확성은 직접 검토한다.

결정 근거의 TODO를 실제 선택 이유로 바꾸면 해당 항목도 확인으로 바뀐다. 하지만 의미 없는 한 문장으로 교체해도 통과할 수 있다. 따라서 이 프로그램은 문서 작성의 누락을 줄이는 보조 도구로 사용한다. 본문에 적힌 명령을 그대로 실행하고, 기여와 근거를 코드에 대조하는 검토는 별도로 남는다.

실무에서 자주 틀리는 것

문서 어디에든 단어가 있으면 통과시킨다

문자열 포함 여부만 검사하면 “실행 방법은 아직 쓰지 않았다”라는 소개 문장도 통과한다. 구조를 가진 문서는 구조를 분리한 결과로 검사해야 한다.

틀린 코드다.

ok = "실행 방법" in text

고친 코드다. 제목이 실제로 존재하고 본문도 있는지 확인한다.

sections = collect_sections(text)
ok = (
    "실행 방법" in sections
    and has_content(sections["실행 방법"])
)

빈 줄이나 작성 예정 표시를 내용으로 센다

목록의 길이가 양수라고 해서 문서가 작성된 것은 아니다. 빈 줄 한 개도 목록의 원소가 된다. 작성 예정 표시를 본문으로 인정하는 경우에도 같은 문제가 생긴다.

틀린 코드다.

lines = ["", "   ", "TODO"]
ok = len(lines) > 0

고친 코드다. 줄 수 대신 실제 내용이 있는지 검사한다.

lines = ["", "   ", "TODO"]
ok = has_content(lines)

문서 순서에 따라 결과 순서가 바뀐다

문서에서 찾은 제목을 그대로 출력하면 작성자가 항목 순서를 바꿀 때마다 점검 결과 순서도 달라진다. 필수 항목을 빠뜨린 경우에는 그 항목 자체가 출력되지 않을 수도 있다.

틀린 코드다.

for title in collect_sections(text):
    print(title)

고친 코드다. 검사 대상 목록을 기준으로 순회하면 빠진 항목도 같은 위치에서 확인할 수 있다.

sections = collect_sections(text)
for title in REQUIRED:
    print(title, title in sections)

테스트가 끝났다는 메시지를 검증으로 여긴다

함수를 호출하고 메시지만 출력하면 결과가 틀려도 실행이 성공한다. 기대하는 상태를 비교하는 코드가 필요하다. 실제 예약 기능에서도 응답만 보고 저장 상태를 확인하지 않으면 약속의 일부를 놓친다.

틀린 코드다.

inspect_readme("## 실행 방법\nTODO")
print("검사 완료")

고친 코드다. 어떤 입력에서 어떤 상태가 나와야 하는지 명시한다.

result = inspect_readme("## 실행 방법\nTODO")
assert result[0] == ("실행 방법", "내용 보완")

한눈에 보기

프로젝트를 확인 가능한 상태로 만드는 기록
대상핵심 질문남길 자료완료 판단
테스트어떤 약속을 지키는가조건·기대 결과·테스트 코드정상과 실패 조건을 재확인
README다른 사람이 실행할 수 있는가실행·구조·기여·근거안내 순서대로 실행 확인
배포어떤 버전을 반영했는가대상 버전·절차·확인 결과수정 기능의 동작 확인
장애 대응무엇을 보고 어떻게 복구했는가현상·근거·조치·재확인복구 결과와 후속 작업 명시

다음 장에서는 이 자료를 바탕으로 포트폴리오와 이력서에 결과, 결정, 기여를 표현한다. 지금은 문장을 꾸미기보다 실제로 확인한 사실과 확인 범위를 남긴다. 무엇을 했는지 기억에 의존하지 않아도 설명할 수 있는 상태가 이번 작업의 도착점이다.

연습 문제

  1. 예제 README의 결정 근거에 문제, 선택한 방법, 남은 제약을 담은 본문을 작성한다. 수정 뒤 달라지는 출력 두 줄을 적는다.
  2. 필수 항목에 “배포 기록”을 추가한다. 예제 README는 그대로 두었을 때 새 항목과 합계가 어떻게 출력되는지 설명한다.
  3. 코드 블록 안의 제목을 무시하는 동작을 검증하되, 블록 밖에 실제 실행 방법 항목도 있는 입력을 만든다. 기대 결과를 검증문으로 작성한다.
  4. 자신의 프로젝트에서 실패 조건 하나를 고른다. 준비 상태, 입력, 기대 응답, 저장 상태를 적고, 배포 뒤 같은 조건을 확인했다는 기록에 필요한 항목을 정한다.

정답과 해설

  1. 예를 들어 “필수 항목을 빠뜨리는 문제가 있어 제목 목록을 고정했다. 외부 파일 없이 바로 실행할 수 있도록 예제 문서를 코드에 넣었다. 문장 내용의 정확성은 사람이 검토해야 한다”라고 쓸 수 있다. 이 설명은 이 장의 점검기에 대한 근거다. 실제 프로젝트 문서에는 해당 프로젝트의 결정을 적는다. 달라지는 출력은 다음과 같다.

    결정 근거: 확인
    확인: 4/4

    본문이 추가되어 최소 내용 검사를 통과한다. 이 결과가 설명의 충분함까지 자동으로 보장하지는 않는다.

  2. 필수 항목 튜플 끝에 새 제목을 추가한다.

    REQUIRED = ("실행 방법", "구조", "내 기여", "결정 근거", "배포 기록")

    새 항목은 문서에 없으므로 다음 줄이 추가된다. 기존 결정 근거도 여전히 내용 보완이므로 합계는 다음과 같다.

    배포 기록: 제목 없음
    확인: 3/5

    출력 순서와 합계가 같은 필수 항목 목록을 사용하므로 다른 출력 코드는 수정하지 않아도 된다.

  3. 코드 블록의 가짜 제목에는 작성 예정 표시를 두고, 블록 밖 실제 제목에는 본문을 둔다.

    text = (
        "```\n## 실행 방법\nTODO\n```\n"
        "## 실행 방법\npython3 main.py를 실행한다."
    )
    assert inspect_readme(text)[0] == ("실행 방법", "확인")
    assert collect_sections(text)["실행 방법"] == [
        "python3 main.py를 실행한다."
    ]

    첫 번째 검증은 최종 상태를 확인한다. 두 번째 검증은 블록 안의 내용이 실제 항목에 섞이지 않았는지 확인한다. 같은 확인 상태가 나와도 수집 과정이 잘못됐을 가능성을 구분한다.

  4. 예약 서비스라면 같은 시간에 예약 한 건이 있는 상태를 준비하고, 같은 시간의 추가 예약을 요청할 수 있다. 기대 결과는 중복을 나타내는 응답과 저장 건수 한 건 유지다. 실제 오류 응답의 형식은 프로젝트가 정한 규칙에 맞춘다.

    배포 뒤 확인 기록에는 대상 환경, 커밋 식별자, 확인 시각, 준비한 데이터, 보낸 요청의 조건, 실제 응답, 저장 상태를 적는다. 실행하지 않은 검증은 실행했다고 쓰지 않는다. 요청을 순서대로 보냈다면 동시 요청 검증까지 마쳤다고 해석하지 않도록 확인 범위를 덧붙인다.

오탈자·오류 제보 비공개로 접수되어 원고 수정에 반영됩니다

이메일 등 개인정보는 받지 않습니다. 답변이 필요한 질문은 아래 댓글을 이용해 주세요.

READER FEEDBACK

질문·의견

내용에 관한 질문이나 더 나은 설명을 위한 의견을 남겨 주세요. 오탈자는 위의 제보 양식이 더 빨리 반영됩니다. 이 댓글은 원래 게시글과 같은 자리에 쌓입니다.

댓글 0

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

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