두 번째 화분을 올렸습니다 — 플랫폼 가설의 성적표
"두 번째 제품은 플러그인만 추가하면 된다." 온실을 지으며 걸었던 그 가설의 채점일이 왔어요. 캘린더가 올라갔거든요. 결과는 반은 맞고 반은 틀렸습니다.

온실을 지어놓고 1년 가까이, 화분은 하나뿐이었어요.
이 시리즈 0편에서 제가 쓴 문장이 있습니다. "두 번째 제품이 올라오는 날, 이 설계의 성적표가 나온다."
그날이 왔어요. calendar.arcacore.com — 캘린더가 올라갔습니다.
그래서 오늘은 채점을 하겠습니다. 제 설계의 채점을, 제가요.
두 번째 화분은 왜 캘린더였나
블로그 다음으로 줄 서 있던 건 다이어리, 계산기, 지도였어요. 그중 캘린더를 먼저 고른 건 이게 제일 만만해서가 아니라, 반대였습니다.
블로그 글은 발행하면 굳는 콘텐츠예요. 그런데 일정은 아니거든요. 만들고, 옮기고, 지우고, 다시 만들고 — 계속 살아 움직이는 데이터죠.
플랫폼이 블로그만 잘 담는 그릇이었다면, 여기서 티가 날 수밖에 없어요. 가설을 제일 아프게 때려볼 수 있는 후보였습니다.
(쉬운 걸로 검증하면 검증이 아니라 자축이잖아요.)
결정 하나: 로그인 없이 시작한다
일정 도구는 대개 가입부터 시키죠. 일정 하나도 안 만들어 본 사람한테요.
그래서 캘린더는 로그인 없이 바로 씁니다. 브라우저 안에 일정이 저장되고, 지도에 핀도 찍히고, 다 돼요.
대신 정직하게 말합니다. 이건 백업이 아니라고요. 브라우저를 비우면 사라진다고요.
그리고 로그인을 해도 자동으로 업로드하지 않아요. 로컬 일정을 미리 보여주고, 사용자가 "이걸 계정으로 옮기겠다"고 눌러야 옮깁니다. 옮기는 연산은 여러 번 눌러도 같은 결과가 되게 만들었고, 서버 쪽이 검증되기 전엔 로컬 원본을 지우지 않아요.
(자동으로 해주는 게 친절 같지만, 내 데이터가 나도 모르게 서버로 가는 건 친절이 아니죠.)
결정 둘: 캘린더를 공유해도 사이트 권한은 안 준다
공유 캘린더를 만들려니 권한 문제가 걸렸어요. 기존 플랫폼에는 이미 사이트 멤버십이 있었거든요. 그거 재활용하면 하루면 끝났을 겁니다.
그런데 그러면 "가족 일정 하나 같이 보자"고 초대한 사람에게 사이트 설정과 빌더 권한까지 딸려 가요.
그래서 캘린더 멤버십을 따로 만들었습니다. owner·editor·viewer 세 단계로, 딱 그 캘린더에 대해서만요. 캘린더 멤버라는 사실만으로는 플랫폼 쪽 명령을 하나도 부를 수 없어요.
결정 셋: 캘린더는 지도를 모른다
일정에 장소를 붙이려면 지도가 필요하죠. 지도 SDK를 캘린더 화면에서 그냥 가져다 쓰면 제일 빠릅니다.
안 했어요. 위치 기능을 따로 떼서 패키지로 만들고, 캘린더는 그 경계 너머만 봅니다.
이유는 두 개예요. 하나는 지도 업체를 갈아탈 때 캘린더가 안 흔들리게. 또 하나는 업체에 우리 일정 내용을 넘기지 않기 위해서요. 장소 검색은 장소만 물어봅니다. 일정 제목도, 설명도, 캘린더 이름도, 누가 멤버인지도 보내지 않아요.
그리고 검색한 장소는 이름·주소·좌표를 그 시점에 복사해 둡니다. 나중에 지도 업체가 장애가 나거나 바뀌어도, 지난 일정의 장소는 그대로 보여요.
그런데 블로그 글에 일정표를 넣고 싶어졌습니다
여기서 진짜 시험이 나왔어요. 블로그 글 안에 캘린더 일정표를 꽂고 싶었거든요.
제일 쉬운 길은 블로그가 캘린더 API를 부르는 거죠. 그리고 그 순간 두 제품이 서로의 내부에 묶입니다. 다음에 다이어리가, 그다음에 투표가 같은 요구를 하면 그때마다 짝을 지어 붙여야 하고요.
그래서 계약을 하나 더 만들었습니다. 블로그가 저장하는 건 "어느 제공자의, 어떤 공개본을, 어떤 방식으로 그린다"는 명세 한 줄뿐이에요. 캘린더가 자기 공개본을 소유하고, 블로그는 그 참조만 문서에 담습니다.
블로그 글을 발행해도 캘린더 일정을 복사하거나 잠그지 않아요. 글에 꽂았다고 해서 비공개 일정이 공개로 바뀌지도 않고요.
(계약서에 "캘린더"라는 단어가 안 나오게 쓰는 게 이 작업의 절반이었어요.)
채점: 반은 맞았습니다
가설은 "두 번째 제품은 플러그인만 추가하면 된다"였죠. 그래서 제일 먼저 확인한 건 플랫폼 코어였어요.
코어 패키지에서 "calendar"나 "blog" 같은 도메인 이름으로 갈라지는 분기를 찾아봤습니다. 0건이었어요. 조립기는 지금도 blog라는 단어를 모르고, 캘린더라는 단어도 모릅니다. 사이트 종류를 하나 추가하는 일은 청사진 플러그인 하나를 얹는 일이었어요.
배관은 값을 했습니다. 저장도, 게시도, 배포도, 인증도, 로그인 화면도 다시 만들지 않았어요. 블로그가 쓰던 걸 그대로 썼습니다.
채점: 반은 틀렸습니다
그런데 정직하게 말할게요. 일이 적지는 않았어요.
캘린더와 위치 기능을 위해 새로 만든 패키지가 열 개가 넘습니다. 도메인 모델, 정책, 저장소, 서버, 브라우저, 지도 업체 어댑터 둘, 공개본 서버, UI…
그러니까 "플러그인만 추가하면 된다"는 문장은 이런 뜻이 아니었어요. "적게 만들면 된다."
온실이 준 건 배관이지 화분이 아니었어요. 흙과 씨앗은 매번 새로 준비해야 합니다. 대신 물길을 다시 파지 않아도 되고, 온실 유리를 깨지 않아도 되죠.
저는 이 성적이 만족스러워요. 제가 걸었던 진짜 내기는 "다음 제품이 쉬워진다"가 아니라 "다음 제품이 코어를 망가뜨리지 않는다"였거든요. 그건 지켰습니다.
이 시리즈는 여기서 닫아요. 부탁 하나로 시작해서, 온실을 짓고, 혼자 만들며 앓았고, 두 번째 화분까지 올렸습니다. 캘린더 안쪽 이야기는 캘린더를 짓다 시리즈에서 따로 풀었어요.
(그리고 세 번째 화분이 이미 줄 서 있습니다. 다이어리요. 아, 그리고 지도도.)


