- 배운 점
- 어려웠지만 해결한 주요 내용
- 주요소스코드
1. 배운 점
백엔드 개발 측면에서 배운 점
- 도메인 중심 설계의 이점을 몸소 느꼈다
- 기존에는 계층형 패키지 구조를 주로 사용했지만, 이번에는 도메인 중심 구조를 도입하면서 기능별로 코드를 응집시키는 것이 유지보수에 훨씬 유리하다는 점을 체감했다. 서비스가 커질수록 이 구조가 코드의 복잡도를 낮추고 협업에도 유리하다는 걸 실감할 수 있었다.
- JWT 인증의 전체 흐름과 보안 설계의 중요성을 깊이 이해하게 됐다
- 단순한 토큰 발급을 넘어서, Access/Refresh Token을 분리하고 Refresh Token Rotation을 적용하는 방식을 도입하며, 인증 시스템의 보안 설계에 대해 실무 수준의 고민을 할 수 있었다. Redis를 활용한 토큰 저장과 무효화 처리 경험을 통해 토큰 탈취에 대한 대응 능력과 인프라 연결까지 고려한 설계 감각을 키울 수 있었다.
- OAuth2 인증은 단순 연결이 아닌, 책임 분리를 어떻게 할지의 문제임을 알게 되었다
- 이전에는 프론트에서 처리하던 OAuth 인증을 이번에는 백엔드가 전담하면서, 외부 인증 흐름을 우리 시스템 안에 끌어들이고, 사용자 상태를 완전히 통제하는 경험을 할 수 있었다. 보안과 유지보수를 고려했을 때 이 방식이 갖는 장점을 직접 체득했고, OAuth2UserService를 커스터마이징하는 과정을 통해 인증에 대한 이해도가 확장되었다.
- WebSocket과 STOMP를 활용한 실시간 통신 구조를 처음부터 끝까지 설계해본 경험
- 메시지 흐름, 구독 주소 관리, 방별 연결 관리 등을 설계하면서, 단순한 실시간 통신이 아닌 확장성과 유지보수까지 고려된 구조를 어떻게 만들 것인지 고민해볼 수 있었다. 특히, Redis Pub/Sub와 연동하여 채팅 메시지를 브로드캐스트하는 구조는 실시간 아키텍처에 대한 이해를 한 단계 끌어올리는 경험이었다.
- API 응답은 기능보다 일관성이 중요하다는 걸 실감했다
- 공통 응답 포맷(
ApiResponse
)과 전역 예외 처리(@RestControllerAdvice
)를 적용하면서, 개발자 경험과 클라이언트와의 협업 효율성이 얼마나 달라지는지 체감했다. 이는 기술보다 커뮤니케이션이 중요한 백엔드의 역할을 다시 한번 느끼게 해준 부분이었다.
- 스프링 시큐리티의 구조와 흐름을 이해하고 제어할 수 있게 되었다
- 직접
UsernamePasswordAuthenticationFilter
를 상속하여 로그인 요청을 가로채고, JWT 토큰을 발급한 뒤, 매 요청마다 OncePerRequestFilter
를 통해 인증 정보를 검증하고 스프링 시큐리티 컨텍스트에 주입하는 과정을 구성하면서, 시큐리티 필터 체인의 작동 순서와 역할을 명확하게 이해하게 되었다.
- 또한, 커스텀 로그아웃 핸들러를 통해 Redis에 저장된 리프레시 토큰까지 삭제함으로써 보안적으로 완결된 로그아웃 흐름을 구현하며, 보안이라는 것이 단순히 차단이 아닌 전반적인 상태 관리를 포함한 설계 문제라는 것을 배울 수 있었다.
- 이 경험을 통해 스프링 시큐리티가 제공하는 기본 기능 위에 내가 원하는 인증 흐름을 입힐 수 있다는 자신감을 갖게 되었고, 실무에서도 필요한 보안 정책을 직접 구현할 수 있을 것이라는 감각이 생겼다.
프론트 개발 측면에서 배운 점
- 컴포넌트를 목적에 맞게 분리하고 설계하는 것이 얼마나 중요한지 느꼈다
- 초반에는 모든 기능을 하나의 컴포넌트에 몰아넣는 실수를 했지만, 점차 기능별로 컴포넌트를 나누고 역할을 분리하면서 구조적인 코드의 가독성과 유지보수성의 차이를 몸으로 실감했다. 특히, 재사용 가능한 컴포넌트를 만들수록 다른 기능을 개발할 때도 훨씬 수월하다는 걸 배웠다.
- React의 생명주기를 이해하지 않고는 복잡한 기능을 구현할 수 없다는 걸 체감했다
- WebRTC 연결이나 WebSocket 채팅처럼 실시간성이 중요한 기능은 단순히 화면에 렌더링하는 것과는 차원이 달랐다.
useEffect
, cleanup
, useRef
를 통해 언마운트 시 자원을 정리하지 않으면 메모리 누수나 중복 연결 같은 문제가 생긴다는 걸 직접 경험했다.
- STOMP 기반의 실시간 통신 구조를 직접 구축해보며 실시간 시스템의 동작 원리를 이해하게 됐다
/sub/room/{id}
와 /pub/room/{id}
처럼 pub/sub 경로를 명확히 나누고, 메시지의 흐름과 WebSocket 연결 타이밍을 컨트롤하면서 실시간 채팅 시스템이 단순히 메시지를 주고받는 것이 아니라 상태와 구조까지 설계하는 일임을 깨달았다.