개발 slecs

마이페이지 4탭 시안 일치와 브랜드 분기 구조 개선

목차

마이페이지 4탭 시안 일치 작업을 마무리하면서, 생각보다 손이 많이 가는 작업이었다.


배경: "시안 일치"가 왜 생각보다 큰 작업인가

디자인 시안과 실제 구현 사이의 간극은 항상 존재한다. 그런데 그 간극을 메우는 작업이 단순히 CSS 픽셀 조정에서 끝날 것 같아 보여도, 실제로 파고들면 컨트롤러, 쿼리 매퍼, JSP 레이아웃 전반을 건드려야 하는 경우가 있다. 이번이 딱 그 케이스였다.

마이페이지 4탭 — 탭 자체의 뷰 구조를 시안에 맞게 정리하면서, 동시에 주문관리와 활동관리 영역에 viaggioone 브랜드 분기 로직이 필요하다는 걸 확인했다. 사실 처음엔 "탭 UI 몇 개 고치면 되겠지" 싶었는데, 막상 열어보니 컨트롤러 레벨의 분기, 쿼리 매퍼 수정, 공통 헤더 fragment 추출까지 연쇄적으로 엮여 있었다.


작업 내용: 변경 파일별로 뜯어보기

영역 파일 주요 변경 내용
컨트롤러 mypage/web/내부 클래스 viaggioone 분기 처리 추가
컨트롤러 order/web/내부 클래스 주문관리 viaggioone 분기
쿼리 매퍼 sqlmap/ap/쿼리 매퍼 분기에 따른 쿼리 분리
JSP _pageTabs.jsp 4탭 시안 일치, 탭 구조 정리
JSP bookmarkList.jsp 북마크 리스트 뷰 수정
JSP mypage.jsp 공통 헤더 fragment 적용

특히 _pageTabs.jsp 앞에 언더스코어(_)가 붙어 있다는 건, 이 파일이 다른 JSP에서 include되는 부분 뷰(fragment)라는 걸 의미한다. 탭 자체를 별도 fragment로 분리해서 관리하는 구조인데, 이렇게 해두면 나중에 탭 구성이 바뀔 때 mypage.jsp 본체를 건드리지 않아도 된다. 팀에서 공통 헤더도 fragment로 빼달라는 요구가 있었고, 이번에 mypage.jsp에 그 작업도 같이 반영했다.

<%-- 공통 헤더 fragment include 예시 패턴 ---%>
<jsp:include page="/WEB-INF/jsp/slecs/co/viaggioone/_pageHeader.jsp">
    <jsp:param name="activeTab" value="mypage"/>
</jsp:include>

이런 식으로 파라미터로 현재 활성 탭 정보를 내려주면, 헤더 fragment 안에서 active 클래스를 동적으로 제어할 수 있다. 매번 각 페이지마다 헤더 마크업을 복붙하던 구조에서 벗어나는 첫 번째 단계다.


viaggioone 분기: 컨트롤러에서 자르는 게 맞는가

이번 작업에서 가장 고민했던 부분이 여기다. 주문관리/활동관리 양쪽 컨트롤러에 viaggioone 분기를 넣었는데, 분기를 어느 레이어에서 처리하느냐는 꽤 중요한 결정이다.

  • 컨트롤러 레벨 분기: 요청이 들어오는 시점에 사용자/브랜드 컨텍스트를 판단하고, 다른 서비스 메서드를 호출하거나 다른 뷰를 리턴. 명확하고 추적이 쉬움
  • 서비스 레벨 분기: 비즈니스 로직 안에서 분기. 뷰는 공통으로 쓰되 데이터가 달라질 때 적합
  • 쿼리 매퍼 레벨 분기: SQL 안에서 조건으로 처리. 단순 필터 차이라면 유용하지만, 복잡해지면 쿼리 가독성이 급격히 떨어짐

이번에는 쿼리 매퍼도 같이 수정이 들어간 걸 보면, 세 레이어 모두 어느 정도 손이 닿은 케이스다. 쿼리 매퍼까지 건드렸다는 건 단순 뷰 분기가 아니라 데이터 조회 조건 자체가 viaggioone과 일반 케이스 간에 차이가 있다는 의미다. 그렇다면 컨트롤러에서 분기를 열고, 각 경로에 맞는 쿼리 ID를 다르게 호출하는 패턴이 현재 구조에서는 제일 읽기 편한 선택이었다고 본다.

// 컨트롤러 분기 패턴 (개념적 예시)
if ("viaggioone".equals(userBrandType)) {
    model.addAttribute("orderList", orderService.selectViaggiooneOrderList(param));
    return "slecs/co/viaggioone/orderList";
} else {
    model.addAttribute("orderList", orderService.selectOrderList(param));
    return "slecs/co/mypage/orderList";
}

물론 이게 분기가 계속 늘어나면 나중에 if-else 체인이 길어지는 부채가 생긴다. 그 전에 전략 패턴이나 브랜드별 핸들러 분리를 고려해야 할 시점이 오긴 할 것이다. 지금은 브랜드가 둘이라 관리 가능한 수준이지만, 미리 팀에 공유해두는 게 좋겠다 싶어 PR 설명에 메모를 달아놨다.


회고

이번 작업은 팀장 입장에서 "작업 범위를 처음에 제대로 파악했냐"를 돌아보게 됐다. 처음 티켓에는 "마이페이지 탭 시안 일치"만 있었는데, 실제로 해보니 컨트롤러 분기와 쿼리 매퍼 수정이 따라왔다. 이런 연쇄 작업은 스프린트 플래닝에서 추정치가 틀리는 주요 원인이다.

앞으로 마이페이지 계열 작업 추정할 때는 뷰 변경이라도 컨트롤러/쿼리까지 훑는 시간을 포함시켜야 한다. 그리고 공통 헤더 fragment 분리처럼, 리팩터링 성격의 작업이 기능 작업에 묻혀 들어올 때는 커밋을 나눠서 히스토리를 남기는 게 나중에 리뷰하기 훨씬 편하다. 이번엔 한 커밋에 같이 들어갔는데, 그 부분은 다음엔 조금 더 신경 쓰려고 한다.

다음

댓글 0

첫 댓글 달아줘.