프로그래밍

도서 대출 시스템

한 번 답하고 끝나지 않습니다.
끝내라고 할 때까지 계속 말을 걸어 봅니다.

학습 목표

  1. 이름으로 값을 찾아 쓰는 자료 담기를 설계에 쓸 수 있다.
  2. 끝날 때까지 반복하는 구조를 만들고, 빠져나갈 조건을 정할 수 있다.
  3. 상태가 바뀌는 자료를 다루며 어떤 명령이 언제 되는지 구분할 수 있다.
  4. 없는 이름을 찾는 경우를 먼저 막아 프로그램이 멈추지 않게 할 수 있다.

무엇을 만드나

명령을 계속 받는 프로그램은 어떻게 만들까요?

주어진 문제

도서관에 책 몇 권이 있고 각각 대출 가능이거나 대출 중입니다. 사용자가 대출 · 반납 명령을 계속 넣으면 그때마다 처리하고, 끝내라는 명령이 오면 멈추는 프로그램을 만듭니다.

이 프로그램은 값을 받아 답 하나를 내놓고 끝나지 않습니다. 몇 번 도는지 미리 알 수 없고, 앞의 명령이 뒤의 결과를 바꿉니다. 빌린 책은 다시 빌릴 수 없으니까요. 이렇게 상태를 들고 다니는 프로그램을 짜 봅니다.

단계 여기서 답할 질문
1 요구 분석 어떤 명령을 받고 각각 언제 되는가
2 설계 책과 상태를 어떻게 담고 언제 멈출 것인가
3 구현 명령을 어떻게 구분해 처리할 것인가
4 테스트 명령을 어떤 순서로 넣어 봐야 하는가

먼저 개발 문서 양식을 내려받으세요

읽기만 하지 말고 직접 채워 보세요. 단계마다 자기 답을 적어 두면 그 기록이 요구 사항 명세서이자 설계서가 됩니다. 답을 보기 전에 먼저 적어 봅니다.

요구 분석과 설계는 언어와 상관없습니다. 두 양식의 앞부분은 같고, 구현을 적는 자리만 언어에 맞춰 다릅니다. 수업에서 쓰는 언어에 맞는 것을 받으면 됩니다. 이 강의노트의 코드 예시는 파이썬으로 되어 있습니다.

1단계 · 무엇을 만들 것인가

「대출한다」가 언제나 되는 것은 아닙니다.

되물어야 할 것들

  • 이미 빌린 책을 또 빌리면? 안 된다고 알리나요, 그냥 넘기나요
  • 안 빌린 책을 반납하면?
  • 없는 책 이름을 넣으면?
  • 언제 끝나나요? 끝내는 명령이 따로 있나요
  • 책 목록은 어디서 오나요? 입력받나요, 정해져 있나요

정리한 요구 사항

  1. 책 목록과 처음 상태는 프로그램 안에 정해 둔다. 입력받지 않는다.
  2. 명령은 「번호 책이름」 꼴로 한 줄씩 받는다. 1은 대출, 2는 반납이다.
  3. 0만 넣으면 프로그램을 끝낸다.
  4. 없는 책이면 없는 책이라고 알린다.
  5. 대출은 대출 가능일 때만 되고, 반납은 대출 중일 때만 된다. 아니면 그렇다고 알린다.
  6. 처리할 때마다 결과를 한 줄씩 알린다.

4번과 5번의 순서가 정해져 있습니다

없는 책인지 먼저 보고, 그다음에 상태를 봐야 합니다. 없는 책의 상태를 물어보려 들면 거기서 프로그램이 멈춥니다. 「꺼내기 전에 막는다」입니다. 없을 수도 있는 것은 꺼내기 전에 있는지부터 봅니다.

스스로 확인

요구 사항 3번에서 끝내는 명령을 따로 두었습니다. 이것이 없으면 프로그램이 어떻게 될까요? 알고리즘이 갖춰야 할 조건 가운데 유한성(정해진 단계 안에 반드시 끝나야 한다는 조건)과 이어서 생각해 보세요.

2단계 · 이름으로 찾고, 끝날 때까지 돈다

새로 필요한 것이 두 가지입니다.

토막 무엇을 정하는가
입력 명령 줄이 여러 개 — 몇 개인지 미리 모른다
처리 책의 상태를 찾아보고, 되면 바꾸고 안 되면 알린다
출력 명령마다 결과 한 줄

번호가 아니라 이름으로 찾는다

목록에서는 몇 번째라고 인덱스(목록에서 몇 번째인지를 0부터 센 번호)를 대어 값을 꺼냅니다. 그런데 여기서 필요한 것은 「파이썬이라는 책의 상태」입니다. 책이 몇 번째에 있는지는 아무도 모르고 알 필요도 없습니다.

이름을 대면 값이 나오는 방식으로 담으면 됩니다. 책 이름이 찾는 키(key)가 되고 상태가 그 값입니다. 사전에서 낱말을 찾으면 뜻이 나오는 것과 같습니다.

찾는 이름 담긴 값
파이썬 대출가능
씨언어 대출중
자바 대출가능

몇 번 돌지 모르는 반복

정해진 횟수만큼 도는 반복은 「몇 번」을 미리 알고 시작합니다. 여기서는 사용자가 언제 끝낼지 모릅니다. 그래서 「끝내라는 말이 나올 때까지 계속」이라는 방식으로 돕니다.

빠져나가는 길을 반드시 만들어 두어야 합니다. 처리 순서를 기호와 화살표로 그린 순서도에서 조건은 마름모로 그리는데, 되돌아가는 화살표에는 빠져나가는 마름모가 함께 있어야 합니다. 없으면 영원히 도는 프로그램이 됩니다.

푸는 순서

  1. 책과 상태를 짝지어 담아 둔다.
  2. 다음을 끝내라는 명령이 올 때까지 반복한다.
    • 명령을 한 줄 받아 번호와 책 이름으로 나눈다.
    • 번호가 0이면 반복을 빠져나간다.
    • 없는 책이면 그렇다고 알리고 다음 명령으로 간다.
    • 대출 명령이면 — 대출 가능일 때만 대출 중으로 바꾸고 알린다.
    • 반납 명령이면 — 대출 중일 때만 대출 가능으로 바꾸고 알린다.
    • 둘 다 아니면 없는 명령이라고 알린다.

끝내는 명령에는 책 이름이 없습니다

다른 명령은 번호와 책 이름 둘인데 끝내는 명령은 번호 하나뿐입니다. 그러니 책 이름을 꺼내기 전에 0인지 먼저 봐야 합니다. 순서를 바꾸면 없는 둘째 토막을 꺼내려다 멈춥니다.

스스로 확인

설계에서 「없는 책이면 알리고 다음 명령으로」가 대출·반납보다 앞에 있습니다. 이 줄을 맨 뒤로 옮기면 무슨 일이 벌어질까요?

3단계 · 파이썬으로 옮기기

조건이 여러 겹으로 겹칩니다.

먼저 스스로 적어 본 뒤에 코드를 보세요. 코드는 길지만 새로운 것은 이름으로 찾기와 끝날 때까지 돌기, 둘뿐입니다. 설계에서 말한 이름으로 찾는 담기는 파이썬의 딕셔너리({ })입니다. 코드의 books가 그것이고, 요구 사항에서 「책 목록」이라 부른 것도 리스트가 아니라 이 딕셔너리로 담았습니다.

도서.기본.py

books = {"파이썬": "대출가능", "씨언어": "대출중", "자바": "대출가능"}

while True:
    parts = input().split()
    if parts[0] == "0":
        break

    command = parts[0]
    title = parts[1]

    if title not in books:
        print("없는 책입니다")
    elif command == "1":                 # 대출
        if books[title] == "대출가능":
            books[title] = "대출중"
            print("대출되었습니다")
        else:
            print("이미 대출 중입니다")
    elif command == "2":                 # 반납
        if books[title] == "대출중":
            books[title] = "대출가능"
            print("반납되었습니다")
        else:
            print("대출 중이 아닙니다")
    else:
        print("없는 명령입니다")

조건이 두 겹입니다

바깥에서 어떤 명령인지를 구분하고, 안에서 지금 그 명령이 되는 상태인지를 구분합니다. 「대출 명령이다」와 「대출할 수 있다」는 다른 것이라 두 번 물어보는 것입니다. 이 구별이 흐려지면 이미 빌린 책을 또 빌려 주는 프로그램이 됩니다.

상태를 바꾸는 줄

이 프로그램은 담아 둔 값을 덮어씁니다. 이 한 줄이 있어서 다음 명령의 결과가 달라집니다. 답 하나를 내놓고 끝나는 프로그램에는 없는 성질입니다. 같은 명령을 두 번 넣으면 다른 답이 나오는 프로그램이니까요.

스스로 확인

상태를 바꾸는 줄(대출 중으로 덮어쓰는 줄)을 지우면 프로그램이 어떻게 동작할까요? 무엇을 알리고 무엇이 안 바뀔까요?

4단계 · 넣어 보고 확인하기

이번엔 값 하나가 아니라 명령의 순서를 넣어 봅니다.

같은 명령이라도 언제 넣느냐에 따라 답이 다릅니다. 그러니 테스트도 명령 하나가 아니라 명령의 줄거리로 짜야 합니다.

넣은 명령 차례 나와야 할 결과 무엇을 보려는 값인가
1 파이썬 대출되었습니다 대출 가능한 책을 빌린다
1 파이썬 (한 번 더) 이미 대출 중입니다 상태가 바뀌었는지 — 앞 명령의 결과가 남아 있는가
2 파이썬 반납되었습니다 되돌아오는지
2 자바 대출 중이 아닙니다 안 빌린 책을 반납하는 경우
1 없는책 없는 책입니다 없는 이름 — 멈추지 않는가
3 자바 없는 명령입니다 모르는 번호
0 끝난다 빠져나가는 길이 있는가

결과가 어긋났다면 여기부터 봅니다

  • 같은 책을 계속 빌릴 수 있다 — 상태를 바꾸는 줄이 빠졌거나 상태를 보는 조건이 빠졌습니다
  • 없는 책에서 멈춘다 — 없는 책 검사가 상태를 보는 것보다 뒤에 있습니다
  • 0을 넣어도 안 끝난다 — 빠져나가는 줄이 빠졌거나 글자와 수를 비교하고 있습니다
  • 0을 넣으면 오류가 나며 멈춘다 — 책 이름을 0인지 보기 전에 꺼내고 있습니다
  • 아무 반응이 없다 — 알리는 줄이 빠졌거나, 들여쓰기가 어긋나 실행되지 않는 갈래로 들어갔는지 봅니다

「1 파이썬 (한 번 더)」 줄을 빠뜨리지 않습니다

같은 명령을 두 번 넣어 답이 달라지는지를 보는 줄입니다. 답이 두 번 다 「대출되었습니다」라면 프로그램이 앞의 일을 기억하지 못하고 있다는 뜻입니다. 상태를 들고 다니는 프로그램은 반드시 이런 테스트가 필요합니다. 한 번씩만 넣어 보면 절대 안 잡힙니다.

스스로 확인

표의 명령을 순서를 바꿔 넣어 보세요. 「2 파이썬」을 맨 처음에 넣으면 무엇이 나와야 할까요?

더 해 보기

실제 도서관에 가까워지려면 무엇이 더 필요할까요?

책 목록을 보여 주는 명령

번호 3을 넣으면 모든 책과 상태를 한 줄씩 보여 주게 합니다. 이름으로 찾는 것과 전부 차례로 순회하는 것은 다른 일입니다.

누가 빌렸는지 기록한다

상태만 두지 말고 빌린 사람의 이름까지 담아 봅니다. 값 하나에 두 가지를 담아야 하니 담는 모양부터 다시 정해야 합니다.

책을 새로 넣는 명령

정해 둔 목록에 책을 더할 수 있게 합니다. 이미 있는 책 이름을 넣으면 어떻게 할지 먼저 정해야 합니다.

끝낼 때 저장한다

지금은 프로그램을 끝내면 빌린 기록이 전부 사라집니다. 실제 시스템이라면 큰 문제일 것입니다. 무엇이 더 있어야 할지 생각해 보세요.

스스로 확인

「끝낼 때 저장한다」 과제에서 「끝내면 기록이 사라진다」고 했습니다. 값을 받아 답 하나를 내놓고 끝나는 프로그램에는 이 문제가 왜 없을까요?