아무도 세지 않던 문
연습 모드는 기록을 건너뛰어서 무해해 보였습니다. 그런데 오늘 문제를 그대로 열고 정답까지 알려 줬습니다. 연습 세 번이면 본 게임 만점이었습니다.
DUGOUT 9은 KBO 팬을 위한 독립 프로젝트이고, 공개 데모로 열려 있습니다. 그 일부가 오늘의 3게임입니다. 매일 아침 공식 통산기록에서 새로 만들어지는 세 문제 — 소속팀 여정으로 선수 맞히기, 기록이 위인지 아래인지 부르기, 하나만 다른 선수 찾기. 같은 날이면 누구나 같은 세 문제를 받고, 결과는 시즌 점수와 연속 기록에 들어가며, 랭킹이 있습니다.
연습 모드도 있었습니다. 취지는 합리적이었습니다. 팬이 점수에 안 들어가게 몸을 풀 수 있게 하자. 요청이 이건 연습이다라고 말하면 서버는 채점만 하고 기록은 건너뜁니다. 아무것도 기록되지 않으니 제품에서 느슨하게 둬도 되는 구석으로 여겼습니다. 걸린 것이 없으니 지킬 것도 없다고.
연습이 실제로 내준 것
연습은 오늘 문제를 열었습니다. 같은 세 문제입니다. 그리고 틀리면 정답을 알려 줬습니다 — 연습 모드라면 당연히 하는 일입니다.
둘을 합치면 게임에 게임이 없었습니다. 연습 세 번이면 오늘의 답을 다 압니다. 그다음 본 게임을 하면 만점이 랭킹에 들어갑니다. 아무것도 쓰지 않아서 무해하다고 표시해 둔 모드가, 이 제품의 유일하게 값진 것 — 정답 — 을 묻는 누구에게나 내주는 자리였습니다.
«점수를 안 매기니까 안전하다»는 논리가 거꾸로였습니다. 점수를 안 매기기 때문에 안전하지 않았습니다. 기록되지 않는 요청은 아무도 세지 않고, 아무도 제한하지 않고, 아무도 알아차리지 않는 요청입니다. 쓰기가 없다는 것은 느슨해져도 되는 이유가 아니라, 문이 지키는 사람 없이 열려 있던 이유였습니다.
연습은 과거가 됐다
수정은 연습의 뜻을 바꾸는 것이었습니다. 이제 연습은 자기가 연습이라고 말하는 요청이 아닙니다. 지난 날짜의 문제를 여는 것입니다. 오늘의 답과 무관한 문제라면 정답을 보여 줘도 잃을 것이 없으니, 연습은 마음껏 너그러워도 됩니다. 오늘 문제는 기록될 요청에만 채점하고, 그리로 가는 편리한 무채점 경로는 지키는 대신 없앴습니다.
반가운 부수 효과가 있었습니다. 아카이브가 진짜가 됐습니다. 전에는 지난 날짜로 가는 모든 링크가 조용히 오늘 문제를 열었습니다 — 아카이브는 같은 세 문제를 가리키는 날짜 목록이었습니다. 이제 지난 날짜를 누르면 그날의 게임이 연습으로, 시즌 점수와 연속 기록 밖에서 열립니다.
그다음엔 아카이브가 샜다
수정 자체가 한 번 틀렸습니다. 아카이브를 열면서 «지난 날짜니까 얼마든지»라고 생각하고 창을 400일로 잡았습니다.
세 문제는 유한한 선수 풀에서 순번대로 만들어집니다. 순번을 충분히 거슬러 올라가면 되풀이됩니다 — 23일마다 같은 정답이 돌아옵니다. 그러니 23일 전의 문제를 여는 것은 오늘의 답을 읽는 또 하나의 방법이었습니다. 방금 닫은 문에 400일 너비의 두 번째 사본이 있었습니다.
창은 지금 2주입니다. 2주가 보기 좋은 숫자라서가 아니라, 정답이 되풀이되는 주기보다 짧기 때문입니다. 아카이브의 길이는 편의 설정이 아닙니다. 아카이브에 담긴 것의 반복 주기가 정합니다.
무엇을 기록하나가 아니라 무엇을 돌려주나로 나눈다
여기서 가져온 일반 규칙은 권한선을 어디에 긋느냐에 관한 것입니다. 본능은 요청을 무엇을 기록하나로 분류합니다. 쓰기는 위험하고, 읽기는 안전하고, 로그에 안 남는 읽기는 가장 안전하다고. 그 본능은 가치가 저장하는 것에 있는 제품에서는 괜찮습니다.
가치가 돌려주는 것에 있는 제품에서는 틀립니다. 게임, 시험, 추첨 — 정답이 곧 자산인 곳에서는 응답이 지켜야 할 그것이고, 세지 않고 그것을 돌려주는 요청은 무해한 경로가 아니라 가장 위험한 경로입니다. 세는 경로의 규칙을 전부 무의미하게 만들기 때문입니다.
그리고 생성되는 콘텐츠는 보이는 만큼 새롭지 않습니다. 문제가 유한한 소스에서 나온다면 «지난 것»과 «지금 것»은 다른 날짜에 놓인 같은 콘텐츠이고, 둘 사이의 거리는 계산할 수 있는 숫자입니다. 그것을 계산하지 않으면 과거로 난 문이 곧 오늘로 난 문입니다.