[김현창] WAS 서버 패키지 구조 리팩터링#92
Merged
github-actions[bot] merged 9 commits intosofteerbootcamp-7th:codingbaraGofrom Jan 5, 2026
Merged
[김현창] WAS 서버 패키지 구조 리팩터링#92github-actions[bot] merged 9 commits intosofteerbootcamp-7th:codingbaraGofrom
github-actions[bot] merged 9 commits intosofteerbootcamp-7th:codingbaraGofrom
Conversation
- HttpResponse::setBody 메서드 내부에서 Content-Length, Content-Type 등의 Body 관련 헤더를 설정하도록 책임 포인트 변경 - Post Handler의 File 읽기 관련 코드 리펙토링
- HttpServlet -> ConnectionHandler - WasServlet -> Dispatcher
- 구성 요소들을 web 패키지 아래에 수평적 구조로 구성 - exception 패키지 분리
develop <- refactor/architecture/#24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
작업
내가 짠 패키지의 구조가 상당히 난잡하다 느꼈다.
처음에 제시된 코드를 최대한 유지하려다 보니 구조가 꼬여버린 것 같다.
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를 설정한다.브라우저는 일반적으로 이를 자동으로 따라가며 새 요청을 보낸다. 다만 어떤 상태코드를 쓰느냐에 따라 의미가 달라진다.
302303이 의도가 더 명확307,308AI 활용