Devin.KR

CS · 기본

비전공자를 위한 컴퓨터공학 지도 - 전공 4년을 개발자 눈으로 따라잡기

나만의 따라잡기 계획 - 6개월 학습표와 면접 준비

과목별 우선순위, 주 단위 계획, 공부한 것을 증명하는 방법(정리 글·코드·코드패스 기록), 면접 CS 질문 준비, 완성 코드는 가용 시간과 우선순위로 주별 학습표를 만드는 계획기

개발자KR · 원고 갱신

이 장에서 배우는 것

앞 장에서 보안 지식을 실제 코드의 판단 기준으로 연결했다. 이제 책에서 만난 과목들을 자신의 일정에 배치할 차례다. 과목 이름을 많이 아는 것과 필요한 지식을 꺼내 설명하는 것은 다르다. 이 장에서는 남은 시간을 세고, 우선순위를 정하고, 학습 결과를 확인할 증거를 남기는 방법을 다룬다. 여섯 달을 마쳤을 때의 목표는 모든 과목을 끝냈다는 표시가 아니다. 업무에서 만난 문제를 어느 과목의 개념으로 설명할지 알고, 자신의 판단을 코드와 말로 보여 주는 상태다.

여기서는 여섯 달을 계획용으로 24주로 잡는다. 실제 달력의 여섯 달과 주 수가 정확히 같다는 뜻은 아니다. 날짜를 붙이기 전, 반복 가능한 주간 계획을 만드는 데 쓰는 길이다. 완성 코드는 매주 쓸 수 있는 시간과 과목별 우선순위를 받아 24주의 학습표를 출력한다.

  • 업무와 설명의 빈틈을 기준으로 과목별 우선순위를 정한다.
  • 가용 시간을 학습 시간과 증거를 만드는 시간으로 나눈다.
  • 정리 글, 실행 코드, 코드패스 기록으로 학습 결과를 확인한다.
  • 면접 질문에 정의, 사례, 선택 이유, 확인 방법을 연결해 답한다.
  • Python 표준 기능으로 결정적인 주별 계획기를 만든다.

문제 상황

다른 전공을 공부한 뒤 개발 업무를 시작한 사람이 있다. 기능을 구현하고 오류를 고치는 일은 익숙해졌다. 그런데 동료가 자료구조를 고른 이유를 물으면 “그동안 이렇게 사용했다”는 답부터 나온다. 데이터베이스 변경 중 일부만 반영되는 상황을 설명하거나, 요청 지연의 원인을 나누어 말하는 일도 어렵다. 경험은 쌓였지만 경험에 붙일 개념의 이름과 경계가 아직 정리되지 않은 상태다.

이 사람은 평일 두 번에 두 시간씩, 주말에 두 시간을 확보할 수 있다. 일주일에 여섯 시간이다. 처음에는 모든 과목을 매일 조금씩 보려고 했다. 그러나 자료를 찾고 읽는 데 시간을 쓰다 보니 무엇을 이해했는지 확인할 결과가 남지 않았다. 면접을 앞두고 정리 노트를 펼쳐도 읽은 문장과 자신이 설명할 수 있는 문장을 구별하기 어려웠다.

해결할 문제는 학습 자료를 더 모으는 일이 아니다. 제한된 시간에 어떤 과목을 더 자주 만나고, 매주 어떤 결과를 남길지 정하는 일이다. 전공 수업에서는 목표와 활동, 평가를 연결하는 일을 학습 설계라고 부른다. 개인 계획에도 같은 관점이 필요하다. “운영체제를 공부한다”는 활동만 적지 않고, “직접 실행한 코드의 동작을 운영체제 용어로 설명한다”는 확인 기준까지 적는다.

완성 코드의 입력은 이미 확보한 시간이라고 가정한다. 희망하는 시간을 넣으면 실제 생활과 맞지 않는 표가 나온다. 지난 몇 주 동안 지킬 수 있었던 시간을 먼저 확인하고, 그 안에서 계획을 만든다. 이동 중 읽기처럼 집중 조건이 다른 시간은 처음부터 같은 학습 시간으로 합치지 않아도 된다.

과목의 우선순위를 정하는 기준

우선순위는 사람의 능력을 한 줄로 평가하는 점수가 아니다. 이번 계획에서 만나는 횟수를 정하기 위한 설정이다. 세 가지를 함께 본다. 현재 맡은 일에서 자주 쓰이는가, 다른 과목을 이해하는 데 도움이 되는가, 직접 설명하거나 실행할 때 빈틈이 드러나는가다. 이 가운데 두 가지 이상이 뚜렷하면 높은 우선순위를 줄 수 있다.

먼저 과목마다 짧은 진단을 한다. 자료를 보지 않고 익숙한 문제 하나를 설명하고, 관련된 작은 코드를 실행하고, 결과가 예상과 다른 경우를 하나 만든다. 말은 이어지는데 코드를 바꾸지 못하면 적용 연습이 필요하다. 코드는 돌아가는데 이유를 말하지 못하면 설명 연습이 필요하다. 둘 다 가능하면 다른 과목에 시간을 더 줄 근거가 된다.

우선순위는 다음 학습 행동을 정하는 값이다
값판단 기준이번 계획의 행동
3업무 관련성이 높거나 다른 과목과 연결되며 설명이 막힌다여러 차례 다시 만나 실행과 설명을 보강한다
2기본 설명은 가능하지만 사례와 선택 이유가 부족하다다른 입력과 대안을 비교한다
1현재 목표에서는 빈도가 낮거나 증거가 이미 있다학습표에 남겨 두고 연결을 점검한다

예제에서는 이산수학, 자료구조, 알고리즘, 컴퓨터 구조에 3을 준다. 운영체제, 네트워크, 데이터베이스, 언어와 컴파일러에는 2를 주고, 소프트웨어 공학과 보안에는 1을 준다. 앞에서 만난 기초 개념의 연결을 다시 확인하려는 가상 독자의 설정이다. 보안이나 소프트웨어 공학이 덜 중요하다는 일반적인 순위가 아니다. 실제 업무가 인증 기능이나 협업 절차에 집중되어 있다면 해당 과목의 값을 높인다.

과목별 학습표 옆에는 세 칸짜리 메모를 둔다. 실무에서 만난 장면, 확인할 핵심 질문 3~5개, 더 깊게 볼 서재의 책이다. 책은 지금 막힌 질문에 답할 목차가 있는지 보고 한 권을 고른다. 이 장에서 새 독서 목록을 늘리기보다 앞에서 확보한 과목별 책과 질문을 연결한다. 읽을 범위를 “한 권”으로 적는 대신 해당 질문을 설명하는 절로 좁히면 주간 시간 안에 확인하기 쉽다.

전공 수업에서 먼저 알아야 뒤의 내용을 이해할 수 있는 관계를 선수 관계라고 부른다. 개인 계획에서는 이것을 엄격한 통과 조건으로 만들 필요가 없다. 예를 들어 다른 과목을 읽다가 자료구조 설명이 막히면 해당 질문을 다음 자료구조 시간에 가져온다. 과목을 하나씩 모두 끝낸 뒤 이동하는 방식보다, 같은 과목을 다시 방문하면서 연결을 보강하는 방식이 이 계획의 목적에 맞는다.

업무 장면과 진단 결과를 우선순위로 바꾸고 주간 시간에 배치한다

아래의 짧은 코드는 우선순위 값이 방문 횟수로 바뀌는 원리를 보여 준다. 가중치는 항목마다 배정하는 비중이다. 이 계획에서는 우선순위 값을 가중치로 사용한다. 값이 3인 과목을 한 묶음에서 세 번, 값이 1인 과목을 한 번 넣는다. 같은 과목을 연달아 세 번 넣지 않고, 전체를 돌면서 필요한 횟수를 채운다.

subjects = [("자료구조", 3), ("보안", 1)]
visits = []
for level in range(3):
    for name, priority in subjects:
        if priority > level:
            visits.append(name)
print(visits)
# ['자료구조', '보안', '자료구조', '자료구조']

이 실험에서 3은 숙련도를 뜻하지 않는다. 목록에 들어가는 횟수다. 완성 코드도 같은 규칙을 사용하므로, 우선순위를 바꾸었을 때 시간 배정이 어떻게 달라지는지 목록 길이와 실제 출력으로 확인할 수 있다.

주간 시간과 학습 증거를 함께 설계한다

시간을 쪼개어 배정하는 최소 단위를 시간 블록이라고 부르겠다. 완성 코드에서는 한 블록을 두 시간으로 잡는다. 매주 마지막 한 블록은 학습 증거를 만드는 데 쓰고, 나머지를 과목 학습에 배정한다. 여섯 시간이면 과목 학습 두 블록과 증거 한 블록이다. 한 시간 단위로 잘게 나누지 않는 이유는 예제를 실행하고 결과를 정리할 시간을 함께 확보하려는 것이다.

이 규칙은 시간의 성격을 드러내기 위한 선택이다. 두 시간을 연속으로 확보할 필요는 없다. 한 블록을 하루 한 시간씩 나누어 사용할 수 있다. 다만 계획기의 계산 단위는 두 시간으로 유지한다. 주간 시간이 홀수라면 남는 한 시간은 표에서 여유 시간으로 표시한다. 지키기 어려운 일정을 만들기보다, 중단된 작업을 마치거나 쉬는 데 쓸 공간을 남긴다.

예제의 한 주 여섯 시간은 학습과 증거에 나뉜다
용도시간끝났다고 판단할 기준
첫 과목 방문2시간질문 하나를 정하고 입력을 바꾸어 실행한다
둘째 과목 방문2시간예상과 실제 결과의 차이를 설명한다
증거 만들기2시간정리 글, 코드, 코드패스 기록 중 하나를 남긴다

정리 글은 읽은 내용의 축약본보다 질문에 대한 자신의 답에 가깝다. “왜 이 선택을 했는가”라는 제목 아래 전제, 선택, 근거, 다른 선택이 나을 조건을 적는다. 글에 코드 결과를 인용한다면 어떤 입력으로 실행했는지도 함께 남긴다. 나중에 읽는 자신이 같은 판단을 재현할 수 있어야 한다.

코드는 기능이 큰 프로그램일 필요가 없다. 이번에 확인한 차이를 보여 주는 짧은 실험이면 된다. 입력, 실행 방법, 예상 결과를 적고 두 가지 이상의 조건을 비교한다. 이미 돌아가는 코드를 저장했다는 사실만으로 해당 개념을 이해했다고 판단하지 않는다. 설명하려던 질문에 코드가 답하는지 확인한다.

코드패스 기록은 여기서 입력이 들어온 뒤 함수 호출과 조건 분기를 거쳐 출력에 이르는 경로를 적은 기록을 뜻한다. 특정 서비스나 도구의 이름이 아니다. 전공 수업에서는 실행 흐름을 따라 값을 확인하는 활동을 추적이라고 부른다. 완성 코드에 적용한다면 “6 입력 → 전체 세 블록 → 증거 한 블록 예약 → 과목 두 개 선택 → 한 줄 출력”처럼 적을 수 있다. 여기에 실제 변수 값과 해당 줄을 덧붙이면 기억에 의존한 설명을 줄인다.

세 종류의 증거는 서로를 보완한다. 글은 판단을 드러내고, 코드는 재현할 수 있는 실험을 남기며, 코드패스 기록은 설명과 실제 실행을 잇는다. 완성 코드에서는 종류만 주마다 순환시킨다. 어떤 주제를 다룰지는 그 주의 두 과목 중 더 많이 막힌 질문을 골라 정한다.

이 학습표는 우선순위에 따른 한 묶음을 두 번 배정한다. 예제의 우선순위 합은 22이므로 전체 방문은 44회다. 매주 두 번 방문하면 22주가 필요하다. 남은 두 주의 학습 칸에는 면접 답변과 모의 면접을 넣는다. 다른 가용 시간을 입력하면 끝나는 주도 달라진다. 목록을 다 배정하지 못하면 남은 방문 수를 출력한다. 배정은 학습 완료를 뜻하지 않으며, 실제 완료 여부는 주간 증거로 따로 확인한다.

면접 답변을 학습의 확인 장치로 쓴다

면접의 컴퓨터공학 질문은 용어를 기억하는지 확인하는 형태로 시작할 수 있다. 그러나 준비할 때는 한 문장 정의에서 멈추지 않는다. 정의를 말하고, 자신이 실행한 사례를 붙이고, 그 선택이 유리한 조건과 불리한 조건을 나누고, 무엇을 확인했는지 설명한다. 이 네 부분이 이어지면 모르는 조건을 만났을 때도 답의 범위를 분명하게 말할 수 있다.

질문 목록은 과목마다 세 가지 방향으로 만든다. “무엇인가”는 뜻을, “왜 골랐는가”는 선택 근거를, “조건이 달라지면 어떻게 되는가”는 적용 범위를 묻는다. 같은 정의를 여러 표현으로 외우는 대신 질문의 방향을 바꾸어 본다. 확인하지 않은 성능이나 동작을 단정하지 않고, 자신이 실행한 조건과 추가로 필요한 확인을 구분한다.

면접 질문은 기존 학습 증거에 연결해 준비한다
질문 방향준비할 내용꺼내 볼 증거
자료구조를 왜 골랐는가필요한 연산과 대안을 비교한 이유같은 입력을 처리한 비교 코드
실행 결과가 왜 달라졌는가입력에서 출력까지의 조건과 값코드패스 기록
실패를 어떻게 확인했는가예상 결과와 실제 결과의 차이실패 조건을 포함한 실행 기록
다른 선택은 언제 가능한가현재 선택이 기대는 전제와 한계선택 이유를 적은 정리 글

짧게 말하는 연습과 정확히 설명하는 연습은 함께 진행한다. 먼저 한 분 안에 핵심을 말하고, 이어지는 질문에는 코드의 입력과 결과를 사용해 답한다. 설명을 녹음하거나 글로 옮겼을 때 “빠르다”, “안전하다”, “효율적이다”라는 말만 남는다면 비교 대상과 조건을 더한다. 답변 길이를 늘리기보다 근거가 없는 형용사를 구체적인 관찰로 바꾸는 편이 도움이 된다.

모의 면접 뒤에는 맞힌 질문 수만 세지 않는다. 정의가 막혔는지, 사례가 없었는지, 선택 이유가 약했는지 표시한다. 정의가 막히면 정리 글을 고치고, 사례가 없으면 실험을 만들고, 실행 설명이 어긋나면 코드패스 기록을 보완한다. 이 되먹임을 피드백이라고 부른다. 질문 결과를 다음 행동으로 돌려보내는 것이다.

면접에서 막힌 부분을 확인하고 그에 맞는 학습 증거를 보완한다

계획은 네 주마다 검토한다. 이때 학습한 시간을 성과와 같은 뜻으로 쓰지 않는다. 예정한 시간 중 지킨 시간, 실제로 설명할 수 있게 된 질문, 다음에 확인할 질문을 따로 적는다. 계속 밀리는 과목은 의지가 부족하다고 결론짓기 전에 범위가 너무 크거나 선수 개념이 빠졌는지 살핀다. 우선순위가 바뀌면 다음 계획을 다시 만들되, 이미 남긴 증거는 유지한다. 아래 프로그램은 진행 상태를 저장하지 않으므로 재실행할 때 기존 계획과 실적을 별도로 대조해야 한다.

완성 코드

다음 내용을 main.py에 저장한다. 입력을 기다리거나 파일을 읽지 않으며, 설정값으로 표를 출력한 뒤 끝난다. 과목 이름은 표를 짧게 유지하기 위해 일부 줄여 쓴다. 구조는 컴퓨터 구조, 언어는 프로그래밍 언어와 컴파일러, 공학은 소프트웨어 공학을 가리킨다.

WEEKS = 24
WEEKLY_HOURS = 6
BLOCK_HOURS = 2
REPEATS = 2

SUBJECTS = [
    ("이산", 3),
    ("자료", 3),
    ("알고", 3),
    ("구조", 3),
    ("운영", 2),
    ("네트", 2),
    ("DB", 2),
    ("언어", 2),
    ("공학", 1),
    ("보안", 1),
]
ARTIFACTS = ("정리 글", "코드", "코드패스 기록")
INTERVIEW = ("면접 답변", "모의 면접")


def make_plan(weekly_hours, subjects):
    if type(weekly_hours) is not int or weekly_hours < 4:
        raise ValueError("주간 시간은 4 이상의 정수여야 한다.")
    if not subjects:
        raise ValueError("과목을 한 개 이상 넣어야 한다.")
    names = [name for name, _ in subjects]
    if any(not isinstance(name, str) or not name.strip() for name in names):
        raise ValueError("과목 이름은 빈 문자열일 수 없다.")
    if len(set(names)) != len(names):
        raise ValueError("과목 이름은 중복될 수 없다.")
    for _, priority in subjects:
        if type(priority) is not int or priority not in (1, 2, 3):
            raise ValueError("우선순위는 1, 2, 3 중 하나여야 한다.")

    cycle = []
    for level in range(3):
        for name, priority in subjects:
            if priority > level:
                cycle.append(name)
    visits = cycle * REPEATS
    study_slots = weekly_hours // BLOCK_HOURS - 1
    spare_hours = weekly_hours % BLOCK_HOURS
    cursor = 0
    rows = []
    for week in range(1, WEEKS + 1):
        selected = []
        for slot in range(study_slots):
            if cursor < len(visits):
                selected.append(visits[cursor])
                cursor += 1
            else:
                selected.append(INTERVIEW[slot % len(INTERVIEW)])
        artifact = ARTIFACTS[(week - 1) % len(ARTIFACTS)]
        rows.append((week, selected, artifact))
    return rows, len(visits) - cursor, spare_hours


def main():
    rows, remaining, spare = make_plan(WEEKLY_HOURS, SUBJECTS)
    print(f"{WEEKS}주 계획 | 주 {WEEKLY_HOURS}시간")
    print(f"각 항목 {BLOCK_HOURS}시간 | 매주 여유 {spare}시간")
    for week, selected, artifact in rows:
        print(f"{week:02d}주 | {' / '.join(selected)} | 증거: {artifact}")
    print(f"미배정 과목 블록: {remaining}")


if __name__ == "__main__":
    main()

줄별 해설

WEEKS부터 REPEATS까지는 계획의 고정 규칙이다. 대문자 이름은 실행 중 바꾸지 않을 설정이라는 관례를 나타낸다. Python이 대문자 변수의 변경을 막아 주는 것은 아니다. 사용자가 조정하는 주요 입력은 WEEKLY_HOURS와 SUBJECTS다. 블록 길이와 반복 횟수는 이 장의 규칙인 두 시간과 두 번으로 유지한다.

SUBJECTS는 순서가 있는 목록이다. 각 괄호는 이름과 우선순위 두 값을 묶은 튜플이다. 같은 우선순위의 과목은 목록에 적힌 순서를 따른다. 순서도 결과에 영향을 주므로, 값을 바꾸지 않고 과목 위치만 바꾸어도 주별 배치는 달라질 수 있다. ARTIFACTS와 INTERVIEW는 반복해서 사용할 활동 이름이다.

make_plan은 입력을 받아 결과를 돌려주는 함수다. 맨 앞에서는 계산할 수 없는 입력을 거절한다. ValueError는 값이 함수의 약속에 맞지 않을 때 사용하는 예외다. 주간 시간이 네 시간보다 작으면 과목 한 블록과 증거 한 블록을 함께 확보할 수 없다. 이 경우 없는 시간을 배정하는 대신 원인을 알리는 문장과 함께 중단한다.

type(... ) is int는 값의 자료형이 정확히 정수인지 확인한다. 이 예제에서는 참과 거짓을 나타내는 값도 시간이나 우선순위로 받지 않으려는 의도다. 이름 검사에서 사용하는 isinstance는 문자열인지 확인한다. 먼저 이름의 자료형과 빈칸 여부를 검사하므로, 그다음 줄에서 중복 검사를 수행할 수 있다.

names를 만드는 대괄호 표현은 목록의 각 원소에서 필요한 값을 모으는 리스트 컴프리헨션이다. _는 꺼내지만 사용하지 않는 값을 표시하는 관례다. any는 조건에 맞는 항목이 하나라도 있는지 확인한다. strip은 문자열 양끝의 공백을 제거한다. set은 중복 원소를 하나로 모으므로 원래 이름 수와 비교하면 중복을 발견한다. 집합은 검사에만 쓰고 출력 순서를 정하는 데 쓰지 않는다.

cycle을 채우는 바깥 반복은 0, 1, 2를 차례로 사용한다. 안쪽 반복은 모든 과목을 원래 순서로 확인한다. 우선순위가 현재 값보다 크면 이름을 추가한다. 따라서 첫 회전에는 모든 과목, 다음에는 2와 3인 과목, 마지막에는 3인 과목이 들어간다. 이 규칙으로 과목 순서를 유지하면서 방문 횟수에 차이를 둔다.

visits = cycle * REPEATS는 목록을 두 번 이어 붙인다. study_slots는 주간 시간을 두 시간 단위로 나눈 뒤 증거 한 칸을 뺀 값이다. //는 나눗셈의 몫을, %는 나머지를 구한다. 여섯 시간을 넣으면 과목 칸은 두 개이고 여유 시간은 0이다. 일곱 시간을 넣으면 과목 칸은 그대로 두 개이고 여유 시간은 1이다.

cursor는 다음에 배정할 방문의 위치다. 전공 수업에서는 이런 순서상 위치를 인덱스라고 부른다. 방문을 고를 때만 1을 더하므로 아직 배정하지 않은 수를 마지막에 계산할 수 있다. 과목 목록을 다 사용하면 남은 칸에 면접 활동을 넣는다. slot은 주마다 다시 0부터 시작하므로 예제의 마지막 두 주에는 면접 답변과 모의 면접이 각각 들어간다.

artifact는 주 번호에서 1을 빼고 증거 종류의 수로 나눈 나머지로 고른다. 위치가 0부터 시작하기 때문에 1을 뺀다. rows.append는 주 번호, 활동 목록, 증거 이름을 결과에 추가한다. 반환값은 전체 표, 미배정 방문 수, 매주 여유 시간 세 가지다. 함수 내부에서는 화면에 출력하지 않아 계산 결과를 별도로 살펴볼 수 있다.

main은 계산을 호출하고 출력한다. 02d는 주 번호를 두 자리로 맞추며, join은 과목 이름 사이에 구분자를 넣는다. 마지막 조건문은 이 파일을 직접 실행할 때 main을 호출한다. 현재 시각, 외부 파일, 난수를 사용하지 않으므로 같은 설정은 같은 출력을 만든다. 난수 자체가 없어 난수의 시작값을 고정할 필요도 없다.

실행 결과

파일을 저장한 디렉터리에서 다음 명령을 실행한다. 별도 입력 없이 아래 결과가 출력된다. 마지막 값 0은 예정한 과목 방문이 모두 표에 들어갔다는 뜻이다.

python3 main.py
24주 계획 | 주 6시간
각 항목 2시간 | 매주 여유 0시간
01주 | 이산 / 자료 | 증거: 정리 글
02주 | 알고 / 구조 | 증거: 코드
03주 | 운영 / 네트 | 증거: 코드패스 기록
04주 | DB / 언어 | 증거: 정리 글
05주 | 공학 / 보안 | 증거: 코드
06주 | 이산 / 자료 | 증거: 코드패스 기록
07주 | 알고 / 구조 | 증거: 정리 글
08주 | 운영 / 네트 | 증거: 코드
09주 | DB / 언어 | 증거: 코드패스 기록
10주 | 이산 / 자료 | 증거: 정리 글
11주 | 알고 / 구조 | 증거: 코드
12주 | 이산 / 자료 | 증거: 코드패스 기록
13주 | 알고 / 구조 | 증거: 정리 글
14주 | 운영 / 네트 | 증거: 코드
15주 | DB / 언어 | 증거: 코드패스 기록
16주 | 공학 / 보안 | 증거: 정리 글
17주 | 이산 / 자료 | 증거: 코드
18주 | 알고 / 구조 | 증거: 코드패스 기록
19주 | 운영 / 네트 | 증거: 정리 글
20주 | DB / 언어 | 증거: 코드
21주 | 이산 / 자료 | 증거: 코드패스 기록
22주 | 알고 / 구조 | 증거: 정리 글
23주 | 면접 답변 / 모의 면접 | 증거: 코드
24주 | 면접 답변 / 모의 면접 | 증거: 코드패스 기록
미배정 과목 블록: 0

면접 주의 코드 증거는 답변에서 언급한 실험을 다시 실행하는 데 사용한다. 코드패스 기록은 설명한 경로와 실제 실행이 같은지 확인하는 데 사용한다. 새로운 과목을 추가하지 않아도 면접 준비와 증거 만들기를 함께 진행할 수 있다.

실무에서 자주 틀리는 것

증거를 만들 시간을 남기지 않는다

가용 시간 전부를 읽기와 실험에 배정하면 결과 정리가 일정 밖으로 밀린다. 아래의 틀린 계산은 여섯 시간에 과목 세 칸을 배정한다. 여기에 증거 두 시간을 더하면 실제 계획은 여덟 시간이 된다.

# 틀린 코드
weekly_hours = 6
study_slots = weekly_hours // 2
print(study_slots)  # 3

# 고친 코드
study_slots = weekly_hours // 2 - 1
print(study_slots)  # 2

증거는 남는 시간에 하는 부록이 아니다. 이해한 내용을 확인하는 활동이므로 처음부터 한 칸을 예약한다.

가용 시간을 올림해서 배정한다

일곱 시간이 있으니 두 시간짜리 활동을 네 개 할 수 있다고 계산하면 한 시간이 부족하다. 나머지는 별도로 보관해야 한다.

# 틀린 코드
weekly_hours = 7
all_slots = (weekly_hours + 1) // 2
print(all_slots)  # 4

# 고친 코드
all_slots = weekly_hours // 2
spare_hours = weekly_hours % 2
print(all_slots, spare_hours)  # 3 1

고친 코드의 세 칸에는 증거 한 칸이 포함된다. 과목에 쓸 수 있는 칸은 두 개다. 여유 한 시간을 이미 배정한 시간처럼 중복해서 세지 않는다.

우선순위를 정렬에만 사용한다

높은 값을 앞으로 옮기는 것만으로는 학습 비중이 바뀌지 않는다. 각 과목을 한 번씩 넣으면 두 과목의 배정 횟수는 같다.

# 틀린 코드
subjects = [("자료", 3), ("보안", 1)]
visits = [name for name, priority in sorted(
    subjects, key=lambda item: item[1], reverse=True
)]
print(visits)  # ['자료', '보안']

# 고친 코드
visits = []
for level in range(3):
    for name, priority in subjects:
        if priority > level:
            visits.append(name)
print(visits)  # ['자료', '보안', '자료', '자료']

틀린 코드의 lambda는 정렬 기준을 전달하는 짧은 함수 표현이다. 정렬은 방문 순서를 바꾸지만 방문 횟수까지 늘려 주지는 않는다. 우선순위를 비중으로 쓰려면 횟수에도 반영해야 한다.

배정을 완료와 같은 뜻으로 기록한다

표가 만들어졌다고 실제 학습이 끝난 것은 아니다. 계획기에서 모두 배정되었다는 값을 학습 완료로 저장하면 아직 실행하지 않은 일까지 끝난 것으로 보인다.

# 틀린 코드
remaining = 0
completed = remaining == 0
print(completed)  # True

# 고친 코드
allocated_all = remaining == 0
evidence_reviewed = False
completed = allocated_all and evidence_reviewed
print(completed)  # False

and는 두 조건이 모두 참인지 확인한다. 이 코드는 구분을 보여 주는 작은 예다. 실제 실적은 주마다 증거를 확인하며 기록해야 한다. 파일이 존재한다는 사실을 넘어서, 처음 정한 질문에 답하는지도 살핀다.

한눈에 보기

계획의 각 항목은 확인할 수 있는 결과와 연결된다
항목이 장의 규칙확인 방법
기간계획용 24주실제 시작일에 주 번호를 붙인다
우선순위1~3을 방문 비중으로 사용한다업무 관련성, 연결, 설명의 빈틈을 적는다
시간두 시간 단위로 배정한다과목 시간과 증거 시간이 가용 시간을 넘지 않는다
증거글, 코드, 코드패스 기록을 순환한다입력과 판단과 결과를 다시 확인한다
면접정의, 사례, 선택 이유, 확인 방법을 잇는다막힌 부분을 다음 학습 행동으로 바꾼다
미배정 수기간 안에 넣지 못한 방문을 센다완료 수와 구별해 다음 계획에 반영한다

계획을 처음 세울 때부터 모든 질문을 알고 있을 필요는 없다. 지금 설명할 수 없는 질문을 적고, 한 주 안에 확인할 수 있는 크기로 줄이는 일부터 시작한다. 이 표는 과목을 대신 공부해 주지 않지만, 무엇을 선택했고 무엇이 남았는지 보이게 한다.

연습 문제

  1. WEEKLY_HOURS를 5로 바꾼다. 매주 과목 칸 수, 증거 시간, 여유 시간, 24주 뒤 미배정 과목 블록 수를 실행 전에 예상하고 확인한다.
  2. 주간 시간을 다시 6으로 돌리고 보안의 우선순위를 1에서 3으로 바꾼다. 전체 방문 수와 마지막 두 주의 과목을 예상한 뒤 실행한다.
  3. main에서 과목별 배정 횟수를 계산해 출력하도록 확장한다. 예제의 과목별 횟수와 전체 과목 학습 시간을 확인한다. 면접 활동은 과목 횟수에 포함하지 않는다.
  4. 완성 코드의 시간 배분을 설명하는 면접 답변을 네 문장으로 작성한다. 이어서 주간 시간이 6일 때 첫 주가 생성되는 코드패스 기록을 변수 값과 함께 남긴다.

정답과 해설

첫 번째 문제에서 전체 시간 블록은 두 개다. 증거 한 개를 빼면 과목은 매주 한 칸이다. 증거에 두 시간을 쓰고 한 시간은 여유로 남긴다. 24주 동안 과목 방문 24회를 배정하므로 44회 중 20회가 남는다. 과목 목록이 남아 있어 면접 활동이 자동으로 들어가는 주는 없다. 면접 준비가 필요하다면 방문 목표나 별도 활동 배치를 조정해야 한다. 이 계획기는 목표를 몰래 줄이지 않고 남은 수를 보여 준다.

두 번째 문제에서 우선순위 합은 24가 되고 두 번 반복하므로 방문 수는 48이다. 매주 두 칸씩 24주에 모두 들어간다. 한 묶음의 마지막 네 항목은 자료, 알고, 구조, 보안이다. 따라서 23주는 자료와 알고, 24주는 구조와 보안이다. 증거 종류는 주 번호로 정하므로 바뀌지 않는다. 이 변경은 보안 시간을 늘리는 동시에 마지막 면접 활동 칸을 사용한다는 뜻이다.

세 번째 문제는 main에서 표를 출력한 반복문 다음에 아래 코드를 추가하면 된다. 사전은 이름과 값을 연결하는 자료형이다. 과목 이름을 키로, 횟수를 값으로 사용한다. 과목 목록에서 사전을 만들었으므로 출력 순서도 그 순서를 따른다.

    counts = {name: 0 for name, _ in SUBJECTS}
    for _, selected, _ in rows:
        for name in selected:
            if name in counts:
                counts[name] += 1
    for name, count in counts.items():
        print(f"{name}: {count}회")
    total_hours = sum(counts.values()) * BLOCK_HOURS
    print(f"과목 학습: {total_hours}시간")

원래 설정에서는 이산, 자료, 알고, 구조가 각각 6회이고 운영, 네트, DB, 언어가 각각 4회다. 공학과 보안은 각각 2회다. 과목 학습은 44블록이므로 88시간이다. 증거 48시간과 면접 활동 8시간을 더하면 전체 144시간으로, 주 여섯 시간씩 24주와 일치한다.

네 번째 문제의 답변 예는 다음과 같다. “이 계획기는 가용 시간을 두 시간 단위로 나누어 학습을 배정한다. 주 여섯 시간이면 증거 작성 두 시간을 예약하고 과목 두 개를 배정한다. 우선순위는 반복 방문 횟수에 반영하며, 높은 값을 준 이유는 실제 업무와 설명의 빈틈으로 정한다. 출력의 미배정 수는 일정에 넣지 못한 방문 수이고, 학습 완료 여부는 남긴 증거로 확인한다.”

첫 주의 기록은 weekly_hours=6, study_slots=2, spare_hours=0, cursor=0에서 시작한다. 첫 칸이 이산을 고르면 위치는 1이 되고, 둘째 칸이 자료를 고르면 2가 된다. 주 번호 1에서 증거 위치는 0이므로 정리 글을 선택한다. 첫 결과는 주 번호 1, 활동 목록 이산과 자료, 증거 정리 글이다. 이 기록은 함수가 반환한 첫 행과 비교해 확인할 수 있다.

책을 마친 뒤에도 질문은 새로 생긴다. 익숙한 업무에서 새로운 조건을 만나면 관련 과목으로 돌아가 작은 실험을 만들고, 설명을 고쳐 쓴다. 자신의 경험에 개념의 이름을 붙이고 그 이름을 실행 결과로 확인하는 습관이 다음 학습의 출발점이 된다.

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

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

READER FEEDBACK

질문·의견

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

댓글 0

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

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