
AI 네이티브 개발 기반이 구축되기까지 — 레거시 재생의 과제·목표·순서·결과
요약
레거시 SaaS 시스템을 AI 네이티브 개발 체제로 전환하기 위한 전략적 재생 과정을 다룹니다. 테스트 부재, EOL, 성능 저하 등 기존 시스템의 문제를 진단하고, AI가 자율적으로 동작하는 기반을 구축하기 위한 단계적 접근법을 제시합니다.
핵심 포인트
- AI 네이티브화는 단순 도구 도입이 아닌 질서 있는 재생 프로젝트임
- 레거시 시스템의 정량적 분석(Due Diligence)이 선행되어야 함
- 테스트 자동화, 관측성 확보, 의존성 관리가 핵심 과제임
- AI가 자율 동작하고 인간이 리뷰하는 체제로의 전환 지향
서론
지난 기사 「AI 네이티브 개발에서 QCD는 어떻게 변했는가」에서는 AI 네이티브 개발의 상시 운용이 만들어내는 양과 질을 실측 데이터로 평가했습니다. 본 기사는 그 자매편으로서, 평가 대상이 된 「기반」이 어떻게 만들어졌는지—전체상을 다룹니다.
저희 회사는 지난 몇 달간, 오랜 기간 운용해 온 레거시 시스템을 「AI가 자율적으로 동작하고, 인간이 방침 판단과 리뷰를 담당하는」 체제로 재생해 왔습니다. 개별적인 기술 토픽—AI 멀티 세션(Multi-session) 운영, 리포지토리(Repository) 분할 설계 사상, 계측 문화로의 전환 등—은 그때마다 이곳에 기사로 작성해 왔습니다. 다만, 개별 기사만 읽으면 「흥미로운 시도들의 모음」처럼 보일지도 모릅니다. 실제로는 그것들은 하나의 척추 위에 나열된 공정입니다.
본 기사는 그 척추를 조망하는 총집편입니다. 무엇이 과제였고, 어떤 상태를 목표로 했으며, 어떤 순서로 추진했고, 최종적으로 어떻게 되었는지. 잘 된 판단뿐만 아니라 대가를 치른 판단까지 포함하여 하나의 이야기로 정리합니다. 몇 달간의 총괄이기에 긴 기사가 되겠지만, 레거시 시스템을 안고 AI 활용을 모색하고 있는 분들에게는 순서대로 가져가실 수 있는 내용이 되도록 구성했습니다.
먼저, 이 기사의 핵심을 한 문장으로 적어 두겠습니다.
AI 네이티브화란 개발 도구를 도입하는 것이 아니었습니다. 듀 딜리전스(Due Diligence) → 의사결정 → 테스트라는 안전망 → 기반의 재구축 → 단계적 릴리스(Release)라는
질서 있는 재생 프로젝트였으며, 그 순서 하나하나에는 이유와 때로는 대가가 있었습니다.
1. 무엇이 과제였는가
1-1. 오랜 세월의 퇴적
대상은 오랜 기간 운용해 온 코워킹 스페이스/쉐어 스페이스 관리 SaaS입니다. 회원 등록·체크인/체크아웃·결제·스마트 락 연동·LINE 연동까지 일괄적으로 처리하는 사업의 핵심 시스템입니다.
「레거시」라고 한마디로 치부하지 않고, 우선 AI로 듀 딜리전스(Due Diligence)를 실시했습니다. 그러자 체감상 「괴롭다」고 생각했던 것들이 정량적인 모습으로 드러났습니다.
테스트가 거의 존재하지 않음: 누적 450개 이상의 DB 마이그레이션(Migration)과 약 300개의 컨트롤러(Controller)에 대해 자동 테스트는 실질적으로 제로. 테스트용 데이터 생성기도 거의 미비하며, CI/CD도 없음. 즉 「변경이 시스템을 망가뜨리지 않았음」을 기계적으로 확인할 수단이 오랫동안 존재하지 않았음 -
EOL(지원 종료)의 퇴적: 웹 프레임워크·언어 런타임·프론트엔드 빌드 환경이 모두 지원이 종료된 버전. 보안 패치가 공급되지 않는 상태가 상시화되었고, 의존 라이브러리에도 알려진 취약점을 포함한 오래된 버전이 남아 있었음 -
성능 과제: 5초를 초과하는 슬로우 쿼리(Slow Query)가 하루 약 1,800건. 매년 비대해지는 거대 테이블에 인덱스(Index)가 미비하며, ORM의 N+1 쿼리가 다발적으로 발생. 무거운 화면은 「여는 데 수십 초, 때로는 타임아웃」이 일상이었음 -
관측성 결여: 모니터링은 서버의 CPU 사용률이 임계치를 넘으면 알림이 오는 인프라 계층뿐. 애플리케이션 내부에서 무엇이 일어나고 있는지—어떤 에러가, 어떤 화면에서, 어느 정도의 빈도로 발생하는지—를 알 수 있는 수단이 없어, 문제 탐지는 고객의 문의가 사실상 유일한 경로였음 -
보안 과제: 출력 이스케이프(Escape) 누락 잔존, 비밀 정보 관리 방법, 공유 계정 운용(조작자를 특정할 수 없음) 등 파악해야 할 논점이 다수 -
개별 업체 커스텀의 퇴적: 특정 고객을 위한 분기나 하드코딩된 식별자가 코드베이스 전체에 산재. 「이 줄을 바꾸면 어느 고객에게 영향을 주는가」에 대한 예측이 극도로 어려워, 변경할 때마다 조사 비용이 불어나는 구조였음 -
배포는 쉘 스크립트(Shell Script) 수동 실행: 여러 서버로 순차적으로 파일을 배포하고 프로세스 재시작 시 순간 단절이 발생하는 방식. 롤백(Rollback)은 「커밋을 되돌리고 재배포」. 24시간 영업하는 점포를 다수 보유한 서비스로서는 심야라 할지라도 「무풍의 배포 시간대」가 존재하지 않음
1-2. 「건드릴 수 없는 시스템」의 역학
개별 과제보다 심각했던 것은 이것들이 결합되어 만들어내는 역학입니다.
테스트가 없으니 변경이 두렵다. 변경이 두려우니 최소한의 패치(Patch)만 적용한다. 패치의 축적으로 구조는 더욱 복잡해지고, 점점 더 변경이 두려워진다. 성능 문제는 「무거운 건 원래 그래」라며 운용으로 넘기고, 관측성이 없으니 개선 우선순위도 감으로 결정할 수밖에 없다—모두 레거시 시스템을 안고 있는 현장이라면 낯익은 악순환일 것입니다.
이 악순환의 출구로 일반적인 것이 「만들기 다시(리뉴얼)」입니다. 저희 회사도 그 길을 선택하여 풀 리뉴얼(Full Renewal) 버전의 개발 프로젝트를 진행하고 있었습니다.
1-3. 리뉴얼의 정체와 경영 판단
하지만 리뉴얼 버전으로의 이행을 구체적으로 검토하는 단계가 되었고, 품질과 이행 리스크를 실측 평가한 결과——후술할 E2E 테스트 메커니즘을 리뉴얼 버전에 적용하여 품질 실태를 검증했습니다——이행을 중지하고, 현행 시스템을 재생한다는 경영 판단을 내렸습니다.
만들다 만 신규 시스템을 멈추고, 오랫동안 사용해 온 레거시(Legacy)에 다시 투자한다. 글로 쓰면 간단하지만, 매몰 비용(Sunk Cost, 이미 투입된 비용)을 끊어내고 판단하는 것은 결코 쉽지 않습니다. 이 판단을 내릴 수 있었던 데에는 두 가지 지지대가 있었습니다.
하나는 의사결정 방식입니다. 단 한 번의 회의로 결정하지 않고, 약 2주에 걸쳐 「현행을 버리지 않고 돌아올 길을 남긴다」 → 「이행을 멈춘다」 → 「신구 시스템의 상세 비교」 → 「현행 시스템 단일화」와 같이, 철수 가능한 작은 결정들을 단계적으로 쌓아 올리며 수렴시켰습니다. 큰 방침 전환일수록 각 단계를 가역적(Reversible)으로 유지하는 것이 결과적으로 더 빠르고 견고하게 결정된다는 것을, 나중에 기술의 릴리스(Release) 전략과 같은 구조라는 것을 깨달았습니다.
또 하나는 AI를 통한 듀 데일리전스(Due Diligence, 실사)입니다.
1-4. AI 듀 데일리전스 — 「건드릴 수 없는 것」이 「건드릴 수 있는 것」으로 변한 순간
현행 코드베이스를 성능, 보안, 개별 고객 사양, 구성이라는 4가지 관점에서 병렬적으로 AI 조사를 수행했습니다. 인간이라면 수 주일이 걸릴 규모의 자산 파악(Inventory)이 단 며칠 만에 끝났으며, 게다가 망라적이었습니다. 전절까지 언급한 정량적인 과제들의 모습은 바로 이 조사의 산물입니다.
결정타가 된 것은 과제의 나열이 아니라 **공수 산정(Estimation)**이었습니다. 「DB 부하 개선」, 「프레임워크의 메이저 버전 업데이트」, 「테스트 도입」, 「개별 고객사 하드코딩 해소」, 「대형 신기능 구현」과 같은 주요 개수(改修) 계통별로 AI 체제에서의 견적을 낸 결과, 모두 수 주에서 10주 정도라는 현실적인 수치 안에 들어왔습니다. 기존 체제에서는 「무서워서 건드릴 수 없다」라는 한마디로 끝나버렸던 레거시가, AI의 등장으로 인해 「견적을 낼 수 있는 자산」으로 변했습니다. 리뉴얼 중지라는 경영 판단은 이 견적이 있었기에 비로소 성립할 수 있었습니다.
장 끝의 증류: 레거시 재생인가 새로 만들 것인가의 판단은 감각이 아닌 실측으로 내릴 수 있다. AI는 코드를 쓰기 전에, 먼저 「의사결정의 재료를 갖추는 도구」로서 효과적이었다. 그리고 큰 방침 전환은 철수 가능한 작은 결정의 축적으로 설계한다.
2. 어떤 상태를 목표로 했는가
2-1. 5가지 목적
재구축 계획에서는 목적을 5가지로 세웠습니다.
- 보안 및 퍼포먼스 문제 해소
- AI 네이티브 개발의 기반 구축
- 추가 기능 개발의 가속화
- 배포 사고의 억제와 영향 범위의 한정
- 개별 고객용 기능 및 새로운 제공 형태에 대한 대응
1, 3, 4, 5번은 레거시 재생 프로젝트라면 보편적으로 꼽히는 항목들일 것입니다. 특징적인 것은 2번을 독립된 목적으로 명시했다는 점입니다. 단순히 오래된 부분을 고치는 것이 아니라, 「AI가 안전하게 자율 주행할 수 있는 구조」 그 자체를 목표로 삼았습니다.
2-2. 「AI가 안전하게 자율 주행할 수 있는 구조」의 요건
AI의 생산성은 모델의 똑똑함만으로 결정되지 않습니다. 이번 시도를 통해 확신한 것은 다음 4가지 조건에 대한 의존도가 극히 높다는 점입니다.
- 검증이 자동화되어 있음: AI의 변경이 올바른지를 AI 스스로가 기계적으로 확인할 수 있어야 한다. 테스트가 없다면 AI의 출력은 매번 인간이 육안으로 확인해야 하므로 자율 주행은 성립하지 않는다.
- 환경이 재현 가능함: 동일한 환경을 코드를 통해 몇 번이고 다시 만들 수 있어야 한다. 검증을 위해 환경을 일회용으로 사용할 수 있는지 여부에 따라 시도할 수 있는 가설의 수가 차원이 달라진다.
- 관측 가능함: 운영 환경에서 무엇이 일어나고 있는지를 로그와 메트릭스(Metrics)를 통해 기계 판독 가능한 형태로 취득할 수 있어야 한다. 이것이 없으면 릴리스 후의 정상성 확인도 장애 조사도 AI에게 맡길 수 없다.
- 문맥(Context)이 닫혀 있음: 하나의 변경을 이해하는 데 필요한 코드와 지식이 하나의 리포지토리(Repository), 하나의 책임 범위 안에 담겨 있어야 한다. 컨텍스트 윈도우(Context Window)라는 물리적 제약을 가진 AI에게 이는 인간보다 훨씬 더 중요하다.
돌이켜보면, 이것들은 「인간에게도 좋은 환경」의 조건 그 자체입니다. 즉, 레거시 해소와 AI 네이티브화는 별개의 투자가 아니라 하나의 동일한 투자였습니다. 차이는 우선순위를 매기는 방식뿐입니다. 인간 팀이라면 「있으면 좋은 것」으로 치부되어 뒤로 밀리기 쉬운 자동 테스트나 환경 재현성이, AI 체제에서는 「없으면 시작조차 할 수 없는」 최우선 사항으로 격상됩니다.
2-3. 하드 포크(Hard Fork) 분할 — DRY의 재검토
설계 면에서 가장 대담한 결단은 모놀리스(Monolith)의 하드 포크 분할입니다.
하나의 모노레포(Monorepo)를 제공 채널별(LP·Web 회원 화면·LINE·스마트폰 앱용 API·매장 관리·전체 관리·배치 그룹 등)로 약 10개의 리포지토리(Repository)로 분할했습니다. 방법은 "공통 부분을 라이브러리로 분리하여 참조하는 것"이 아니라, "모든 리포지토리에 모노레포 전체를 복사한 다음, 각 리포지토리의 책무에 불필요한 부분을 깎아내는 것"입니다.
코드 중복을 대량으로 허용하므로, DRY(Don't Repeat Yourself) 원칙에는 명백히 위배됩니다. 공통 로직의 수정은 여러 리포지토리에 걸쳐 수평 전개하는 작업이 되며, 실제로 그 수평 전개 과정에서 실패했던 경험도 과거 기사에 썼습니다. 그럼에도 이 방식을 선택한 이유는 AI 시대에는 저울의 무게추가 바뀌었기 때문입니다.
- 공유 라이브러리 방식은 변경 영향이 모든 서비스로 파급됨 = "문맥이 닫혀 있다(Context is closed)"라는 조건을 깨뜨림
- 하드 포크(Hard Fork) 방식은 리포지토리 단위로 문맥이 완결됨. AI는 눈앞의 리포지토리만 이해하면 안전하게 변경할 수 있음
- 중복 관리 비용(동일한 수정의 수평 전개)은 AI에게는 특기 분야이며, 기계적 대조와 리뷰를 통해 담보할 수 있음
"중복 관리 비용"이 AI에 의해 급감한 결과, "느슨한 결합(Loose Coupling)의 가치"가 상대적으로 승리하게 되었다는 판단입니다(설계 사상의 상세 내용은 별도 기사에 작성했습니다).
2-4. 진행 방식의 모토
진행 방식의 모토는 "작고 빠르게 단계적으로, 안전 조치를 취하면서"입니다. 구체적으로는 다음과 같은 운영 원칙으로 구체화했습니다.
- 현행 환경에는 손을 대지 않고 운영을 지속하며, 병행하여 신규 환경을 구축하고 단계적으로 이행한다.
- 모든 공정에서 "되돌아갈 길"을 확보한다(구 환경은 삭제하지 않고 퇴역시키며, 릴리스는 즉시 롤백(Rollback) 가능한 방식만 채택).
- 큰 변경은 반드시 파일럿(Pilot, 최소 대상)을 통해 절차를 확립한 후 수평 전개한다.
장 끝의 증류: 목표로 한 것은 "깨끗한 시스템"이 아니라 "AI가 안전하게 자율 주행할 수 있는 시스템"입니다. 목표를 그렇게 정의하면 DRY와 같은 기존 원칙도 재검토할 여지가 생깁니다. 그리고 AI에게 필요한 환경 조건은 사실 인간에게도 이상적인 환경 조건이었습니다.
3. 어떤 순서로 진행했는가
이 부분이 본 기사의 핵심입니다. 수개월간의 노력을 시책 간의 연결 고리로 정리하면 다음과 같은 순서가 됩니다(가독성을 위해 일직선으로 재구성하였으며, 실제로는 병행되거나 전후가 바뀐 부분이 있습니다).
3-1. 듀 딜리전스(Due Diligence)와 의사 결정 (첫 1개월)
1장에서 썼듯이, 첫 약 1개월은 현행 시스템의 자산 조사(Inventory)·개수 로드맵 수립·리뉴얼 이행 중단 의사 결정에 할애했습니다. 코드를 한 줄도 바꾸지 않은 기간이지만, 여기서 만든 "과제 전체 리스트"와 "계통별 공수 산정"이 이후 모든 공정의 지도가 되었습니다.
간과하기 쉽지만, 이 기간에는 AI 측의 기반 정비도 포함되어 있습니다. AI가 코드베이스·AWS·태스크 관리·문서에 안전하게 접근할 수 있는 환경(읽기 전용 권한으로부터의 단계적 개방, 조작 로그 확보)을 먼저 갖추었습니다. "AI에게 무엇을 어디까지 허용할 것인가"를 임기응변식으로 결정하면 나중에 반드시 사고가 발생합니다. 권한 설계는 프로젝트 첫날에 해야 할 일이었습니다.
3-2. 현행 사양 파악과 E2E 테스트 정비
의사 결정 다음에 착수한 것은 코드 수정이 아니라 테스트입니다.
사양서가 없는 오래된 시스템에서는 "지금 무엇이 올바른 동작인가"에 대한 정의부터 시작해야 합니다. 절차는 다음과 같습니다. 먼저 AI에게 실제 화면을 조작하게 하면서 사용자 매뉴얼(=살아있는 사양서)을 작성합니다. 그다음 그 매뉴얼과 코드를 통해 테스트 관점(수백 건)을 망라적으로 도출합니다. 관점을 실행 절차(수천 단계)로 전개합니다. 그리고 브라우저 조작을 포함한 E2E(End-to-End) 테스트로서 AI가 실행하고 결과를 기록하는——이러한 파이프라인을 정비했습니다. 테스트 결과는 단순한 합격/불합격의 이진(Binary) 값이 아니라 "합격/확인 필요/불합격"의 3진법으로 관리하며, "확인 필요" 항목을 인간과의 대화를 통해 사양으로 확정함으로써 사양서와 테스트가 동시에 성장하는 구조로 만들었습니다.
이것이 이후 모든 공정의 안전망이 됩니다. 이 뒤에 이어지는 대규모 코드 삭제도, 버전 업그레이드도, 구조 변경도, "E2E 테스트가 계속 통과하는 것"을 회귀(Regression) 판정 기준으로 삼을 수 있었기에 AI에게 대담한 변경을 맡길 수 있었습니다. 반대로 말하면, 이 안전망보다 먼저 코드를 건드리기 시작했다면 어느 지점에서 반드시 "망가뜨린 것을 인지하지 못하는 변경"이 쌓였을 것입니다.
또한, 이 E2E 테스트 실행과 코드 조사에는 방대한 시간과 AI 토큰이 소비되었습니다. 전용 MacBook 1대를 AI에게 할당하고, 최상위 플랜의 구독을 계약하며, 외출 시에는 스마트폰으로 진행 상황을 모니터링하고 지시하는 체제를 구축했습니다. 브라우저를 실제로 조작하는 E2E 테스트는 건당 부하가 커서, 수천 단계의 실행은 말 그대로 밤낮을 가리지 않고 계속 돌려야 합니다. 기반 투자로서는 저렴하지 않지만, 이 안전망 없이는 후속 공정이 성립되지 않았기에 가장 먼저 투자하기를 잘했다고 생각합니다.
3-3. 리포지토리 분할과 불필요한 코드 삭제
안전망이 마련된 시점에서, 2장에서 기술한 하드 포크(Hard Fork) 분할을 실행했습니다.
모든 리포지토리에 모노레포(Monorepo) 전체를 복사한 뒤, 리포지토리마다 "이 서비스는 무엇에 응답하고 무엇을 제공하는가"라는 동작 정의를 명문화했습니다. 그 정의에 비추어 불필요한 코드를 "루트 정의 → 컨트롤러 → 서비스 → 모델 → 의존 패키지" 순으로, 바깥쪽에서 안쪽 방향으로 깎아 나갑니다. 이 순서가 중요한데, 입구(루트와 컨트롤러)를 먼저 끊어내면 안쪽의 코드는 "어디에서도 호출되지 않음"을 기계적으로 판정할 수 있어 삭제의 안전성이 높아집니다. 입구 삭제만으로 코드베이스의 6~7할을 덜어낼 수 있다는 전망이 섰고, 실제로 누적으로 수백만 행을 삭제했습니다.
이 삭제 공정은 AI 멀티 세션 운영의 첫 번째 본격적인 실전이기도 했습니다. 여러 AI 세션을 병렬로 실행하여 각각 리포지토리를 담당하게 하고, 인간은 방침 판단과 리뷰에 집중합니다. 3일 만에 270만 행을 삭제했을 때의 운영 원칙은 과거 기사에 자세히 적어두었습니다.
순서의 핵심은 버전 업그레이드 전에 삭제를 마쳤다는 점입니다. 코드가 6할 줄어들면, 버전 업그레이드 시 신경 써야 할 대상도 6할 줄어듭니다. "청소하고 이사한다"는 가사 노동의 철칙이지만, 코드베이스에서도 마찬가지였습니다.
3-4. 버전 업그레이드 — EOL로부터의 탈피
이어서 언어·프레임워크·라이브러리의 버전 업그레이드입니다.
여기서는 "파일럿 → 수평 전개" 패턴을 사용했습니다. 우선 영향이 가장 적고 규모가 작은 리포지토리 1개를 대상으로, 프레임워크의 메이저 버전을 여러 단계 뛰어넘는 업데이트 절차를 확립합니다. 파괴적 변경(Breaking Changes) 목록화, 의존 패키지 호환성 확인, 설정 파일의 서식 변경, 테스트를 통한 회귀 확인(Regression Check) 등의 절차서를 AI와의 공동 작업을 통해 공고히 한 뒤, 나머지 리포지토리로 수평 전개합니다. 첫 번째 리포지토리에 지불한 학습 비용을 나머지 전체에서 회수하는 구조입니다.
테스트라는 안전망과 삭제를 통해 가벼워진 코드베이스 덕분에, 모든 리포지토리의 EOL(End of Life) 탈피를 단기간에 완료할 수 있었습니다. 쌓여있던 부채 중에서도 "언젠가는 해야 한다"라고 계속 말하면서도 손대지 못했던 최우선 항목이 프로젝트 전반부에 해결된 것은, 팀의 심리적인 면에서도 큰 전환점이었습니다.
3-5. 배포 파이프라인과 IaC — 토대 정비
인프라는 기존 환경을 개수하는 것이 아니라 처음부터 다시 만들었습니다.
Terraform으로 모든 환경을 코드 관리(IaC)하고, 공유 모듈 + 환경 정의라는 구조를 통해 "개발 → 스테이징 → 운영"의 3개 환경을 동일한 코드로부터 생성할 수 있도록 했습니다. 이 시점에서 환경명·도메인명·네트워크 CIDR·리소스 명명 규칙도 일괄 정리했습니다. 레거시 환경의 "역사적 경위로 이렇게 되어 있는" 네임스페이스는 그 자체로 인지 부하이며, AI에게는 오작동의 리스크 원인입니다. 이름이 규칙적이라면 AI는 "dev 설정으로부터 stg 설정을 규칙에 따라 도출"할 수 있고, 리뷰도 차이점(diff)만 확인하면 됩니다.
배포는 GitHub Actions를 통한 CI/CD로 이행하였고, 후술할 컨테이너 기반 위에서 Blue/Green 배포를 확립했습니다. IaC를 선택한 이유의 절반은 AI와의 친화성입니다. 인프라가 코드라면 AI가 차이점을 리뷰할 수 있고, 변경 계획(plan)을 실행 전에 명시할 수 있습니다. 인간이 콘솔을 직접 조작하는 운영은 AI 입장에서 "관측할 수 없는 블랙박스"가 되어 버립니다. 역설적으로 말하면, IaC화란 인프라를 AI의 가독 범위 안으로 넣는 작업이었습니다.
초기 구축은 모듈 설계를 포함하여 실질적으로 하루 만에 끝났습니다. 수십 개의 Terraform 코드를 AI가 작성했고, 코드 리뷰는 AI(GitHub Copilot)와 인간이 이중으로 수행했습니다. 이후 이 기반은 검증용 환경을 단 하나의 PR로 일회성 구축하는(실례) 것과 같은 배당을 계속해서 만들어내고 있습니다.
3-6. 컨테이너화와 스테이트리스(Stateless)화
애플리케이션은 EC2 상의 상주 프로세스에서 ECS Fargate 상의 컨테이너로 이행했습니다. 그 전제로 필요한 것이 스테이트리스(Stateless)화——'이 서버가 아니면 동작하지 않는다'는 상태의 해체입니다.
세션 정보: 서버 로컬 → Redis. 어떤 컨테이너가 요청을 받더라도 동일한 세션을 참조할 수 있도록 -
이미지·CSV 등의 파일: 로컬 디스크 → S3. 파일 저장소가 컨테이너의 생사와 무관하게 -
로그: 로컬 파일 → CloudWatch Logs. 컨테이너가 사라져도 로그는 남으며, 횡단 검색이 가능해짐 -
정기 실행 작업 (Job): 서버 상의 cron → 스케줄 기반으로 기동되는 컨테이너 태스크. 실행 이력과 출력이 기계 판독 가능(Machine-readable)하게 -
이를 통해 오토스케일링(Auto-scaling)과 Blue/Green 배포를 적용할 수 있게 되었으며, '배포할 때마다 순간적인 단절이 발생하는' 구조에서 '중단 없이 신구 버전을 전환하고, 문제가 발생하면 즉시 구버전으로 되돌릴 수 있는' 구조가 되었습니다. 데이터 이행(로컬에서 S3로의 이미지 이행 등)은 참조 경로의 추상화 → 이중 쓰기(Double writing) → 이행 → 구 경로 폐지의 단계를 거쳤습니다.
이 스테이트리스화에는 부산물이 있습니다. 로그가 CloudWatch로 집약된 것은 이후 문의 전 탐지 메커니즘이나, AI에 의한 릴리스 후 모니터링의 토대가 되었습니다. 관측성(Observability)은 그것 단독으로 만드는 것이 아니라, 인프라 쇄신의 설계 단계에 녹여두어야 하는 것이었다는 점을 실감했습니다.
3-7. DB와 데이터 관리·권한 정비
데이터베이스 주변도 같은 사상으로 다시 만들었습니다.
마이그레이션(Migration) 정비: 스키마 변경을 모두 마이그레이션 코드로 다시 관리하여, 3개 환경에서 동일한 절차와 동일한 결과가 나오도록 보장 -
데이터 관리 전용 컨테이너: DB 조작(조사 쿼리·수정·마이그레이션 적용)을 전용 컨테이너를 통해서만 수행하도록 일원화. 개인 PC에서 운영 DB로 직접 연결하는 경로를 차단하여 조작 로그가 반드시 남는 구조로 구축 -
운영 환경을 모사한 마스킹 데이터: 검증 환경에는 개인정보를 마스킹한 운영 환경 수준의 데이터를 투입. '개발 환경에서는 데이터가 적어서 재현되지 않는다'는 문제를 해결하고, 운영 환경에 준하는 데이터 양과 형태(Shape)로 테스트할 수 있도록 함 -
DB 계정과 IAM 권한 정리: 읽기 전용/쓰기/관리 등 역할별로 계정을 분리하고 개인의 IAM과 연결. '누가(어떤 AI 세션이) 언제 무엇을 했는지' 추적 가능하게 함
스테이트리스화(3-6)와 이 권한 정리는 사실 또 다른 포석이기도 합니다. 로그와 권한이 정리되어 있다면, 시장 트러블의 1차 조사를 엔지니어 이외의 인원(혹은 AI)에게 개방할 수 있습니다. '운영 상태를 안전하게 읽을 수 있는' 경로가 정비됨으로써, 실제로 그 후 CS 멤버의 문의 조사를 AI가 지원하여, 기존에는 며칠씩 걸리던 에스컬레이션(Escalation)이 30분 만에 완결되는 체제(과거 기사)로 이어졌습니다. 엔지니어링 투자가 직종 간의 경계를 허무는 방향으로 작용한 사례입니다.
3-8. 보안 강화 — 그리고 대가
출력 이스케이프(Escape)의 철저화, 인증·인가(Authentication/Authorization) 주변의 엄격화, 비밀 정보 관리 방법의 시정(하드코딩 제거 및 시크릿 관리 서비스로의 이행), 공유 계정 폐지 등, 듀 디리전스(Due Diligence)에서 지적된 보안 과제들에 대한 리팩토링을 진행했습니다.
솔직히 말하자면, 여기서는 대가도 치렀습니다. 처리를 엄격하게 만든 결과, 지금까지 '느슨함' 위에서 성립되었던 일부 기능이 동작하지 않거나, 에러 발생 시의 동작이 변하여 UX가 악화되는 등, 릴리스 후 긴급 수정에 쫓기는 시기가 있었습니다.
예를 들어 인증 검증을 엄격화하면, 지금까지 '어찌어찌 통과되었던' 에지 케이스(Edge case)의 사용자 동선이 명확한 에러로 나타납니다. 보안 관점에서는 올바른 변경이라 할지라도, 해당 에러 화면에 복귀 경로가 없다면 사용자에게는 '어제까지 사용 가능했던 것이 사용할 수 없게 된' 경험이 됩니다. 보안과 비용, 그리고 UX는 트레이드오프(Trade-off)의 삼각형 관계에 있으며, '엄격하게 하면 안전하다'는 단순한 문제가 아닙니다. 엄격하게 할 것이라면, 그 동작 변화를 탐지할 수 있는 테스트와 사용자가 막다른 길에 다다르지 않도록 하는 복귀 경로를 세트로 준비했어야 했습니다. 이는 지난번 QCD 기사에서 다룬 대책(fail-close 시의 복귀 경로 설계 기준화)으로 교훈으로서 이어지고 있습니다.
3-9. 대규모 신기능 — 다거점 관리 구현
기반 정비와 병행하여, 여러 거점을 일원 관리하는 대형 신기능을 구현했습니다. 요구사항 정의부터 서비스별 구현·테스트까지, 관리 화면·회원 화면·LINE·외부 연동 순으로 AI 세션(AI session)을 통해 진행하고 있습니다. 기반 정비에서 확립한 「파일럿(Pilot) → 수평 전개」「서비스 단위로 구현하고 dev 환경에서 수시로 QA」 패턴이 신기능 개발에서도 그대로 기능했습니다.
여기에도 판단의 분기점이 있습니다. 원칙론적으로 말하자면, 인프라 쇄신과 신기능 추가를 같은 시기의 릴리스에 포함하는 「빅뱅 릴리스(Big Bang Release)」는 피해야 합니다. 인프라만 먼저 전환하여 안정화시키고, 기능 추가는 나중에 진행하는 것이 정석일 것입니다. 하지만 그 경우, 릴리스 전 테스트와 릴리스 후 안정화에 소요되는 기간만큼 신기능 제공이 수 주간 지연됩니다. 당시 리뉴얼 이행 중단으로 인해 이 기능의 제공을 기다리고 계시던 고객이 여러 분 계셨습니다. 이번에는 최단 거리로 도달하는 길——기반 쇄신과 신기능을 근접하게 출시하는 길——을 선택했습니다.
결과적으로, 릴리스기의 부하(다음 절) 중 일부는 이 선택에서 기인합니다. 그럼에도 불구하고, 교과서적인 정답과 사업적 요청이 충돌했을 때 어느 쪽의 대가를 치를지 자각적으로 선택한다. 그것이 가능하다면 원칙에서 벗어나는 것 자체가 악은 아니라고 생각합니다. 나쁜 것은 무자각하게 원칙을 어겨서 예상치 못한 대가에 놀라는 것입니다.
3-10. 단계적 릴리스 — 약 3주간의 전환
운영 환경 전환은 일제히 진행하지 않고, 도메인(서비스) 단위의 단계적인 전환으로 진행했습니다.
- 영향이 작은 서비스부터 순차적으로 DNS 전환을 통해 신규 환경으로 이행
- 영향이 큰 서비스는 로드 밸런서(Load Balancer)의 가중치를 사용한 카나리 릴리스 (Canary Release). 신규 환경으로의 트래픽 비율을 수 %부터 시작하여 단계적으로 높이며, 각 단계에서 에러율·응답 시간을 확인한 후 다음 단계로 진행
- 배치 처리(Batch Process)는 구 환경의 정기 실행을 중단하고 신규 환경의 스케줄러를 기동하는 전환을 잡(Job) 단위로 순차 실시
릴리스 후에는 AI가 정기 순회하며 로그·메트릭(Metrics)을 모니터링하고, 문제를 감지하면 「롤백(Rollback)인가, 최속의 핫픽스(Hotfix)인가」를 수시로 판단합니다. 카나리의 장점은 롤백이 「가중치를 되돌리는 것뿐」인 단순한 조치라는 점이지만, 실제로는 되돌리는 것보다 고치는 것이 더 빠른 상황도 많아, 감지 후 수 시간 이내의 핫픽스로 전진하며 수렴시키는 패턴이 주력이 되었습니다. 문제 발생과 해소의 속도를 보며 릴리스 계획 자체를 매일 조정하며, 모든 서비스의 전환 완료까지 약 3주가 소요되었습니다.
이 기간은 솔직히 말해 힘든 시기였습니다. 전환에 따라 크고 작은 결함이 현재화되어 고객에게 불편을 끼치는 상황이 계속되었습니다. 신규 환경에서 처음으로 운영 부하를 받아 드러나는 문제, 이행된 설정의 불일치, 그리고 오랫동안 코드에 잠복해 있다가 환경이 바뀌면서 표면화된 기존 버그——원인은 다양하지만, 고객 입장에서 보면 모두 「전환했더니 상태가 안 좋다」는 것입니다.
그리고 최전선에 서는 것은 엔지니어뿐만이 아닙니다. 문의를 받아내는 CS, 고객과의 관계를 책임지는 PdM에게도 물리적으로나 정신적으로나 부하가 큰 3주였습니다. 기술적으로는 「단계적 릴리스로 영향 범위를 한정할 수 있었다」고 총괄할 수 있지만, 단계적 릴리스는 「사고를 작게 만드는」 수법이지 「사고를 제로로 만드는」 수법은 아닙니다. 전환 계획에는 기술 계획과 동일한 해상도로 팀의 부하 계획——문의 증가를 고려한 CS 체제, 우선순위 판단의 권한 위임, 경영진에 대한 기대치 조정——을 포함했어야 한다는 것이 이 기간의 가장 무거운 반성입니다.
3-11. 운영의 정착화 — 모니터링 강화와 비용 최적화
전환 완료 후에는 운영의 정착화 단계입니다.
- 관측성(Observability) 강화: 프론트엔드의 크래시(Crash)를 서버 측에서 포착하는 텔레메트리(Telemetry) 신설, 화면 표시 대기 시간 측정, 릴리스 후의 정량적 모니터링(에러 건수·응답 시간 실측 확인)의 표준화. 「문의가 오기 전에 감지하여 고친다」는 경로가 주력이 됨
- 측정에 기반한 퍼포먼스 튜닝(Performance Tuning): 슬로우 쿼리(Slow Query)의 인덱스 설계, 쓰기 잠금(Write Lock) 경합 해소, 무거운 화면의 비동기화. 45초 걸리던 화면이 2.7초로, 7초 걸리던 목록이 0.5초로 개선되는 과정을 「측정 → 개수 → 실측 확인」 사이클로 쌓아 올림
- AWS 비용 최적화: 신구 환경의 병행 가동과 모니터링 강화로 늘어난 클라우드 비용을 불필요한 리소스 삭제·DB 인스턴스 적정화·컨테이너 리소스의 실측 기반 축소 등으로 월간 20% 초과 절감. 성능 개선으로 DB의 이중화 구성을 축소할 수 있었던 사례도 있어, 품질 개선과 비용 절감이 같은 뿌리에서 나온다는 것을 실감함
이 상시 운영의 실태——주당 어느 정도의 아웃풋(Output)이 나오고 품질이 어떠한가——가, 지난번 QCD 기사에서 평가했던 '최근 2주간'에 해당합니다.
장 끝의 증류: 순서의 뼈대는 '안전망(테스트)을 먼저 펼치고, 짐을 줄인(삭제) 다음 새로 만들기(버전 업그레이드·컨테이너화), 토대(IaC/CI/CD) 위에서 단계적으로 전환하기'입니다. 그리고 원칙에서 벗어나는 판단을 할 때는, 어떤 대가를 치를 것인지를 자각하며 선택합니다. 무의식적인 일탈만이 실패입니다.
4. 최종적으로 어떻게 되었는가
4-1. 시스템의 Before/After
일련의 노력을 거친 현재 위치를 시스템 측면에서 정리합니다.
| 관점 | Before | After |
|---|---|---|
| 구성 | 모놀리스(Monolith) 1개 리포지토리 | 책무별 약 10개 리포지토리(마이크로서비스) |
| ... |
4-2. 개발 체제의 Before/After
시스템보다 더 크게 변한 것은 개발이 돌아가는 방식 그 자체입니다.
현재의 상시 운영에서는 인간(리드 엔지니어)은 방침 판단·리뷰·고객 및 팀과의 조정에 집중하고, 구현·조사·QA·배포·릴리스 후 모니터링은 AI 세션이 담당합니다. 여러 개의 AI 세션이 병렬로 실행되며, 리포지토리 단위로 담당을 갖고, 코드 리뷰는 AI(GitHub Copilot)와 인간의 이중 구조, 릴리스 판단은 인간의 승인 게이트(Approval Gate)를 거치는——식의 분업입니다. 이 운영 프로토콜 자체도 기간 중 몇 번이나 실패하며 개정해 왔습니다(원칙 편·자주화 편).
의사결정 스탠스도 변했습니다. '추측으로 논쟁하지 않고 측정하고 나서 결정한다'(측정 편), '구현 공수의 크고 작음을 설계 판단의 결정적 요인으로 삼지 않는다'(의사결정 편)——둘 다 조사와 측정의 비용이 AI에 의해 급감했기에 성립할 수 있는 스탠스입니다.
4-3. 그리고 QCD로
이 기반 위에서 어떤 일이 일어나고 있는지는 지난 QCD 기사에서 쓴 바와 같습니다. 주당 인간 환산 약 80인일(Man-day)의 아웃풋이 변경 실패율을 업계 수준 이하로 유지하면서 나오고 있습니다. 그리고 '결함이 빈번하게 발생하고 있다'고 느껴졌던 체감의 주된 원인은 품질의 악화가 아니라 검출률의 향상이었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기