Skip to content

[김현창] WAS 서버 패키지 구조 리팩터링#92

Merged
github-actions[bot] merged 9 commits intosofteerbootcamp-7th:codingbaraGofrom
codingbaraGo:develop
Jan 5, 2026
Merged

[김현창] WAS 서버 패키지 구조 리팩터링#92
github-actions[bot] merged 9 commits intosofteerbootcamp-7th:codingbaraGofrom
codingbaraGo:develop

Conversation

@codingbaraGo
Copy link

@codingbaraGo codingbaraGo commented Jan 5, 2026

작업

  • 패키지 구조 리팩터링
  • 2주차 과제에 대한 Issue 발행

내가 짠 패키지의 구조가 상당히 난잡하다 느꼈다.
처음에 제시된 코드를 최대한 유지하려다 보니 구조가 꼬여버린 것 같다.
2,3주차 과제를 대비해 확장성을 확보하기 위해 대대적인 패키지 구조 리팩토링을 진행했다.
이를 위해 Spring MVC의 패키지 구조는 어떤 식으로 구축되어있는가를 공부해 참고했다.


고민 & 배운 점

Spring MVC 패키지 구조

Spring MVC 코드를 보면 org.springframework.web.servlet에는 DispatcherServlet, HandlerMapping, HandlerAdapter, ViewResolver, View, ModelAndView 같은 핵심 규약과 공통 타입이 모여 있고, 구체 구현은 org.springframework.web.servlet.mvc.method.annotation처럼 하위 패키지로 내려가 있다.

여기서 핵심은 “인터페이스만 모아둔다/구현체만 모아둔다” 같은 단순 규칙이 아니라, **프레임워크가 의존하는 안정적인 중심부(SPI + 공통 데이터 구조)**를 최상위에 두고, 기술/전략별 구현은 분리해 교체 가능하게 만든다는 점이다.
예를 들어 ModelAndView는 ViewResolver에 종속된 타입이라기보다, DispatcherServlet 파이프라인에서 “핸들러 실행 결과를 뷰 렌더링 단계로 전달”하기 위한 공통 운반체이기 때문에 web.servlet의 핵심 타입으로 위치한다.

=> 핵심 규약과 공통 모델은 중심에, 구현체는 하위 패키지로

엔진(프레임워크)과 앱(기능 코드)의 분리

직접 WAS를 만들 때 가장 먼저 정리해야 하는 것은 “이 프로젝트가 무엇을 제공하는가”의 경계다.
HTTP 파싱/응답 직렬화, 디스패칭, 핸들러 실행 같은 코드는 **프레임워크(엔진)**에 속하고, 회원가입/로그인 같은 실제 엔드포인트는 앱 코드에 속한다.
이 둘을 같은 루트 패키지에 섞어두면 규모가 커질수록 의존성 방향과 책임이 흐려진다.

따라서 이 둘을 명확하게 분리하고 아래와 같은 패키지 구조를 만들었다.

  • http: 요청 파싱, 응답 모델, socket write 등 “프로토콜” 레이어
  • web/dispatch: Dispatcher, HandlerMapping, HandlerAdapter 같은 “요청 처리 엔진” 레이어
  • web/handler: 애플리케이션 핸들러(엔드포인트)
  • web/result, web/render: 핸들러 결과와 이를 HTTP 응답으로 만드는 단계
  • exception: 예외 모델과 예외 → 응답 변환 정책
  • app: 실제 기능(도메인/핸들러)

HandlerAdapter 설계

Handler에서 다양한 Argument를 받도록 하기 위해 adapter를 사용하기로 했다.
adapter 설계에서 처음에는 Argument 타입 + Return 타입(json인지, static view인지, rendered view인지 등) 페어당 하나의 adapter를 만들어야 한다 생각했다.
그런데 이러면 adapter의 개수가 argument 타입 수 * return 타입 수 가 되어버린다.

만약 새로운 형태의 argument를 받는 handler를 추가한다고 가정하면 adapter는 지원하는 return 타입의 개수만큼 만들어야하는 문제가 생긴다.

이 부분에서는 GPT의 조언을 받았다.

반환값을 하나의 인터페이스로 통일하고, 반환된 인스턴스를 renderer에서 처리해 json을 만들거나, view를 렌더링 하는 등의 작업을 하도록 설계했다.

Redirect 처리

예전에 프로젝트를 할 때에는 이미 구현된 클래스의 메서드만 호출하면 되었기에 리다이렉트 처리에 대해 공부를 했다.

리다이렉트는 상태 코드를 3XX 로 설정하고 Location 헤더에 리다이렉트할 uri를 설정한다.
브라우저는 일반적으로 이를 자동으로 따라가며 새 요청을 보낸다. 다만 어떤 상태코드를 쓰느냐에 따라 의미가 달라진다.

  • 화면 이동: 보통 302
  • POST 후 GET으로 전환(PRG 패턴): 303이 의도가 더 명확
  • 메서드/바디 유지: 307, 308

AI 활용

  • 패키지 리팩토링 시 이름이 애매하다 느낀 패키지와 클래스의 네이밍을 추천받음
  • HandlerAdapter 설계 시 Renderer를 Adapter 밖으로 분리하여 Handler의 반환 값을 Adapter 밖에서 처리하는 구조를 제안받아 채택함
  • PR 코드리뷰를 통해 잠재적 취약점 및 네이밍 에러 등에 대한 피드백을 받음 코드리뷰 링크

- HttpResponse::setBody 메서드 내부에서 Content-Length, Content-Type 등의 Body 관련 헤더를 설정하도록 책임 포인트 변경
- Post Handler의 File 읽기 관련 코드 리펙토링
- HttpServlet -> ConnectionHandler
- WasServlet -> Dispatcher
- 구성 요소들을 web 패키지 아래에 수평적 구조로 구성
- exception 패키지 분리
@codingbaraGo codingbaraGo self-assigned this Jan 5, 2026
@github-actions github-actions bot merged commit 0aca569 into softeerbootcamp-7th:codingbaraGo Jan 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments