Skip to content
[017]2026.06.03log

밀어 넣기와 끌어당기기

같은 기능인데 데이터가 흐르는 방향이 정반대였다

옵시디언 플러그인을 만들기로 했다.

옵시디언은 지식관리 앱이다. 유튜브를 학습에 쓰는 사람들 중 상당수가 옵시디언으로 노트를 관리한다. 스택튜브의 분석 결과를 옵시디언에 자동으로 넣어줄 수 있다면, 그 사람들에게 강력한 연결고리가 된다.

그런데 여기서 이상한 점이 있었다.

스택튜브에는 이미 옵시디언 출력 기능이 있었다. 분석이 끝나면 마크다운 파일을 옵시디언 폴더에 넣어주는 기능. 처음 만들 때부터 있었다. 그런데 왜 또 플러그인을 만들어야 하나?

관제탑에 이 질문을 던졌다. 기존 기능이 있는데 왜 플러그인이 필요한지.

돌아온 답이 흥미로웠다. "방향이 반대이기 때문입니다."

설명을 듣고 나서야 이해했다.

기존 옵시디언 출력 기능은 서버가 사용자의 옵시디언 폴더에 파일을 직접 써넣는 방식이었다. 설정에 폴더 경로를 넣으면, 서버가 그 경로에 마크다운을 저장한다. 서버가 폴더로 파일을 밀어 넣는다(push).

이건 V2 시절 — 그러니까 프로그램이 내 컴퓨터에서 돌던 시절 — 에는 완벽하게 작동했다. 서버가 곧 내 컴퓨터였으니까. 내 컴퓨터가 내 폴더에 파일을 쓰는 건 당연하다.

하지만 SaaS가 되면서 상황이 바뀌었다. 이제 서버는 클라우드에 떠 있다. 내 컴퓨터가 아니다. 그리고 클라우드에 있는 서버는 사용자 컴퓨터의 폴더에 손을 댈 수 없다. 당연하다. 만약 아무 서버나 내 컴퓨터 폴더에 파일을 쓸 수 있다면, 그건 심각한 보안 문제일 것이다.

그러니까 "서버가 사용자 폴더에 밀어 넣는" 방식은, SaaS에서는 근본적으로 불가능했다. 기존 기능이 로컬에서는 작동했지만 클라우드에서는 막혀 있었던 것이다.

여기서 방향을 뒤집어야 했다.

서버가 폴더로 밀어 넣을(push) 수 없다면, 폴더 쪽에서 서버로 끌어당기면(pull) 된다. 사용자의 옵시디언 안에서 도는 플러그인이, 스택튜브 서버의 API에 접속해서 분석 결과를 가져오는 것이다. 서버는 사용자 컴퓨터를 모르지만, 사용자 컴퓨터 안의 플러그인은 서버 주소를 알 수 있으니까.

밀어 넣기에서 끌어당기기로. push에서 pull로.

이 방향의 차이가 처음엔 사소해 보였다. 어차피 마크다운 파일이 옵시디언 폴더에 들어간다는 결과는 같으니까. 하지만 결과가 같아도 구조는 완전히 달랐다.

밀어 넣기 구조에서는 서버가 능동적이다. 서버가 "언제, 어디에" 파일을 쓸지 결정한다. 끌어당기기 구조에서는 플러그인이 능동적이다. 플러그인이 "언제, 무엇을" 가져올지 결정한다. 서버는 그저 "가져갈 수 있게 열어두는" 역할만 한다.

이 깨달음은 EP.02를 떠올리게 했다. 그때는 V2를 SaaS로 확장하려다 구조적 결함 6개를 만났다. "한 사람이 쓸 때는 문제없지만, 여러 사람이 쓰면 터지는" 문제들. 이번 push/pull 문제도 정확히 그 계열이었다. 로컬에서는 작동하지만, 호스팅되면 막히는 것.

다만 이번엔 달랐다. EP.02 때는 관제탑이 문제를 짚어줬다. 이번엔 내가 먼저 "왜 기존 기능이 있는데 플러그인이 필요하지?"라는 질문을 던졌다. 답을 몰라서 물은 게 아니라, 뭔가 이상하다는 감각이 먼저 왔다. 구조를 읽는 감각이 조금 자란 것이다. EP.06에서 "구조를 읽는 언어"를 배웠는데, 이제 그 언어로 스스로 질문을 만들 수 있게 됐다.

플러그인의 실제 구조는 단순했다. 서버 쪽에는 API 창구 하나만 추가하면 됐다. "이 시각 이후의 새 분석 결과를 마크다운으로 돌려줘"라는 요청을 받는 창구. 마크다운을 만드는 일(가치의 핵심)은 서버가 이미 하고 있으니, 그걸 열어두기만 하면 된다.

플러그인 쪽은 얇은 운반책이었다. API에서 새 노트를 가져와서, 파일명을 정리하고, 옵시디언 폴더에 저장한다. 중복은 영상 ID로 걸러낸다. 30분마다 자동으로 확인하거나, 수동으로 "지금 가져오기"를 누를 수 있다.

핵심은 "가치를 만드는 부분"과 "운반하는 부분"을 분리한 것이었다. 서버는 분석이라는 가치를 만들고, 플러그인은 그걸 운반한다. 각자 잘하는 일만 한다.

이 분리를 이해하고 나니, 앞으로 다른 도구들과 연동할 때도 같은 원리를 쓸 수 있겠다는 생각이 들었다. 노션이든, 다른 앱이든, "서버가 밀어 넣을 수 없으면 클라이언트가 끌어당긴다"는 원칙. 데이터가 흐르는 방향을 먼저 정하고, 그다음에 구조를 짠다.

만드는 것보다 방향을 정하는 게 먼저다. 방향이 틀리면 아무리 잘 만들어도 작동하지 않는다. 이건 코드의 문제가 아니라 설계의 문제이고, 설계는 코드를 모르는 사람도 — 아니, 어쩌면 코드를 모르는 사람이 오히려 더 잘 — 판단할 수 있는 영역이다.

밀어 넣을 수 없으면, 끌어당긴다. 간단한 원리 하나를 아는 데, 꽤 먼 길을 돌아왔다.

이렇게 플러그인의 구조는 정해졌다. 하지만 만드는 것과 내놓는 것은 또 다른 문제였다. 이 플러그인을 사람들이 쓰게 하려면, 옵시디언이라는 남의 마을에 가게를 내야 했다. 그건 다음 이야기다.


🔧 이 에피소드의 기술 용어 해설

Push vs Pull 데이터를 주고받는 두 가지 방향. Push는 보내는 쪽이 능동적으로 밀어 넣는 것. Pull은 받는 쪽이 능동적으로 끌어당기는 것. 같은 데이터 이동이라도 누가 주도하느냐가 다르고, 이 차이가 시스템 구조를 결정한다.

API 창구 (API Endpoint) 외부에서 데이터를 요청할 수 있는 주소. 플러그인이 이 주소에 요청을 보내면, 서버가 해당 데이터를 돌려준다. 이 에피소드에서는 "새 노트를 마크다운으로 돌려주는" 창구를 하나 새로 열었다.

클라이언트 (Client) 서버에 요청을 보내는 쪽. 여기서는 옵시디언 안에서 도는 플러그인이 클라이언트다. "얇은 클라이언트"란 복잡한 처리는 서버에 맡기고, 자신은 최소한의 운반 역할만 하는 가벼운 프로그램을 뜻한다.

폴링 (Polling) 클라이언트가 일정 주기로 서버에 "새로운 거 있어?"라고 반복해서 물어보는 방식. 플러그인이 30분마다 서버를 확인하는 것이 폴링이다. 서버가 먼저 알려주는 방식(push)의 반대.

관심사 분리 (Separation of Concerns) 서로 다른 역할을 각각 다른 부분이 맡게 하는 설계 원칙. 서버는 "가치 생성", 플러그인은 "운반"만 맡는 것. 각자 하나의 일만 하면 전체가 단순하고 튼튼해진다.