[HR Bank] 프로젝트 개인 개발 리포트 및 회고

1. 프로젝트 개요

  • 프로젝트명: HR Bank (Batch로 데이터를 관리하는 Open EMS)
  • 목적 및 핵심 기능: 기업의 핵심 자산인 인적 자원(HR) 데이터를 안전하게 저장하고, 대량의 데이터를 무중단으로 주기적으로 백업 및 관리하는 엔터프라이즈 백엔드 시스템입니다. 대규모 트래픽에서의 OOM(Out Of Memory) 방지, Audit(수정 이력)을 통한 데이터 무결성 확보, 심야 Batch 처리를 통한 서버 부하 분산이 핵심 과제입니다.

2. 담당한 작업

본 프로젝트에서 부서(Department) 도메인 백엔드 아키텍처 설계 및 구현을 총괄하였으며, 팀의 원활한 소통과 산출물 퀄리티를 높이기 위한 테크 리드 역할을 수행했습니다.

  • 백엔드 개발: ERD 기반 부서 엔티티 설계, CRUD RESTful API 파이프라인 구축, 예외 처리(Global Exception) 규약 역설계 및 적용, 대규모 데이터 조회를 대비한 동적 검색 및 성능 최적화(Cursor Pagination) 아키텍처 도입
  • 팀 프로세스 관리: 매 스프린트 종료 후 팀 회고록(Retrospective) 작성 및 관리 주도
  • 기술 프레젠테이션: 프로젝트 산출물(명세서) 및 효과적인 발표 자료(PPT) 구성 주도, 최종 기술 발표(Tech 피칭) 스크립트 작성 및 메인 발표자 역할 수행

3. 기술적 성과

  • 기술 스택: Spring Boot 3.x, Java 17, PostgreSQL, Spring Data JPA, QueryDSL, MapStruct
  • 주요 구현 기능:
    • DTO-Entity 매핑 분리: MapStruct를 도입하여 계층 간 데이터 전송 객체(DTO)와 영속성 객체(Entity)의 변환 로직을 캡슐화하고 결합도를 낮췄습니다.
    • 동적 검색 로직 구현: QueryDSL을 활용하여 부서 이름 및 설명 필드에 대한 대소문자 무시, 부분 일치(OR 조건) 동적 검색 쿼리를 안전하게 구현했습니다.
    • No-Offset 커서 페이징: 대규모 트래픽 환경을 가정하여, 기존 Offset 방식의 성능 저하를 극복하기 위해 Slice 인터페이스와 고유 식별자(ID)를 활용한 무한 스크롤 방식의 커서 페이징을 구현했습니다.
  • 관련 PR 링크: https://github.com/sb09-hrbank-team03/sb09-hrbank-team03/pull/39

4. 문제점 및 해결 과정 (STAR 기법)

[사례 1: 프론트엔드-백엔드 예외 처리 규약 불일치 해결]

  • Situation (상황): 부서명 중복 생성 차단 및 삭제 방어 비즈니스 로직을 백엔드에 구현했으나, 클라이언트 화면에서 에러 경고창이 렌더링되지 않고 ‘undefined’ 처리되는 이슈가 발생했습니다.
  • Task (과제): 백엔드의 GlobalExceptionHandler 응답 구조를 프론트엔드가 예상하는 에러 파싱 규약(Contract)과 정확히 동기화해야 했습니다.
  • Action (행동): 프론트엔드 코드를 역설계하여, 클라이언트 인터셉터가 400 Bad Request가 아닌 409 Conflict 상태 코드를 기다리고 있으며, 특정 Exception 클래스명에 화면의 에러 메시지가 매핑되어 있다는 사실을 파악했습니다. 이에 맞춰 백엔드의 커스텀 예외 응답 구조와 Status 코드를 프론트엔드 규격에 맞게 재조정했습니다.
  • Result (결과): 프론트엔드 화면에 의도한 예외 메시지가 완벽하게 렌더링되어 UX가 개선되었으며, API 개발 시 프론트엔드 파싱 로직을 사전에 합의하는 ‘인터페이스 계약’의 중요성을 깊이 체감했습니다.

[사례 2: 커서 페이징 시 데이터 누락(Tie-breaker) 이슈 해결]

  • Situation (상황): 설립일 기준으로 커서 페이징을 구현하여 테스트하던 중, 동일한 설립일을 가진 부서 데이터가 여러 개 존재할 경우 페이징 경계선에서 일부 데이터가 누락되거나 중복 조회되는 버그를 발견했습니다.
  • Task (과제): 정렬 기준 값이 중복될 때도 데이터의 순서를 100% 보장하는 무결점 페이징 쿼리를 작성해야 했습니다.
  • Action (행동): QueryDSL 정렬 조건에 보조 정렬 기준(Tie-breaker)을 추가했습니다. 1차 정렬 기준(예: 설립일)의 값이 같을 경우, 절대 중복될 수 없는 PK(고유 ID)를 2차 정렬 조건으로 삼도록 동적 쿼리를 수정했습니다.
  • Result (결과): 중복 데이터 환경에서도 데이터 누락이나 중복 조회 없이 완벽하게 페이징이 작동하는 안정적인 조회 로직을 완성했습니다.
  • 관련 코드 리뷰 링크: https://github.com/sb09-hrbank-team03/sb09-hrbank-team03/pull/39

5. 협업 및 피드백

단순히 코드를 작성하는 것을 넘어, 프로젝트 전체의 완성도를 높이기 위한 ‘소통과 문서화’ 에 집중했습니다.

초기에는 각자의 도메인 개발에 집중하다 보니 팀의 개발 방향성이나 진척도가 파편화되는 경향이 있었습니다. 이를 바로잡기 위해 주기적인 팀 회고록(Retrospective) 작성을 주도하여, 발생했던 이슈와 해결 방안을 팀원 전체의 자산으로 공유하는 문화를 정착시켰습니다.

또한, 개발된 복잡한 백엔드 아키텍처를 비개발자나 평가자도 쉽게 이해할 수 있도록 효과적인 발표 자료(PPT) 구성을 기획하고 발표 대본을 직접 작성했습니다. 최종 기술 발표(IR 피칭)를 직접 진행하며, ‘기능 나열’이 아닌 ‘문제 해결과 비즈니스 가치(OOM 방지, 데이터 무결성 확보 등)’ 중심으로 기술적 성과를 어필하는 소통 역량을 크게 기를 수 있었습니다.


6. 코드 품질 및 최적화

  • 유지보수성: QueryDSL의 OrderSpecifierBooleanExpression을 반환하는 공통 메서드를 추출하여 중복 코드를 제거하고 쿼리 가독성 증대.
  • 성능 최적화: 생성과 수정의 DTO를 분리하여 각 API 규격에 맞는 유효성 검증을 수행함으로써 데이터 정합성 강화.

7. 향후 개선 사항 및 제안

  • 프론트엔드 레퍼런스 코드 고도화 및 엣지 케이스(Edge Case) 확보: 프로젝트를 진행하며 백엔드 예외 처리 로직을 완벽하게 구현했음에도, 연동되는 프론트엔드 코드 내부의 이슈나 미구현된 예외 처리 파싱 로직으로 인해 최종 기능 구현과 테스트를 100% 마무리하지 못한 아쉬움이 더러 있었습니다. 향후 프로젝트에서는 클라이언트 측에서 발생할 수 있는 다양한 경우의 수(다양한 HTTP Status Code, Null 데이터 유입 등)가 사전에 방어되어 있는 완성도 높은 프론트엔드 레퍼런스 코드가 제공된다면 좋겠습니다. 이를 통해 백엔드 개발자는 연동 이슈에 소모되는 시간을 줄이고, API 아키텍처 안정화와 성능 최적화라는 본연의 역할에 더욱 집중할 수 있을 것입니다.