여러 저장소를 넘나들며 통합 릴리스를 준비하던 날

모바일 앱, 백엔드, 관리자 도구까지 세 개 저장소를 한 번에 묶어서 릴리스해야 하는 날이었습니다. 예전에 이런 큰 작업을 어떻게 나눴는지 궁금해서 옛날 설계 메모를 다시 열어봤습니다.

에이전트 하나가 다 하지 않고 역할을 나눌 때, 오케스트레이터와 워커

text
1orchestrator: 릴리스 순서·의존성 관리
2 ├─ worker: mobile-app 빌드
3 ├─ worker: backend 빌드
4 └─ worker: admin-tool 빌드
몇 달 전 남겨둔 메모에 이미 이 구조가 정리돼 있었습니다. 전체 순서와 의존 관계를 관리하는 역할과, 실제 작업 하나하나를 처리하는 역할을 나눠서, 한쪽이 지시하면 다른 쪽들이 각자 몫을 처리하는 구조였습니다. 전체 일정을 관리하는 공사 현장 소장과, 맡은 구간을 실제로 시공하는 각 팀으로 나뉘어 있는 셈이었습니다.
전체 순서를 관리하는 역할과 실제 작업을 처리하는 역할이 나뉜 구조
전체 순서를 관리하는 역할과 실제 작업을 처리하는 역할이 나뉜 구조
실제로 릴리스를 시작하니, 에이전트가 세 저장소 작업을 하나씩 다른 세션에 넘기는 걸 몇 번이나 반복해서 보게 됐습니다.

같은 패턴이 반복될 때, 이게 델리게이트라는 걸 알아챈 순간

text
1Delegating mobile-app build to worker session...
2Delegating backend build to worker session...
세 번 다 같은 문구가 뜨는 걸 보고 나서야, 이게 그때그때 다른 임기응변이 아니라 정해진 방식이라는 걸 알아챘습니다. 직접 처리하는 대신, 그 일을 잘 처리할 수 있는 다른 쪽에 맡기고 결과만 받는 것이 델리게이트였습니다. 팀장이 실무를 전부 직접 하지 않고 각 담당자에게 맡기는 것과 같은 이름이 여기서도 그대로 쓰이고 있었습니다.
직접 처리하지 않고 맡긴 뒤 결과만 돌려받는 반복되는 패턴
직접 처리하지 않고 맡긴 뒤 결과만 돌려받는 반복되는 패턴
백엔드 저장소 릴리스 노트를 준비하다가, 최근에 새로 연결한 도구 하나가 어떻게 우리 시스템에 붙는지 궁금해서 찾아봤습니다.

서로 다른 도구를 표준화된 방식으로 연결할 때, MCP

json
1{ "mcpServers": { "figma": {...}, "notion": {...} } }
검색해보니 이 약자는 모델과 외부 도구를 연결하는 공통 규격을 뜻했습니다. 각 도구마다 매번 다른 연결 방식을 새로 익힐 필요 없이, 정해진 하나의 규격만 따르면 어떤 도구든 연결할 수 있게 해주는 표준이었습니다. 전 세계 전자제품이 다른 플러그 모양 대신 표준 규격 콘센트를 쓰는 것과 비슷한 발상이라, 이름 자체는 낯설어도 개념은 금방 이해가 됐습니다.
서로 다른 도구를 표준화된 하나의 규격으로 연결하는 구조
서로 다른 도구를 표준화된 하나의 규격으로 연결하는 구조
관리자 도구 저장소를 정리하다가, 로그에 남은 라이브러리 출처 하나가 원래 알던 프로젝트와 링크가 다르다는 걸 발견했습니다.

같은 이름인데 원본이 아닐 때, 포크

text
1origin: github.com/our-team/chart-lib-fork
2(원본: github.com/original-author/chart-lib)
로그를 다시 확인해보니, 몇 달 전 팀에서 원본 라이브러리에 필요한 기능을 추가하려고 통째로 복제해서 우리만의 버전으로 갈라져 나왔던 흔적이었습니다.
원본 저장소를 그대로 복제해서, 이후로는 독립적으로 발전시켜 나가는 나만의 사본이 포크였습니다. 원본에 없는 기능을 우리 쪽에만 추가해뒀는데, 이번 릴리스에도 그 기능이 필요했습니다.
원본에서 복제된 뒤 독립적으로 갈라져 나간 사본
원본에서 복제된 뒤 독립적으로 갈라져 나간 사본
같은 나무에서 갈라져 나온 두 개의 가지를 그린 그림을 화면으로 확인하는 장면
세 저장소의 빌드가 모두 끝나고, 이제 정식으로 버전을 표시할 차례였습니다. 릴리스를 담당하는 동료가 절차를 알려줬습니다.

이번 버전을 나중에도 정확히 찾을 수 있게, 릴리스 태그

bash
1$ git tag v3.4.0
2$ git push origin v3.4.0
동료가 "커밋 번호는 기억하기 힘드니까 태그로 이름표를 박아두는 거야"라고 알려줬습니다.
수많은 커밋 중에서 "이게 정식으로 배포된 3.4.0 버전이다"라고 딱 짚어 표시해두는 이름표였습니다. 나중에 문제가 생겨도, 그 시점의 코드를 정확히 다시 꺼내볼 수 있었습니다.
수많은 커밋 중 정식 배포 지점 하나를 이름표로 딱 짚어두는 구조
수많은 커밋 중 정식 배포 지점 하나를 이름표로 딱 짚어두는 구조
마지막으로 관리자 도구 저장소 안에, 다른 팀이 관리하는 디자인 컴포넌트 저장소가 통째로 들어있는 걸 발견했습니다.

저장소 안에 또 다른 저장소가 통째로 들어있을 때, 서브모듈

text
1.gitmodules
2[submodule "design-kit"]
3 path = libs/design-kit
4 url = github.com/design-team/design-kit
공식 문서를 찾아보니, 이 폴더는 우리 저장소 소속이 아니라 다른 저장소를 특정 버전 그대로 참조만 하고 있었습니다.
독립적으로 관리되는 다른 저장소를, 내 저장소 안의 특정 폴더 자리에 특정 버전으로 통째로 끼워 넣는 방식이었습니다. 액자 안에 다른 사람이 그린 그림을 그대로 넣어 전시하는 것과 비슷했습니다. 이걸로 세 저장소의 통합 릴리스가 모두 끝났습니다.
독립적인 다른 저장소를 특정 버전으로 통째로 끼워 넣은 구조
독립적인 다른 저장소를 특정 버전으로 통째로 끼워 넣은 구조
늦은 오후, 세 개의 모니터에 릴리스 완료 화면이 나란히 떠 있는 것을 확인하는 장면
세 저장소의 릴리스는 같은 날 오후에 한꺼번에 나갔습니다. 저장소가 여러 개일 때 어려운 건 각각을 배포하는 일이 아니라, 어느 버전이 어느 버전과 짝이었는지를 나중에도 알아볼 수 있게 남겨두는 일이었습니다.

자주 묻는 질문

오케스트레이터가 죽으면 워커들은 어떻게 되나요?

진행 중이던 작업은 대개 계속 처리되지만, 전체 순서를 관리해줄 존재가 없어져서 다음 단계로 못 넘어가고 멈춥니다. 오케스트레이터 자체의 복구나 재시작 방법을 별도로 마련해두는 게 안전합니다.

포크한 라이브러리는 원본 업데이트를 계속 받을 수 있나요?

업스트림 저장소를 리모트로 등록해두면 새 버전을 받아올 수 있습니다. 다만 우리 쪽에서 따로 수정한 부분과 충돌이 나면 그때마다 손으로 맞춰야 합니다.

서브모듈은 항상 최신 버전을 자동으로 따라가나요?

아닙니다. 서브모듈은 특정 커밋 시점에 고정되어 있어서, 원본이 업데이트돼도 직접 갱신 명령을 실행하기 전까지는 그대로 유지됩니다.

<a href="/glossary/code-generation" class="glossary-link" title="AI가 자연어 설명이나 기존 코드 문맥을 바탕으로 프로그래밍 코드를 자동으로 작성하는 기술입니다.">AI 코딩</a> 도구 용어 사전 연작의 12편입니다. 다음 편 예고 · 13편 동시성 버그를 잡으려고 밤새 로그를 파던 날 플러그인 · 스킬 파일 · 자동 승인 모드 · 데드락 · 레이스 컨디션

관련 글