본문 바로가기

[Spring] 코드 리팩토링 - 계층 분리

@cayman0312025. 12. 17. 19:37

서비스 계층의 책임이 오염되었다.

사이드 프로젝트를 진행하던중 전체적인 MVP 기능을 완성하고 코드 리팩토링, 테스트를 진행하던 와중에 한가지 의문점이 생겼다.

좋은 코드는 하나의 모듈은 하나의 책임만 져야한다. 응집도는 높을수록 결합도는 낮을수록 좋다.

 

그러나 내 프로젝트에서 기존의 인증 흐름에서 서비스 계층에서 서블릿api와 세션을 직접 다루고 있다는것을 깨달았다.

서비스 계층은 본질적으로 비즈니스 규칙을 구현하는 곳인데, 서비스가 직접 `HttpSession`을 직접 읽고/쓰게되면 서비스가 "웹 요청/응답 컨텍스트"에 종속되게 된다.

 

그래서 결국 내가 작성한 코드는 "로그인은 웹 세션 기반으로만 가능"해진 확장이 불가능한 코드가 되어버렸다.


기존의 코드

서비스 계층에서 직접 서블릿 의존을 다루고 있는 모습을 알 수 있다. 

이 때문에 테스트 코드 작성시에도 나는 서비스 단위 테스트를 진행하려 했지만 Mock을 사용한 웹 컨텍스트 의존 테스트로 변질되었다. (코드 작성도 힘들어지고 어찌저찌 테스트는 성공했어도 Mock 지옥에 빠지게되었다...)


책임을 분리하자

/*
* HTTP 세션 + Security 저장/정리 전담 컴포넌트
* 서비스는 서블릿 API를 알 필요없이 이 컴포넌트를 컨트롤러에서 호출
* */

@Component
public class SessionManager {

    public void storeAuthentication(HttpServletRequest request, Authentication authentication) {
        HttpSession session = request.getSession(true);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
    }

    public void clearSession(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }
        SecurityContextHolder.clearContext();
    }
}

 

`SessionManager`라는 HTTP 세션/Security을 전담하는 컴포넌트를 생성해 서비스 계층에서 책임을 분리하였다.

`Service` 계층의 로직과 `Controller`계층의 로직을 수정하여 하나의 계층이 하나의 책임만 질 수 있도록 리팩토링하였다.


결론은?

  • 단일 책임: 서비스는 인증 검증·도메인 로직만, 세션/HTTP 처리는 웹 계층으로 분리되어 레이어 경계가 명확해졌다.
  • 테스트 용이성: 서비스 테스트에서 서블릿 모킹이 사라져 가볍게 유지 가능, 컨트롤러 테스트는 세션 흐름만 집중 검증.
  • 확장성: 세션 저장소 변경(예: Redis)이나 인증 흐름 조정 시 웹 계층만 교체하면 되어 변경 영향 범위가 줄었다.

'Develop > Spring' 카테고리의 다른 글

[JPA] 회원 도메인  (0) 2025.12.02
[JPA] 변경 감지와 병합(merge)  (0) 2025.12.02
[JPA] 도메인 분석 설계  (0) 2025.12.02
[MVC] 요청 매핑  (0) 2025.12.02
[MVC] 핸들러 매핑과 핸들러 어댑터  (0) 2025.12.02
cayman031
@cayman031 :: 그누로그

목차