나뭇잎 교과서

프로젝트 설계

좋은 프로젝트는 코드를 쓰기 전에 이미 절반이 끝나 있습니다. 입력과 출력, 자료 구조, 알고리즘, 역할과 일정을 먼저 정해 두면 나누어 만든 코드가 맞물리고, 마감 직전의 혼란을 줄일 수 있습니다.

먼저 알면 좋은 것 문제 분해빅오 표기법그래프
본문

프로젝트 설계

본문

네 명이 하던 프로그램 프로젝트가 마감을 앞두고 늦어지자, 친구 네 명을 더 불러 여덟 명이 되었다. 손이 두 배가 되었으니 빨리 끝날 것 같았다. 그런데 새로 온 친구들에게 코드를 설명하고, 누가 무엇을 맡을지 정하고, 서로 만든 부분을 맞추느라 오히려 일이 더 늦어졌다. 사람을 늘렸는데 왜 늦어질까? 나누어 만든 코드가 처음부터 잘 맞물리게 하려면 코드를 쓰기 전에 무엇을 정해 두어야 할까?

그림 1. 팀원(점)들 사이의 소통 경로(선). 팀원이 n명이면 서로 맞춰야 할 경로가 n(n − 1)/2개로, 사람 수의 제곱에 가깝게 늘어난다.
먼저 알아야 할 것함수와 매개변수(함수와 매개변수), 문제 발견(컴퓨터과학으로 풀 문제 발견), 조합(수학).

4.2.1소통 경로의 수

여러 사람이 함께 만드는 프로그램에서는 각자 만든 부분이 서로 맞물려야 한다. 그러려면 서로의 코드가 어떤 값을 주고받는지 알아야 하고, 바뀐 것이 있으면 알려야 한다. 팀원이 두 명이면 맞출 관계가 하나지만, 네 명이면 여섯, 여덟 명이면 스물여덟이다. 일하는 손은 사람 수에 비례해 늘지만, 맞춰야 할 관계는 사람 수의 제곱에 가깝게 늘어난다. 그리고 새로 들어온 사람은 일을 배우는 동안 기존 팀원의 시간을 빼앗는다.

정리 4.2.1 소통 경로와 인터페이스

팀원이 \(n\)명이면 둘씩 맺는 소통 경로는 \(\dbinom{n}{2} = \dfrac{n(n-1)}{2}\)개이다. 이 부담을 줄이려면 각 부분이 주고받는 입력과 출력, 함수의 이름과 매개변수, 자료 구조를 미리 정해 두어, 서로의 속을 몰라도 약속만 지키면 맞물리게 한다. 이 약속을 인터페이스라 한다.

그림 1에서 팀원 수를 바꾸어 보자. 4명이면 경로 6개, 8명이면 28개, 12명이면 66개이다. 사람을 두 배로 늘리면 소통할 경로는 네 배 넘게 늘어난다. 그래서 늦어진 프로젝트에 사람을 더 넣으면, 늘어난 소통과 교육의 부담이 늘어난 손을 잡아먹어 오히려 더 늦어지기도 한다. 인터페이스를 미리 정해 두면 각자는 자기 부분과 약속만 신경 쓰면 되므로, 실제로 맞춰야 할 경로가 크게 준다.1

4.2.2코드를 쓰기 전의 설계

좋은 프로젝트는 코드를 쓰기 전에 이미 절반이 끝나 있다. 먼저 프로그램 전체의 입력과 출력을 정하고, 그 사이의 일을 몇 개의 모듈로 나눈다. 모듈마다 무엇을 받아 무엇을 돌려주는지 함수의 꼴로 적고, 모듈 사이에 주고받을 자료 구조를 정한다. 그다음 알고리즘을 고르고 복잡도를 어림한다. 마지막으로 누가 어느 모듈을 맡을지, 언제까지 무엇을 끝낼지 일정을 세운다. 모듈마다 작은 시험을 미리 정해 두면, 나중에 합칠 때 어디가 맞지 않는지 금방 찾을 수 있다.

정할 것배달 경로 프로젝트의 예 입력과 출력학교 주소 목록 → 들르는 순서와 거리 모듈과 인터페이스거리표 만들기(주소들) → 표, 경로 찾기(표) → 순서 역할과 일정모듈마다 담당, 합치는 날짜, 시험 방법
그림 2. 인터페이스를 먼저 정하면 나누어 만든 코드가 맞물린다.

4.2.3예제 풀이

예제 4.2.2

4명 팀에 4명이 더 들어왔다. 소통 경로는 몇 개에서 몇 개로 늘어나는가? 프로그램을 모듈 4개로 나누어 두 명씩 맡기고, 모듈끼리는 정해 둔 인터페이스로만 주고받는다면, 실제로 맞춰야 할 경로는 몇 개로 줄어드는가? 모듈들은 한 줄로 이어져 이웃한 모듈끼리만 자료를 주고받는다.

소통 경로는 \(4 \times 3 \div 2 = 6\)개에서 \(8 \times 7 \div 2 = 28\)개로 늘어난다.

모듈 안에서는 두 명이 하나의 경로로 맞추므로 4개이고, 모듈 사이는 이웃끼리 3개의 인터페이스만 맞추면 된다. 따라서 맞춰야 할 경로는 \(4 + 3 = 7\)개로, 28개의 4분의 1에 불과하다. 즉 팀이 커질수록 일을 잘 나누고 그 경계를 약속으로 고정하는 설계가 중요해진다. 그래서 프로젝트 계획서에는 기능 목록뿐 아니라 모듈 사이의 인터페이스를 함수의 꼴로 적어 둔다.

아래 탐구 카드에서 프로젝트의 입력과 출력, 모듈과 인터페이스, 역할과 일정을 담은 설계서를 써 보자.

  1. '늦어진 소프트웨어 프로젝트에 사람을 더 넣으면 더 늦어진다'는 말은 1975년 브룩스가 「맨먼스 미신」에서 쓴 것으로, 브룩스의 법칙이라 불린다. 그는 IBM의 거대한 운영 체제 개발을 이끌며 이를 겪었다.
마무리

팀원이 \(n\)명이면 소통 경로가 \(n(n-1)/2\)개로 사람 수의 제곱에 가깝게 늘어, 사람을 더 넣으면 소통과 교육의 부담이 늘어난 손을 잡아먹을 수 있다. 그래서 코드를 쓰기 전에 입력과 출력, 모듈과 인터페이스, 자료 구조와 알고리즘, 역할과 일정을 정해 나누어 만든 코드가 약속만으로 맞물리게 한다. 처음 질문의 프로젝트는 인터페이스 없이 사람만 늘려 맞춰야 할 관계가 6개에서 28개로 늘어 더 늦어졌다.

읽기 1

코딩부터 시작하면 왜 프로젝트가 꼬일까?

읽기 · 문제 분석에서 검증까지의 설계

주제를 정하자마자 코드부터 쓰기 시작하면, 며칠 뒤 “이 자료는 어떻게 저장하지?”, “이 함수는 누가 만들었지?” 같은 문제가 한꺼번에 터진다. 프로젝트 수행 과정을 미리 설계하면 무엇을 피할 수 있을까?

1프로그래밍으로 문제를 해결하는 네 단계

단계할 일잔반 분석 프로젝트의 예
문제 분석과 구조화입력·출력·제약을 정하고, 자료를 어떤 구조(리스트, 사전, 그래프)로 나타낼지 정한다날짜를 키로, (메뉴 목록, 잔반 kg)을 값으로 하는 사전
알고리즘 설계해결 방법을 의사코드나 순서도로 쓰고, 여러 후보의 효율(빅오)을 비교한다메뉴별 평균 잔반 계산 O(n), 정렬해 상위 10개 O(n log n)
프로그래밍(자동화)언어와 라이브러리를 고르고, 기능을 함수·모듈로 나누어 구현한다파이썬, CSV 읽기는 csv 모듈, 그래프는 matplotlib
검증테스트로 정확성을 확인하고, 다른 자료와 환경에서도 잘 동작하는지 평가한다손으로 계산한 3일치 결과와 비교, 2학기 자료로 다시 실행

네 단계는 한 번에 끝나는 직선이 아니다. 검증에서 문제가 나오면 설계로, 때로는 문제 정의로 돌아간다. 그래서 작은 기능 하나를 네 단계 모두 거쳐 완성한 다음 기능을 늘려 가는 방식이 실패를 줄인다.

2설계를 코드의 뼈대로 남기기

함수의 이름, 입력, 출력을 먼저 정해 두면 모둠원이 각자 다른 함수를 맡아도 나중에 맞물린다. 몸체는 비워 두고 pass나 설명만 적은 뼈대를 함께 정한다.

def load_records(path):
          """CSV 파일을 읽어 {날짜: (메뉴 목록, 잔반 kg)} 사전을 돌려준다."""   # 담당: 지수
          pass

      def waste_by_menu(records):
          """메뉴별 평균 잔반량 {메뉴: kg}을 돌려준다."""                      # 담당: 현우
          pass

      def top_k(scores, k=10):
          """값이 큰 순서로 (메뉴, kg) k개를 돌려준다."""                       # 담당: 서윤
          pass

3모둠이 함께 정할 것

주제와 언어

후보를 모두 적고 장단점을 비교한 뒤 투표 등 모둠이 합의한 방법으로 정한다. 목소리 큰 한 사람이 정하지 않는다.

역할

자료 담당, 알고리즘 담당, 화면 담당, 테스트 담당처럼 나누되, 모두가 코드 일부를 쓰고 서로의 코드를 읽어 본다.

일정

작업을 나누고 선행 관계를 그려 임계 경로를 찾고, 중간 점검일을 둔다.

도구

코드는 git 저장소에 두고, 할 일과 문제는 이슈 목록이나 공유 문서에 적는다.

완성의 기준

어떤 테스트를 통과하면 끝난 것으로 볼지 처음에 정해 둔다.

판단계획은 처음부터 완벽할 수 없으며, 계획대로 되지 않는 것이 실패도 아니다. 중요한 것은 바뀐 내용을 기록하고 모둠이 함께 아는 것이다. 반대로 계획을 세우는 데만 시간을 쓰고 아무것도 실행해 보지 않으면 문제를 늦게 발견하게 되므로, 작게 만들어 보고 고치는 과정을 일정에 넣는다.

확인조건이 달라지면

프로젝트 마감 1주 전에 테스트해 보니, 자료를 읽는 함수가 돌려주는 형식과 분석 함수가 기대하는 형식이 서로 달랐다. 이런 일을 막으려면 설계 단계에서 무엇을 했어야 할까?

탐구 2

프로젝트는 어느 단계가 늦어지면 전체가 늦어질까?

프로젝트 설계 · 작업 분해와 임계 경로
프로젝트 전체 기간
—
임계 경로
—
선택한 작업의 여유
—
def schedule(dur, pre, order):
          # order: 선행 작업이 언제나 먼저 오도록 정렬한 작업 목록
          start = {}
          for t in order:
              start[t] = max((start[p] + dur[p] for p in pre[t]),
                             default=0)
          return max(start[t] + dur[t] for t in order)

고등학생 모둠의 정보과학 프로젝트(학교 급식 잔반 기록을 분석하는 프로그램)를 가정한 모식 일정이다. 막대 사이의 회색 선은 “앞 작업이 끝나야 시작할 수 있다”는 선행 관계이다.

  1. 질문모둠 프로젝트의 마감이 3주 뒤이다. 할 일을 나누고 각자 맡았는데, 어떤 일은 하루 늦어져도 괜찮고 어떤 일은 하루 늦어지면 발표도 하루 늦어진다. 어느 작업을 가장 신경 써야 할까?
  2. 복원프로그래밍으로 문제를 해결하는 절차는 문제 분석과 구조화 → 알고리즘 설계 → 프로그래밍(자동화) → 검증이다. 작업 사이의 “먼저 끝나야 하는” 관계는 방향 그래프로 나타낼 수 있다.
  3. 설명프로젝트를 크기가 작은 작업으로 나누는 것을 작업 분해라 한다. 각 작업은 모든 선행 작업이 끝난 뒤에야 시작할 수 있으므로, 가장 이른 시작일은 선행 작업의 (시작일 + 기간) 중 가장 큰 값이다. 선행 관계를 지키는 순서(위상 정렬)로 작업을 하나씩 계산하면 전체 기간이 나온다. 처음부터 끝까지 이어지는 가장 긴 작업 사슬이 임계 경로이며, 이 경로의 작업은 하루만 늦어져도 전체가 늦어진다.
  4. 연결임계 경로 밖의 작업에는 여유가 있어, 그만큼 늦어져도 마감에 영향이 없다. 모둠원은 여유가 있는 작업을 맡은 사람이 임계 경로의 작업을 돕는 식으로 역할을 조정할 수 있다. 코드에서 각 작업을 한 번씩만 계산하는 것은 앞에서 배운 동적 계획법과 같은 생각이다.
  5. 적용‘자료 수집’의 기간을 4일에서 8일로 늘려 보자. 전체 기간이 바로 늘어나는가? 임계 경로가 바뀌는 순간은 언제인가? 반대로 ‘프로그래밍’을 하루 줄이면 전체 기간은 몇 일 줄어드는가?
  6. 판단이 계산은 작업 기간을 정확히 안다고 가정하고, 한 사람이 여러 작업을 동시에 할 수 없다는 제약도 넣지 않았다. 실제 프로젝트에서는 예상이 자주 빗나가므로 임계 경로에 여유 기간을 두고, 중간 점검일을 정해 계획을 고친다. 주제와 사용할 언어처럼 모둠 전체에 영향을 주는 결정은 한 사람이 정하지 말고 함께 협의해 정한다.

확인조건이 달라지면

임계 경로에 있지 않고 여유가 3일인 작업이 2일 늦어졌다. 프로젝트 전체 기간은 어떻게 될까?

AI 출제 문항연습문제 풀어보기11문항
Esc

↑↓ 고르기Enter 열기