v1.1.0 — ./guide 하나로 읽고, 풀고, 겪는다
v1.0.0은 학습서·./exam·./shoot 셋을 한 저장소에 모았지만, 셋을 쓰려면 각각의 실행 파일을 알아야 했다. 이번 릴리스는 입구를 하나로 만들고, 읽는 축을 추가한다.
$ ./guide
무엇을 할까요
1) 학습 점검 (퀴즈/시험) 216문항
2) 장애 대응 (실전 훈련) 14스테이지
3) 챕터 읽기 31챕터
읽기 → 확인 → 겪기가 한 자리에서 닫힌다. 챕터를 다 읽으면 그 챕터의 시험을 권하고, 스테이지를 클리어하면 관련 챕터의 시험을 권한다.
새로 생긴 것 — ./guide
- 최상위 메뉴 하나. 모드를 고르면 curses에서 빠져나와 해당 러너를 부르고, 끝나면 메뉴로 돌아온다. 한 모드가 어떻게 끝나든(
SystemExit·Ctrl-C) 런처는 살아남는다. - 챕터 읽기 모드 (신규). DBMS → 티어 → 챕터를 고르면 그 벤더의 본문만 남겨
$PAGER로 연다. 각 화면에서Esc로 한 단계씩 물러난다.- 벤더 필터는 단일 벤더 브랜치를 자르는 것과 같은 함수(
filter_dbms.filter_lines)를 쓴다. 브랜치로 보는 것과 읽기 모드로 보는 것이 갈라질 수 없다. - 본문 뷰어를 새로 만들지 않았다.
less가 스크롤·검색을 이미 다 한다.
- 벤더 필터는 단일 벤더 브랜치를 자르는 것과 같은 함수(
./exam·./shoot은 그대로 남는다 — 인자를 줄 때는 여전히 이쪽이다. 제거되거나 의미가 바뀐 인자는 없다.
학습서
챕터 본문은 이번 릴리스에서 바뀌지 않았다(31챕터 그대로). README.md에 ./guide 시작 안내가 들어갔다.
./exam
- 길이로 정답이 드러나던 64문항의 오답을 다시 썼다. 정답 선택지가 가장 긴 문항은 본문을 몰라도 길이만 보고 맞힐 수 있었다. 은행 23개 216문항을 전수 점검해 걸린 것을 고쳤고, 오답의 정보 밀도를 정답에 맞췄다.
- 길이 누설을 기계적으로 막는다. 새 문항이 같은 함정을 다시 만들면 테스트가 실패한다. 측정 기준은 문자 수가 아니라 표시 폭(
tui.cwidth)이다 — 한글은 2칸,max_connections는 1칸이라 문자 수로 재면 통과하는 문항이 화면에서는 여전히 누설된다. - 라인 모드(파이프·비-tty) 선택 화면이 세 러너에서 하나로 통일됐다.
./shoot
- 진단 문항의 선택지 순서가 이제 실제로 섞인다. 게임 시드로 섞이며, 순서 자체가 의미를 갖는 문항은
shuffle: false로 고정할 수 있다. - 스테이지를 클리어하면 관련 챕터의 시험을 권한다. 경로를 손으로 찾게 하면 거기서 학습이 끊긴다.
- PostgreSQL 스테이지 판정 정정. 여러 피해자 세션을 한 행에 몰면 InnoDB와 달리 PostgreSQL은 튜플 락으로 대기를 직렬화해 범인이 아니라 중간 대기자를 blocker로 보고한다(실측: 피해자 4명일 때 범인은 4개 중 1개에서만 잡혔다). 피해자를 서로 다른 행으로 갈랐다.
- 랩 기동 직후의 준비 대기, 벤더별 클라이언트 표기, 접속 힌트 자동 생성, 오탐을 내던 정규식 하나를 고쳤다.
- 사후 분석(postmortem) 노트에서 해당 챕터로 연결된다.
벤더 브랜치
postgresql/mysql/oracle 세 브랜치를 이 릴리스 시점의 main에서 재생성해 push했다. 각 브랜치에서 마커 잔여 0, 비교표·부록·문제은행 무변형, 테스트 스위트 초록을 확인했다.
이번에 발견해 고친 것: 저장소 본문을 읽는 테스트가 자기도 모르게 "main 위에서 돈다"고 가정하고 있었다. 벤더 브랜치의 챕터는 이미 필터된 뷰라 마커가 0개인데, 스크립트는 *.md만 필터하므로 테스트는 그대로 실려 간다 — 그래서 세 브랜치의 스위트가 조용히 빨간 상태였다. main에서는 어떤 리뷰로도 재현되지 않고, 브랜치를 실제로 잘라 돌려 봐야만 드러난다. 이 규칙을 docs/dbms-branch-strategy.md에 적어 뒀다.
알려진 한계
발견되지 않은 버그가 아니라 알고 감수하는 경계다. 스테이지를 만들거나 판정에 기댈 때 여기를 넘지 마라.
판정 회피 (MySQL)
- 플레이어(
dba)에게는 튜닝 스테이지를 위해SYSTEM_VARIABLES_ADMIN이 있고, 그 권한이면 엔진과 같은 방법(SET SESSION sql_log_off = 1)으로 자기 명령을 로그에서 뺄 수 있다. - 명령 로그를 읽고 비우는 사이에 수 ms의 유실 창이 있다. 로그 테이블에는
DELETE가 막혀 있어(ERROR 1556) "읽은 지점까지만 지우기"가 불가능하므로 고칠 수 없다. 판정 대부분이 누적 목록이 아니라 최종 상태에 기대므로 실해는 거의 없지만, 타임라인에서 한 줄이 빠질 수 있다.
PostgreSQL 판정의 두 구멍 (MySQL에는 없다)
- 파싱 오류는 감시에 남지 않는다. 실측 결과 정확히 파싱 오류만 빠진다 — 없는 테이블 조회나 권한 오류는 잡히고,
KILL 999999(PG 문법이 아님)는 놓친다. - pid를 적지 않는 쓸기가 보이지 않는다.
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE ...형태는 문장에 숫자가 없어kill_precision이 잡지 못한다. 감점 대상으로 삼으려면 스테이지에서forbidden_command로 직접 막아야 한다.
커버리지 공백
- 스테이지 14개 중 MySQL 13 / PostgreSQL 1. Oracle 스테이지는 없다.
- PostgreSQL 스테이지를 하려면
psql클라이언트가 필요하다(./shoot doctor가 알려 준다). - 단답 채점의 허용 답안이 하나뿐인 문항이 남아 있어, 뜻이 같은 다른 표기를 오답 처리할 수 있다.
- 문항 벤더 표기가 전부
neutral인 은행이 2개 있다(01-beginner/01,03-advanced/06) —--dbms로 걸러도 이 은행은 항상 전부 나온다.
운영
- CI가 없다. 테스트 실행도, 벤더 브랜치 재생성도, 릴리스 발행도 전부 사람이 손으로 한다. 실행 코드가 외부 의존성 없는 Python 표준 라이브러리와 Bash뿐이라 유지할 파이프라인 자체가 얇다는 판단이다. 대신 릴리스 전 점검을 자동으로 막아 주는 장치도 없다.
요약
| v1.0.0 | v1.1.0 | |
|---|---|---|
| 챕터 | 31 | 31 |
| 문제은행 / 문항 | 23 / 216 | 23 / 216 (64문항 개정) |
| 스테이지 | 14 | 14 |
| 실행 진입점 | ./exam ./shoot |
./guide ./exam ./shoot |
| 테스트 | 426 | 557 |
커밋 51개. 전체 변경 이력: https://github.com/Ahngbeom/dba-guide/commits/v1.1.0
호환성: 더해지기만 했다. 제거되거나 의미가 바뀐 CLI 인자, 스키마 변경, 진행·결과 기록 형식 변경, 챕터 경로 변경 모두 없다.