프로그래밍웹 교과서
이 페이지의 목차
3단원 · 6차시

나눠 만든 것을 합치다

통합인터페이스디버깅버전 관리

코드 예제: Python · C · 예상 50분

학습 목표

  • 함수 단위로 구현한 코드를 하나의 프로그램으로 통합한다.
  • 통합 과정에서 생긴 오류를 찾아 고친다.

관련 성취기준

  • 프그03-03

    작성된 설계 프로그램을 프로그래밍 언어를 사용하여 구현할 수 있다.

생각 열기 — 각자는 되는데 합치니 안 된다

모둠에서 부품을 나눠 만들었다. 각자 실행해 보니 다 잘 됐다. 그런데 합쳐 놓으니 이런 일이 생겼다.

  • A가 만든 입력 부품은 점수를 문자열로 넘겼는데, B의 통계 부품은 정수를 기다렸다.
  • B는 결과를 (인원, 평균, 최고, 최저) 순으로 돌려줬는데, C의 출력 부품은 (평균, 인원, …) 순으로 받았다.
  • 셋 다 is_valid 를 각자 만들어 넣어 두었고, 그중 하나는 0 < 점수 로 적혀 있었다.

어긋나는 곳은 늘 부품 사이다

각 부품이 따로 옳은데 합치면 틀리는 문제는 1단원 5차시에서 다룬 통합 단계의 잘못이다. 어긋나는 자리는 정해져 있다.

합칠 때 어긋나는 네 자리
어긋나는 것증상설계에서 막는 법
자료형문자열을 넘겼는데 숫자를 기다린다「받는 것」 칸에 자료형을 적는다
값의 순서·이름(인원, 평균)으로 주고 (평균, 인원)으로 받는다묶음으로 넘기고 이름으로 꺼낸다 (3차시)
뜻점수를 100점 만점으로 주고 100분율로 받는다「하는 일」 칸에 단위와 뜻을 적는다
같은 일의 사본is_valid를 각자 만들어 조건이 서로 다르다두 곳 이상에서 쓰이면 따로 떼어 한 사람이 만든다

네 번째가 가장 찾기 어렵다. 프로그램이 멈추지도 않고 오류도 없이 답만 조용히 틀리기 때문이다. 1단원 5차시에서 논리 오류가 가장 찾기 어렵다고 한 것이 이 경우다.

한꺼번에 붙이지 않는다

합치는 방법에도 순서가 있다. 다 만들어 한 번에 붙이면 어긋난 곳이 여럿 겹쳐 원인을 가릴 수 없다.

  • 순서 1

    하나씩 붙인다

    껍데기 상태의 프로그램에 진짜 부품을 하나만 끼운다. 실행해 보고 다음 것을 끼운다.

  • 순서 2

    붙일 때마다 실행한다

    방금 끼운 부품이 유일한 변화이므로, 문제가 생기면 범인이 그것이다.

  • 순서 3

    안쪽부터 바깥으로

    남을 부르지 않는 부품부터 끼운다. 확인이 끝난 것 위에 쌓아 올린다.

  • 순서 4

    되던 것을 다시 본다

    새 부품을 끼운 뒤 앞서 되던 기능도 다시 확인한다 — 회귀 테스트.

합쳐진 프로그램

3차시 설계의 부품들을 실제로 이어 붙이면 이렇게 된다. summarize 가 is_valid 를 부르고, report 가 summarize 의 결과를 받는다.

Python부품을 이어 붙인 프로그램
def is_valid(score):
    return 0 <= score <= 100

def summarize(scores):
    valid = [s for s in scores if is_valid(s)]
    if not valid:
        return None
    return {
        "count": len(valid),
        "dropped": len(scores) - len(valid),
        "avg": sum(valid) / len(valid),
        "high": max(valid),
        "low": min(valid),
    }

def report(result):
    if result is None:
        print("쓸 수 있는 점수가 없다")
        return
    print(f"인원 {result['count']}명 (제외 {result['dropped']}건)")
    print(f"평균 {result['avg']:.1f}  최고 {result['high']}  최저 {result['low']}")

report(summarize([88, 92, 75, 100, 64, -5, 120]))
report(summarize([-1, 200]))
확인된 실행 결과
인원 5명 (제외 2건)
평균 83.8  최고 100  최저 64
쓸 수 있는 점수가 없다
C부품을 이어 붙인 프로그램확인된 출력
#include <stdio.h>

typedef struct {
    int count;
    int dropped;
    double avg;
    int high;
    int low;
} Summary;

int is_valid(int score)
{
    return score >= 0 && score <= 100;
}

/* 쓸 수 있는 점수가 하나도 없으면 0을 돌려준다 */
int summarize(const int scores[], int n, Summary *out)
{
    int sum = 0;
    out->count = 0;
    out->dropped = 0;

    for (int i = 0; i < n; i++) {
        if (!is_valid(scores[i])) {
            out->dropped++;
            continue;
        }
        /* 첫 번째 쓸 수 있는 점수를 최고·최저의 기준으로 삼는다 */
        if (out->count == 0 || scores[i] > out->high) out->high = scores[i];
        if (out->count == 0 || scores[i] < out->low) out->low = scores[i];
        sum += scores[i];
        out->count++;
    }
    if (out->count == 0) return 0;
    out->avg = (double)sum / out->count;
    return 1;
}

void report(const int scores[], int n)
{
    Summary s;
    if (!summarize(scores, n, &s)) {
        printf("쓸 수 있는 점수가 없다\n");
        return;
    }
    printf("인원 %d명 (제외 %d건)\n", s.count, s.dropped);
    printf("평균 %.1f  최고 %d  최저 %d\n", s.avg, s.high, s.low);
}

int main(void)
{
    int a[] = {88, 92, 75, 100, 64, -5, 120};
    int b[] = {-1, 200};
    report(a, 7);
    report(b, 2);
    return 0;
}
실행 결과
인원 5명 (제외 2건)
평균 83.8  최고 100  최저 64
쓸 수 있는 점수가 없다

두 프로그램의 출력이 글자 단위로 같다. 3차시 설계서에 출력 형식을 띄어쓰기까지 적어 둔 덕분이다. 형식을 정해 두지 않았다면 여기서 두 언어의 결과가 달라졌을 것이다.

두 언어가 갈린 곳

같은 설계가 언어에 따라 달라진 부분
설계에서 정한 것PythonC
결과 묶음사전(dict) — 이름으로 꺼낸다구조체(struct Summary) — 미리 항목을 선언한다
"없음" 돌려주기None 을 돌려준다성공 여부를 int 로 돌려주고 결과는 out 에 채운다
최고·최저 찾기max()·min() 이 대신 해 준다반복하면서 직접 비교한다. 첫 값 처리를 손으로 적어야 한다
제외 건수전체 개수에서 남은 개수를 뺀다거를 때마다 dropped 를 센다

합칠 때는 버전 관리가 필요하다

1단원 9차시에서 다룬 문제가 지금 실제로 생긴다. 세 사람이 각자 고친 파일을 하나로 만들어야 한다.

  • 합치기 전에 최신 내용을 받아 온다. 낡은 것 위에 고치면 충돌이 늘어난다.
  • 한 사람이 한 부품만 고친다. 같은 함수를 둘이 고치면 같은 줄에서 충돌한다.
  • 한 번에 한 가지씩 올린다. “is_valid 구현” 과 “출력 형식 수정” 을 한 묶음으로 올리면 되돌릴 때 필요한 것까지 사라진다.
  • 충돌은 고장이 아니다. 두 수정을 나란히 읽고 어느 쪽을 남길지 사람이 정한다.

버전 관리 도구를 쓰지 않는다면 합치는 담당자를 한 명 정하고 나머지는 그 사람에게 부품 파일만 넘긴다. 여럿이 동시에 같은 파일을 고치는 상황만 피해도 대부분의 문제가 사라진다.

어긋난 곳을 좁히는 법

합쳤는데 결과가 틀렸다면 순서대로 좁힌다.

  1. 어느 입력에서 틀리는가 — 4차시 책상 검사의 세 입력을 모두 넣어 본다. 전부 틀리는지, 특정 입력에서만 틀리는지 가른다.
  2. 어느 부품에서 틀어지는가 — 부품 하나만 따로 불러 손으로 낸 값과 대조한다.
  3. 부품 안 어디서 틀어지는가 — 값을 중간에 찍어 보거나 디버거의 중단점을 건다(1단원 8차시).
  4. 고친 뒤 앞의 것을 다시 본다 — 되던 기능이 깨지지 않았는지 확인한다.

활동

프로젝트

모둠원 코드 합치고 동작 확인

약 45분

1단계 — 합치기 전에 정한다 (5분)

정할 것 우리 모둠
합치는 담당자
합치는 순서 (어느 부품부터)
합친 파일을 두는 곳

2단계 — 하나씩 끼운다 (20분)

껍데기 프로그램에 부품을 하나씩 끼우고, 끼울 때마다 실행한다.

차례 끼운 부품 실행됐는가 문제가 있었다면 무엇
1
2

문제가 생기면 방금 끼운 부품을 껍데기로 되돌려 실행해 본다. 문제가 사라지면 그 부품이 원인이다.

3단계 — 어긋난 곳을 기록한다 (10분)

합치면서 발견한 어긋남을 표로 남긴다. 이 표가 다음 프로젝트에서 설계할 때 쓸 자료가 된다.

어긋난 것 어느 부품 사이 어떻게 고쳤나 설계에서 어떻게 막을 수 있었나

4단계 — 전체 확인 (10분)

4차시 책상 검사에서 정한 세 입력을 모두 넣어 본다.

입력 기대 결과 (손으로 낸 값) 실제 결과 같은가
평범한 경우
값이 하나뿐인 경우
전부 걸러지는 경우

끼워 넣었던 확인용 출력문을 전부 지웠는지 확인하고 마친다. 다음 차시에서 이 프로그램을 본격적으로 테스트한다.

개념 확인 문제

보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.

각 부품은 따로 시험했을 때 문제가 없었는데 합치니 틀렸다. 가장 먼저 의심할 곳은?프그03-03

여러 사람이 is_valid 를 각자 만들어 넣었고 조건이 서로 달랐다. 이 문제가 특히 위험한 이유는?프그03-03

부품을 하나씩 끼우면서 합칠 때, 문제가 생겼을 경우 가장 효과적인 진단 방법은?프그03-03

Python 과 C 로 만든 두 프로그램의 출력이 글자 단위로 같을 수 있었던 이유는?프그03-03

C 코드에는 'out->count == 0 ||' 라는 조건이 있는데 Python 코드에는 보이지 않는다. 그 까닭은?프그03-03

값을 확인하려고 코드 중간에 끼워 넣은 출력문을 반드시 지워야 하는 이유로 알맞은 것은?프그03-03

더 알아보기

심화위에서부터 붙이기와 아래에서부터 붙이기

통합에는 두 방향이 있다. 주 프로그램부터 붙이고 아래쪽 부품은 가짜로 채우는 방식과, 가장 안쪽 부품부터 완성해 위로 올라가는 방식이다. 앞의 것은 전체 흐름을 일찍 볼 수 있고, 뒤의 것은 확인이 끝난 것 위에 쌓아 올릴 수 있다. 이 차시에서는 껍데기로 전체를 먼저 돌려 본 뒤 안쪽부터 채웠으니 둘을 섞어 쓴 셈이다. 실무에서도 대개 섞어 쓴다.

실무합치는 일을 매일 한다

학교 프로젝트는 마지막에 몰아서 합치기 쉽다. 그런데 그렇게 하면 어긋난 곳이 한꺼번에 쏟아져 나온다. 실무에서는 하루에 한 번 이상 합치고 자동으로 시험을 돌린다. 합치는 간격이 짧을수록 한 번에 처리할 어긋남이 적어지기 때문이다. 모둠 프로젝트에서도 “수업 끝나기 10분 전에 그날 만든 것을 합쳐 본다”는 약속 하나만으로 마지막 날의 고생이 크게 줄어든다.

심화사전과 구조체 — 무엇이 다른가

Python의 사전은 실행 중에 항목을 넣고 뺄 수 있다. 편한 대신 result['cont'] 처럼 이름을 잘못 적어도 실행하기 전에는 아무도 모른다. C의 구조체는 항목을 미리 선언하므로 이름을 잘못 적으면 컴파일 단계에서 걸린다. 1단원 2차시에서 다룬 “오류를 만나는 시점”의 차이가 여기서도 그대로 나타난다. 어느 쪽이 낫다기보다, 자기가 쓰는 언어가 무엇을 실행 전에 잡아 주고 무엇을 안 잡아 주는지 알고 그만큼 테스트로 메우는 것이 중요하다.

이어지는 학습

이 차시를 이해하려면 다음을 먼저 알아야 한다.

  • 5차시의 기능별 구현 코드 — 프로그래밍 프그03-03

교과서에서 찾기

교과서해당 위치쪽수
성림출판(Python)프로그램 설계와 구현 › 01 프로그램 개발 과정 > 3 프로그램 구현216쪽
씨마스커뮤니케이션(Python)프로그램 설계와 구현 › 2 프로그래밍 실제222쪽
삼양미디어(Python)프로그램의 설계와 구현 › 02 프로그램 개발 프로젝트190쪽
삼양미디어(C)프로그램의 설계와 구현 › 02 프로그램 개발 프로젝트197쪽
씨마스(C)프로그래밍 설계와 구현 › 2 프로그래밍의 실제 Ⅰ206쪽
웅보출판사(C)프로그램 설계와 구현 › Chapter 03 프로그램 구현215쪽