AI API를 AWS로 옮길 계획
회사에서 클라우드를 AWS로 통합하고 있어 알툴즈 AI API도 이전을 준비하고 있습니다. 이번 이전에 맞춰 기존 코드의 구조도 개선하려 합니다.
구조를 개선하려는 이유
기존 서버에서는 설정 변경과 오류 응답이 의도대로 동작하지 않는 문제를 겪었습니다.
- 한도 변경을 두 곳에 반영해야 했습니다. 백오피스에서 수정한 값과 서버가 읽는 값이 달라, 기존 서버에도 수정한 값을 따로 반영해야 했습니다.
- 토큰 만료 요청이 401 대신 500으로 응답했습니다. 예외 처리기들이 서로의 예외를 가로채면서 인증 오류를 서버 오류로 반환했습니다.
코드를 살펴보니 한도 정책과 사용 기록 처리가 여러 모듈에 복사돼 있었고, 수정할 때마다 변경이 어디까지 영향을 주는지 파악하기 어려웠습니다. 같은 규칙을 여러 곳에서 관리하는 구조와 예외 처리 범위를 정리할 필요가 있었습니다.
API를 하나씩 전환하려는 이유
다만 모든 API를 한 번에 다시 만들면 각 API의 기존 동작과 구조 변경, AWS 환경에서의 실행을 한꺼번에 검증해야 합니다. 기존 코드에는 PDF의 캐시 폴백과 응답 형식 보정처럼 유지해야 할 처리도 있어, API별로 어떤 동작을 보존하고 어떤 오류를 수정할지 먼저 확인해야 합니다.
그래서 Strangler Fig Pattern을 활용해 API 하나씩 기존 동작을 확인하고 구조를 개선한 뒤, AWS에서 처리하도록 전환할 계획입니다. 아직 전환하지 않은 API는 기존 Azure 서버에서 계속 처리합니다. 기존 호출 주소와 앱의 호출 방식, 일일 사용 횟수는 유지할 예정입니다.
API 처리와 사용 횟수 이전 분리하기
처리 서버와 사용 횟수 데이터를 동시에 옮기면 문제가 생겼을 때 어느 변경 때문인지 찾기 어려워집니다. 그래서 API 전환 중에는 Azure와 AWS의 API가 기존 사용 횟수 DB를 함께 사용하고, 사용 횟수 저장소는 별도 단계에서 옮기기로 했습니다.
다시 만들고 싶은 마음을 점검하기
운영 중 겪은 문제를 고치면서 제가 이해하기 쉬운 구조로 다시 만들고 싶은 마음도 생겼습니다. 어떤 부분을 바꿀지 판단하려고 실제 코드의 연결과 중복을 살펴봤습니다.
코드에서 확인한 패턴
복잡하게 느껴지는 이유를 찾으려고 화질 개선 준비 요청이 어떤 모듈과 클래스를 참조하는지 따라가 봤습니다. 정책 구조와 한도, 사용 기록 처리도 함께 살펴봤고, 모듈과 클래스 수를 셀 때는 설정 클래스도 포함했습니다.
| 확인한 패턴 | 분석 수치 |
|---|---|
| 여러 모듈에 걸쳐 연결된 코드 |
|
| 구현 하나를 위해 여러 인터페이스를 둔 정책 구조 |
|
| 구현체가 하나뿐인 인터페이스 |
|
| 여러 모듈에 복사된 처리 |
|
개선 방향
다시 만들고 싶은 마음을 점검하기 위해 어떤 기준으로 개선할지 고민하며 관련 자료를 찾아봤습니다.
- 코드 이해 비용
- 원문 요약: Xia 등의 현장 연구에서는 78명의 개발자가 일하는 시간의 평균 약 58%를 코드를 이해하는 데 썼습니다. 원문
- 적용할 기준: 낯설어서 이해하기 어려운 부분과 구조 때문에 변경하기 어려운 부분을 먼저 구분하기로 했습니다.
- 기존 코드에 남은 경험
- 원문 요약: Spolsky의 에세이는 재작성하면서 기존 코드에 쌓인 버그 수정과 예외 처리를 놓칠 수 있다고 설명합니다. 원문
- 적용할 기준: PDF의 캐시 폴백과 응답 형식 보정은 변경 전에 어떤 문제를 막고 있는지부터 확인할 생각입니다.
- 리팩토링의 범위
- 원문 요약: Fowler는 리팩토링을 외부에서 보이는 동작은 그대로 두고, 코드를 이해하고 고치기 쉽게 만드는 작업으로 정의합니다. 원문
- 적용할 기준: 유지해야 할 동작과 수정해야 할 오류를 구분하는 기준으로 삼았습니다.
이 기준에 따라 반복되는 코드는 합치고, 호출만 전달하는 중간 층은 줄이는 방향을 잡았습니다. 입력과 결과, 실패했을 때의 처리와 비즈니스 규칙이 같은 코드만 합치고, 각 부분이 왜 나뉘어 있는지도 먼저 확인하기로 했습니다.
| 반복 패턴 | 개선할 부분 | 유지할 차이 |
|---|---|---|
| 인터페이스와 중간 층 | 각 층이 하는 일을 확인하고, 호출만 전달하는 층은 합칠 수 있는지 검토 | 역할 분리와 구현 선택에 필요한 인터페이스 |
| 한도 확인과 사용 기록 | 같은 규칙으로 처리하는 코드만 합치고, 사용하는 DB와 트랜잭션을 확인 | 사용자 범위, 날짜 기준, 차감과 기록 시점 |
| 입력 검증과 오류 응답 | 같은 검증과 오류 응답 처리를 합치고, 예외 처리기가 어떤 요청에 적용되는지 확인 | API별 상태 코드와 응답 형식 |
| 외부 호출과 폴백 | 실패 조건과 실패했을 때의 대체 처리가 같은 코드만 합치기 | 기능별 캐시 조건, 재시도와 폴백 정책 |
요청자 유형이 늘어나도 같은 구조로 저장하기
상황과 문제
B2B 기능을 살펴보니, 기존 요청 구조에 인증 정보를 함께 넣으면 NULL이 많아져 저장 테이블과 처리가 따로 구현돼 있었습니다. 요청자 유형이 늘어날 때마다 컬럼과 저장 코드를 따로 추가해야 한다는 점이 문제였습니다.
해결 방법을 찾은 과정
유형별 데이터를 비교해 보니 회원 ID, 게스트 ID, 라이선스 키와 기기 ID는 형태가 달라도 누구의 요청인지 구분하는 데 쓰이고 있었습니다.
공통 정보와 유형별 정보를 저장하는 JPA의 상속 매핑을 참고하면서, 이 정보도 유형과 식별자 두 값으로 정리할 방법을 찾았습니다.
적용한 방법
회원과 비회원, 구독, B2B의 식별 정보를 user_type과 user_key 두 컬럼에 담았습니다. 구독 상품 코드와 라이선스 키도 user_type으로 표현해, 유형마다 식별 정보를 위한 컬럼을 따로 두던 구조를 정리했습니다. 기존 한도와 인증 검증 규칙은 유지하면서 저장 방식만 통일했습니다.
그림은 복잡한 구조를 간단히 보여주기 위해 일부만 표현했습니다. 실제로는 사용자 정보와 사용 기록이 나뉜 6개 테이블을 ai_request로 통합했습니다.
| AS-IS | TO-BE |
|---|---|
사내 버셀 런칭
배포 자동화와 권한 조회 개선, 빌드 분리를 거쳐 오늘 사내 버셀을 런칭했습니다. 이제 준비한 기능이 실제로 어떻게 쓰이는지 확인하는 단계입니다.

쇼케이스에는 다음 프로젝트들이 운영 중입니다.
| AI API AWS 전환 안내 | LGTM Watchdog | ALTools Alpha 사용 안내 |
|---|---|---|
| 전환 계획과 단계별 구성 공유 | LGTM 구성 요소의 상태와 응답 시간 확인 | 프로젝트 생성과 배포 방법 안내 |
![]() | ![]() | ![]() |
팀원 합류에 맞춰 작업 프로세스 정하기
사내 버셀을 오픈하고 활용 가치를 확인하면서 팀원도 프로젝트에 합류했습니다. 혼자 작업할 때는 작업 방식을 따로 정리하지 않았습니다. 함께 작업하게 되니 누가 무엇을 진행하고 어떤 기준으로 변경하는지 공유할 방법이 필요해졌습니다.
그래서 작업 시작부터 리뷰, 결정 기록까지 필요한 규칙을 저장소에 남겼습니다.
- 작업 진행 표시: 이슈 담당자를 지정하고 첫 커밋 뒤 Draft PR을 열도록 정했습니다. 한 사람이 동시에 진행하는 PR은 2개 이하로 제한했습니다.
- 변경과 리뷰 기준: CODEOWNERS로 경로별 리뷰 기준을 마련했습니다. API의 요청과 응답 형식이나 DB 구조를 바꿀 때는 작업 전에 이슈에 기록하도록 정했습니다.
- 결정 기록: 개인 메모나 대화에 남아 있던 결정 이유는 이슈나 결정 문서에 모으고, 문서 목록에서 찾을 수 있도록 정했습니다.
혼자 알고 있던 작업 방식과 결정 이유를 팀원이 확인할 수 있게 남기는 일도, 프로젝트를 함께 운영하기 위한 준비라는 것을 깨달았습니다.


