레거시 현대화

본사·해외법인 파일 다운로드 플랫폼(DNA2) 레거시 현대화 및 통합

본사·유럽법인의 결과 파일을 제공하는 다운로드 플랫폼(DNA2)을 Spring Boot 기반 단일 프로젝트로 통합하고, DB Connection·DB Link·배포 구조와 결과 다운로드 기준을 개선했습니다.

기간
2025.03 — 2025.08
상태
운영 반영
역량
레거시 분석 · 호환성 설계
232 → 42DB Connection
16 → 2성공·실패 화면
557기능테스트 케이스
전환 범위
본사 Model2·유럽법인 Model1의 결과 다운로드 기능과 배포 구조
보존해야 한 계약
기존 URL·축약 파라미터·파일명·압축 구성·예외 응답
완료 기준
20개 기능테스트 시나리오·557개 테스트 케이스, 연결 구조 개선, 단계별 운영 안정화
Connection 수치 근거
232개는 현행 분석 PPT, 42개는 과거 운영 화면 판독 기록이며 원본 캡처·해시는 미보존

CASE STUDY

한눈에 보는 변화

이 프로젝트의 핵심은 오래된 코드를 Spring Boot로 옮기는 것이 아니었습니다. 본사와 유럽법인의 서로 다른 실행 구조를 하나로 합치면서도, 다른 시스템과 고객이 이미 사용하던 다운로드 계약을 깨지 않고 DB 객체의 잘못된 생명주기까지 바로잡는 작업이었습니다.

본사와 유럽법인에 유사한 다운로드 기능이 서로 다른 구조로 중복되어 있었습니다. 요청마다 Connection Pool과 SessionFactory가 생성되고, DB Link와 법인별 배포 구조에 대한 의존도도 높았습니다. 구조를 바꾸되 고객이 사용하던 URL·파라미터·파일명·압축 구성은 그대로 유지해야 했습니다.

직접 담당한 범위

  • 본사 Model2와 유럽법인 Model1 구조의 AS-IS/TO-BE 및 Gap Analysis 작성
  • 공통 구조 설계와 핵심 다운로드·검증·예외 처리 개발
  • 기능테스트와 본사·유럽법인 별도 통합테스트, 단계별 배포와 운영 안정화 주도
프로젝트 변경 전후 비교
구분변경 전변경 후확인된 변화
DB 객체 생명주기요청마다 Connection Pool을 만들고 Query 경로에서 SqlSessionFactory를 반복 생성DB별 DataSource와 SqlSessionFactory를 애플리케이션 공용 객체로 관리DB Connection 232개 → 42개
DB 접근 경로구형·신형 LIMS 접근과 DB Link가 코드 안에서 혼재용도별 DataSource를 분리하고 필요한 구간은 직접 DB 접근으로 전환접근 대상과 Pool 소유 관계 명확화
법인별 코드·배포본사 Model2와 유럽법인 Model1에 유사 기능이 중복애플리케이션 코드는 통합하고 Build Profile·설정·배포 흐름은 분리본사·유럽법인 단일 프로젝트
성공·실패 처리기능과 법인에 따라 성공·실패 화면 16개가 분산메시지와 예외 전달 규칙을 정리해 공통 화면 2개로 통합16개 → 2개
요청 호환·다국어레거시 URL·법인별 언어 규칙과 하드코딩 메시지가 혼재원 URL·법인 Profile로 Locale을 먼저 확정하고 DB MessageSource와 내부 Forward에 연결기존 호출 URL을 유지한 Spring 요청 생명주기
입력·접근 검증Service마다 필수값·경로 검증이 반복되고 호출별 차이가 코드에 분산Validation Group을 메서드별로 조합하고 경로·주문 고객 검증은 별도 책임으로 분리호출별 Validation Group을 선언적으로 구성

EVIDENCE CHAIN

문제를 좁힌 과정

  1. 01 · 현행 비교

    연결 수가 아니라 객체 생성 구조를 조사 대상으로 잡았습니다

    DNA2가 DB Connection 232개를 유지하는 상태를 확인하고, 본사 Model2·유럽법인 Model1의 DB 접근과 요청 처리 흐름을 기능별로 비교했습니다. 개별 Query 종료 여부만으로는 수치를 설명할 수 없었습니다.

    판단Connection 한 개의 close 누락과 Connection을 소유하는 Pool 자체의 반복 생성을 분리해 확인해야 했습니다.

  2. 02 · 호출 경로 추적

    요청과 Query가 인프라 객체의 생성 책임까지 가지고 있었습니다

    요청 진입점부터 설정 로드, DataSource 생성, MyBatis 설정, SqlSessionFactory 생성과 Query 실행까지 역추적했습니다. Client 요청마다 Pool이 만들어지고 Query 경로에서 SqlSessionFactory가 다시 생성되는 구조를 확인했습니다.

    판단SqlSession을 닫아도 Connection은 새로 만든 Pool로 돌아갈 뿐이므로, Pool의 생명주기를 애플리케이션 단위로 올려야 했습니다.

  3. 03 · 변경 제약 수집

    구조 변경보다 먼저 외부 호출 계약을 테스트 기준으로 만들었습니다

    LIMS·COMS와 메일 링크가 사용하던 URL, 축약 파라미터, 파일명, 경로, 압축 구성과 예외 응답을 기능별로 목록화했습니다. 내부 명칭을 정리하더라도 외부 입력 규격은 그대로 유지해야 했습니다.

    판단새 구조의 성공 기준을 코드 형태가 아니라 기존 요청과 결과의 동일성으로 정의했습니다.

  4. 04 · 기능 검증

    최초 548건 성공에서 멈추지 않고 차이가 난 9건을 분리했습니다

    20개 기능테스트 시나리오, 557개 테스트 케이스를 실행해 최초 548건 성공과 9건 실패를 확인했습니다. 실패 항목을 기능별 결함으로 분리해 수정한 뒤 전체 557건을 다시 검증했습니다. 본사·유럽법인 통합테스트는 별도 시나리오로 수행했습니다.

    판단기능테스트 557개 수치와 별도 통합테스트를 구분하고, 두 검증 범위를 모두 통과해야 전환을 완료할 수 있었습니다.

  5. 05 · 운영 안정화

    배포 뒤 드러난 문제를 하나의 원인으로 묶지 않았습니다

    대용량 ZIP 처리, 동일 파일명 충돌, 구형 JDBC Driver 선로딩이 차례로 나타났습니다. 압축 로직·파일 충돌·JVM Class Loading이라는 서로 다른 경계에서 재현하고 원인을 분리했습니다.

    판단구조 전환 완료와 실제 운영 안정화는 다른 단계이며, 배포 후 실행 환경까지 확인해야 했습니다.

DECISION LOG

검토한 대안과 선택 근거

제외

Connection close 경로만 보완

개별 세션이 반환돼도 요청마다 새 Pool이 만들어지는 생명주기 문제는 남기 때문입니다.

제외

기존 DB Link 중심 접근 유지

실제 접근 DB와 장애 경계가 코드에서 드러나지 않고 법인별 의존성이 계속 남기 때문입니다.

제외

법인별 Branch 분리

법인별 최적화는 쉽지만 공통 기능 Merge 충돌과 법인 추가 시 Branch 증가가 예상됐고, 현행 분석에서 본사·유럽 기능의 공통성이 더 높았기 때문입니다.

선택

단일 소스 + Active Profile·Build Profile

공통 코드는 한 곳에서 유지하고 법인별 분기는 Active Profile로, 접속정보와 배포 산출물은 Build Profile로 분리할 수 있었습니다.

선택

단일 코드 + 명시적 복수 DataSource

공통 로직을 한 곳에서 관리하면서 구형·신형 LIMS의 접근 대상과 인프라 객체 소유 관계를 명확히 할 수 있었습니다.

IMPLEMENTATION

설계와 구현

DB 인프라 생명주기

  • 구형·신형 LIMS의 XA DataSource와 MyBatis 접근 계층을 각각 분리
  • Atomikos JTA로 조건에 따라 다른 Mapper를 사용하는 Service의 @Transactional 경계를 통합
  • DB Link 의존 구간을 직접 DataSource 접근으로 전환하고 유럽 Profile에서는 미사용 LIMS 2.0 구성을 비활성화

URL·요청 호환 계층

  • 레거시 화면 요청을 내부 Controller로 Forward하고 정적 리소스 경로를 신규 위치에 매핑
  • HandlerMethodArgumentResolver가 레거시 축약 파라미터를 의미가 드러나는 DTO 필드로 변환
  • 기존 파일명·압축 구성·다운로드 결과와 오류 응답을 회귀 기준으로 고정

Locale·메시지 생명주기

  • 원 요청 URL과 법인 Profile로 Locale을 먼저 확정해 내부 Forward 전 언어 정보 보존
  • LocaleContextHolder와 DB MessageSource를 Controller·Service·예외 처리·Bean Validation에 연결
  • 운영은 메시지 사전 적재, 개발·로컬은 지연 적재를 적용하고 요청 종료 시 커스텀 ThreadLocal 제거

호출 맥락별 검증

  • 동일 DTO의 필드 제약에 의미 단위 Validation Group을 부여하고 호출 메서드별로 조합
  • Spring AOP가 Controller 인자에서 대상 DTO를 찾아 표준 Validator를 Group 순서대로 실행
  • 파일 경로의 '..' 검사와 요청 고객·실제 주문 고객 일치 검증은 구조·필수값 검증과 분리

법인·배포 구조

  • 본사와 유럽법인 애플리케이션 코드를 하나의 프로젝트로 통합
  • 법인별 설정, Build Profile과 Jenkins 배포 흐름은 독립적으로 유지
  • 각 법인의 DB 접근 경로와 환경 차이를 설정 경계에서 수용

다운로드·운영 안정화

  • 파일명·압축 구성·시퀀스 길이 계산과 분석 결과 예외 기준 개선
  • 유럽법인 자동발송 결과 압축에 필요한 결과 파일이 포함되도록 보완
  • 대용량 압축 처리와 ZIP 내부 동일 파일명 충돌 보완
  • JVM Class Loading 로그로 애플리케이션 의존성과 실제 JDBC Driver 차이 확인
  • 본사 자동발송 모듈의 불필요한 구형 JDBC Driver 의존 제거

VERIFICATION

테스트 매트릭스

프로젝트 테스트와 완료 기준
검증 영역검증 방법완료 기준
외부 호출 계약기존 .jsp URL·축약 파라미터와 언어 경로를 동일하게 호출Forward 이후에도 본사·유럽법인별 다운로드·Locale·오류 결과 유지
입력·접근 검증API별 필수 Group, '..' 경로와 주문 고객 불일치 요청 확인호출별 선택 필드는 허용하고 비정상 경로·고객 불일치는 업무 처리 전 차단
파일 결과파일명·압축 구성·분석 결과 예외를 전후 비교기존 사용자가 받는 결과 형식 유지
DB 접근구형·신형 LIMS 직접 연결과 기존 조회 결과 대조결과 동일성 및 요청 반복 후 Pool 추가 생성 없음
기능테스트20개 시나리오·557개 테스트 케이스 수행최초 실패 9건 수정 후 557건 전체 통과
법인 통합 흐름본사·유럽법인 통합테스트를 별도 시나리오로 수행557개 기능테스트 수치와 분리해 연계·다운로드 흐름 확인
운영 안정화단계별 배포 후 연결 수·로그·대용량 다운로드 관찰Connection 232개 → 42개 및 주요 흐름 정상 동작
자동발송 모듈 후속 안정화필수 결과 파일 포함과 JDBC 패키징 변경 관련 검증자동발송 결과 구성 유지 및 불필요한 구형 JDBC Driver 의존 제거

OPERATION

운영 반영과 후속 안정화

운영 이슈

대용량 ZIP 처리 지연

분리한 원인
일반 다운로드와 다른 압축 소요시간·타임아웃 경계로 분리
대응
대용량 압축 시간을 고려하도록 처리 흐름 보완
운영 이슈

ZIP 내부 동일 파일명 충돌

분리한 원인
서로 다른 경로의 파일이 같은 이름으로 압축될 때 발생하는 충돌 재현
대응
압축 구성 단계의 파일명 충돌 처리 보완
운영 이슈

JDBC API 실행 불일치

분리한 원인
JVM Class Loading 로그로 JRE Extension 경로의 구형 Driver 선로딩 확인
대응
코드 결함과 운영 런타임 Driver 충돌을 분리해 대응
확인된 결과
  • 근거 강도가 다른 232개 PPT 기록과 42개 과거 화면 판독 기록을 기준으로 190개·약 81.9% 감소 계산
  • 성공·실패 화면 16개를 공통 화면 2개로 통합
  • 본사·유럽법인 유사 기능을 단일 프로젝트와 공통 코드로 재구성
  • 20개 기능테스트 시나리오, 총 557개 테스트 케이스 통과
  • 다운로드 시스템과 자동발송 모듈의 JDBC Driver 로딩·패키징 충돌 요인을 함께 제거

TAKEAWAYS

이 사례에서 드러난 역량

  • Connection 수가 많을 때 close()만 찾지 않고 Pool과 SessionFactory가 몇 번 생성되는지 확인해야 합니다.
  • 레거시 현대화의 완료 기준은 새 코드의 형태가 아니라 기존 외부 계약과 결과가 유지되는지에 있습니다.
  • 공통 코드는 통합하더라도 법인별 설정과 배포 책임까지 억지로 하나로 묶을 필요는 없습니다.
  • 운영 배포 뒤 나타난 문제는 전환 실패로 뭉뚱그리지 않고 압축·파일·런타임 경계로 나눠야 합니다.
레거시 분석호환성 설계다법인 통합운영 안정화

사용 기술

Java 8Spring Boot 2.7.5MavenMyBatisOracle/MySQLLog4j2ThymeleafJenkins자동 결과 발송 연계ZIPAtomikos