기억하는가? 이 책의 첫 장에서 우리는 단 두 줄의 코드 앞에 멈춰 섰다.
const res = await fetch("/api/tasks");
const tasks = await res.json();
그때 우리는 물었다. 이 fetch가 보낸 요청은 도대체 어디로 가는가, 그 반대편에서는 누가 무엇을 하고 있는가. 서버는 그저 JSON을 뱉어내는 블랙박스였고, 빨간 에러가 뜨면 백엔드 담당자에게 슬랙을 보내는 게 우리가 할 수 있는 전부였다.
이제 같은 두 줄을 다시 보자. 느낌이 다르지 않은가? 이 요청이 어떤 경로로 서버에 닿고, 누가 그것을 라우팅하고, 어떤 컨트롤러가 받아 어떤 서비스로 넘기고, 어떤 SQL이 나가고, 어떤 상태코드로 돌아오는지, 이제 당신은 그 반대편을 전부 그릴 수 있다. 더는 블랙박스가 아니다. 첫 장에서 살짝 열렸던 뚜껑이 열세 개의 장을 지나며 완전히 열린 셈이다. 그러니 마지막 장에서는 손을 멈추고, 걸어온 길을 천천히 돌아보자. 그런 다음 어디로 한 걸음 더 내디딜지 함께 가늠해 보자.
우리가 걸어온 길을 잇대어 보면
지금까지 배운 것을 따로따로 떠올리면 그저 개념의 목록처럼 보인다. REST, JPA, 보안, SSR…. 하지만 이것들은 나열된 항목이 아니라 하나의 흐름이었다. 잇대어 보자.
출발은 시점의 전환이었다. 1장에서는 fetch를 뒤집어 클라이언트의 HTTP를 서버의 HTTP로 다시 봤다. 상태코드는 받는 것이 아니라 내가 정하는 책임이 됐고, 서버는 라우팅 → 역직렬화 → 검증 → 처리 → 직렬화의 5단계 파이프라인으로 또렷해졌다. 이 멘탈 모델이 없었다면 그다음 모든 것이 마법으로만 보였을 것이다.
그래서 3장부터 손을 움직여 첫 엔드포인트를 띄웠고, 4장에서 “아무것도 new 하지 않았는데 어떻게 연결됐나”라는 마법을 DI와 IoC로 걷어냈다. 5장에서는 그 위에 제대로 된 REST API를 올렸다. DTO로 입구를 지키고, 전역 예외로 에러를 길들였다. 1장에서 “증상”으로만 심어 둔 빨간 CORS 에러도 마침내 서버의 책임으로 회수해 풀었다. 그리고 @WebMvcTest로 첫 테스트를 심었다.
여기서부터는 그 API에 점진적으로 살을 붙이는 여정이었다. 6장에서 메모리에 살던 데이터를 JPA로 DB에 눌러 담되, API 계약은 깨지 않았다. 7장에서 영속성 컨텍스트라는 “출석부”의 마법(더티 체킹·지연 로딩)을 들여다봤고, 8장에서 그 마법이 운영에서 N+1로 터지는 순간과 “SQL 로그를 직접 보라”는 규율을 익혔다. 편의에서 누수로 이어지는 자연스러운 순서였다.
그다음은 가장 큰 산, 보안이었다. 한 번에 오르지 않고 세 걸음으로 나눴다. 9장에서 “필터체인이 요청을 가로챈다”는 새 멘탈 모델을 세우고, 10장에서 JWT로 stateless 인증을 구현하며 신선도 함정의 클라이맥스를 터뜨렸다. 11장에서는 같은 프로젝트에 세션 방식을 두 번째로 얹어, 두 길을 직접 비교하고 “무엇을 언제 고를지” 판단하는 눈을 길렀다. 12장에서 Thymeleaf로 서버가 그리는 화면을 더해 SSR과 CSR을 손에 쥔 도구로 정리했다. 그리고 마침내 13장에서 그 모든 검증 능력을 무기 삼아 AI와 함께 기능 하나를 스펙에서 동작까지 완주했다.
보이는가? 이건 흩어진 지식이 아니라 한 그루의 나무가 자라는 과정이었다.
TaskBoard 하나가 모든 것을 엮었다
그 나무의 줄기가 TaskBoard다. 우리는 따로 노는 예제 열네 개를 만든 게 아니다. 3장에서 메모리에 사는 빈약한 할 일 목록 하나로 시작한 프로젝트는 장을 지날수록 DB와 연관관계, 인증, 관리자 화면을 차례로 갖췄고, 끝내 AI와 함께 새 기능까지 붙는 어엿한 백엔드로 자랐다.
이 연속성이 왜 중요했을까? 개념을 따로 배우면 “이건 알겠는데 실제로 어디에 쓰지?”라는 찜찜함이 늘 남는다. 하지만 하나의 프로젝트가 자라는 걸 지켜보면, 모든 개념이 어떤 문제를 풀기 위해 등장했는지 몸으로 알게 된다. CORS 설정은 React 앱이 막혔기 때문에, DTO는 엔티티를 그대로 노출하기 찜찜했기 때문에, N+1 해법은 운영에서 느려졌기 때문에 필요했다. 개념이 먼저가 아니라 문제가 먼저였다. 이것이 이 책이 택한 길이고, 당신이 앞으로 새 기술을 배울 때도 가져갈 만한 태도다. 동작하는 것을 먼저 세우고, 막히는 지점에서 개념을 끌어오자.
왜 3.x로 시작했는지, 이제 답할 차례
이제 책 전체를 관통하던 한 가닥 실을 매듭지을 때다. 기억하는가? 2장에서 정직하게 고백했다. 우리는 Spring Boot 3.x로 배우지만, 이미 더 새로운 버전이 나와 있다고. 그때 미뤄 둔 약속, “4.x로의 전망은 마지막 장에서 다시 만난다”를 지킬 차례다.
먼저 시점을 못 박자. 2026년 5월 기준으로 Spring Boot의 최신 stable은 4.0 계열이고 그 바탕인 Spring Framework는 7.0이다. 우리가 배운 3.5는 OSS 커뮤니티 지원 종료가 코앞이다(상용 지원은 그보다 한참 더 길게 이어진다). 다만 버전 숫자와 날짜는 빠르게 바뀌는 영역이니, 정확한 패치 버전과 지원 종료일은 늘 공식 문서를 함께 확인하자.
원문 보정 · 앱 보충2026년 10월에 다시 확인해 보니 그사이 3.5의 OSS 지원은 2026-06-30에 끝났고(마지막 OSS 패치 3.5.16), 최신 stable은 4.1 계열(4.1.1)로 넘어갔다. start.spring.io도 이제 4.0 이상만 만들어 준다. 3.5 프로젝트를 만드는 법은 3장의 보정 상자를 보자.
3.x로 배운 것 중, 4.x로 갈 때 다시 건너지 않아도 되는 가장 큰 강은?
require에서 ESM import로의 전환javax.* → jakarta.* 전환javax.persistence가 클래스패스에 없어서 섞이는 순간 컴파일부터 실패한다. 그래서 import 줄 한 번 훑기가 가장 싼 검증이 된다.그렇다면 4.x에서는 무엇이 달라질까? 큰 줄기만 가늠해 두자. 하나는 Jackson 3로의 메이저 전환이다. 5장에서 당연하게 쓰던 JSON 직렬화의 바탕 라이브러리가 한 단계 올라간다. 또 하나는 API versioning 지원처럼 같은 API의 여러 버전을 다루는 기능이 프레임워크 차원에서 더 매끄러워지는 방향이다. 이 변경 목록은 2026년 5월 기준의 가늠일 뿐이고 시점에 따라 달라지니, 실제 마이그레이션 전에는 공식 마이그레이션 가이드를 1차 근거로 확인하는 편이 낫다.
3.x → 4.x 카드 · 앱 보충 (이 장 내용 요약)
- 시점: 2026년 5월 기준 최신 stable은 Spring Boot 4.0 계열, 바탕은 Spring Framework 7.0이다. 3.5는 OSS 커뮤니티 지원 종료가 코앞이고 상용 지원은 더 길다. 정확한 날짜는 공식 지원 일정에서 확인한다.
- 그대로 가는 것:
jakarta.*네임스페이스. 3.0에서 이미 건넌 강이다.- 새로 만나는 것 ①: Jackson 3로의 메이저 전환. 5장에서 당연하게 쓰던 JSON 직렬화의 바탕 라이브러리다.
- 새로 만나는 것 ②: API versioning처럼 같은 API의 여러 버전을 프레임워크 차원에서 다루는 기능.
- 검증 리듬: 읽고, 버전을 식별하고, 동작을 확인한다. 마이그레이션 전에는 공식 마이그레이션 가이드를 1차 근거로 삼는다.
여기서 책 내내 길러 온 능력이 그대로 작동한다. 새 버전으로 넘어갈 때 AI에게 마이그레이션 코드를 부탁하면, AI는 또 십중팔구 시점이 어긋난 코드를 자신 있게 내밀 것이다. 3.x 코드를 4.x인 척 줄 수도, 4.x 코드를 3.x인 척 줄 수도 있다. 그때 당신은 2장에서 약속한 그 리듬을 꺼내면 된다. 읽고, 버전을 식별하고, 동작을 확인한다. WebSecurityConfigurerAdapter를 잡아냈던 그 눈으로, 이번엔 Jackson 2와 3의 차이를 잡아낼 수 있다. 도구가 바뀌었을 뿐, 무기는 그대로다.
입문 너머의 지도
이 책은 입문서다. 그러니 끝은 곧 또 다른 시작이다. 그렇다면 여기서 어디로 가야 할까? 욕심내어 한꺼번에 다 가지 말고, 갈 만한 길 몇 갈래만 지도에 표시해 두자.
먼저 테스트를 더 깊이 파 보자. 우리는 5장과 8장에서 슬라이스 테스트의 맛만 봤다. 통합 테스트, 테스트 컨테이너로 진짜 DB를 띄워 검증하는 법, 13장에서 살짝 스친 테스트 주도 개발(TDD)까지 파고들 거리가 많다. 테스트는 AI 시대에 “내 코드가 맞다”는 것을 증명하는 가장 강력한 무기다. 다음으로 배포다. 만든 API를 내 노트북 밖으로 내보내는 일, 즉 Docker로 컨테이너에 담고 클라우드에 올리는 흐름은 백엔드 개발자의 또 다른 절반이다. 그리고 관찰 가능성(observability)이 있다. 로그·메트릭·추적으로 “운영 중인 서버 안에서 지금 무슨 일이 벌어지는지” 들여다보는 능력이다. 8장에서 SQL 로그를 켜 본 그 감각의 확장판이라고 생각하면 된다.
이 길들을 지금 다 갈 필요는 없다. 다만 한 가지는 분명하다. 입문자에서 한 걸음 더 나아간 당신은 이제 이 지도를 보고 스스로 다음 목적지를 고를 수 있는 사람이 됐다. 그게 이 책이 정말로 남기고 싶었던 것이다.
마무리 — 검증은 끝까지 사람의 몫
여정의 끝에서 딱 한 가지만 당부하고 싶다. 이 책의 처음과 끝을 관통한 그 약속이다.
우리는 AI와 함께 배웠다. AI는 더없이 든든한 동반자였다. 개념을 설명해 줬고, 보일러플레이트를 대신 타이핑해 줬고, 막막한 빈 화면 앞에서 첫 줄을 띄워 줬다. 앞으로도 그럴 것이고, 그 능력은 점점 더 좋아질 것이다. 하지만 열네 개의 장을 지나며 거듭 확인한 진실이 있다. AI는 자신 있게 틀린다. 시간이 멈춘 평균값을 정답인 양 내밀고, 우리 상황에 맞는지는 알지 못한다.
그래서 우리는 Spring을 직접 배웠다. 코드를 처음부터 타이핑하기 위해서가 아니라, AI가 건넨 코드를 읽고 옳고 그름을 가려내기 위해서. javax인지 jakarta인지 식별하고, SQL 로그로 N+1을 잡아내고, 검증 규칙이 우리 비즈니스와 맞는지 따지고, 테스트로 동작을 단언하는 눈을 갖기 위해서였다. 이 눈은 버전이 4.x로, 5.x로 바뀌어도 낡지 않는다. 오히려 AI가 더 강력해질수록 더 귀해진다.
기억해 두자. 도구는 끊임없이 바뀐다. Spring도, JPA도, AI도, 어쩌면 이 책에 적힌 버전 숫자들도 머지않아 옛것이 될 것이다. 하지만 새로운 것을 만나 읽고, 의심하고, 1차 근거로 검증하는 태도는 바뀌지 않는다. 그 태도 하나만 손에 쥐고 있으면, 당신은 앞으로 어떤 새 기술을 만나도 더는 블랙박스 앞에서 막막해하지 않는다.
fetch 두 줄에서 출발한 여정이 여기서 끝난다. 아니, 끝이 아니라 이제 막 당신만의 길이 시작되는 지점이다. 그 길 위에서, AI를 동반자로 삼되 키는 끝까지 당신이 쥐자. 여기까지 함께 걸어 준 당신에게, 진심으로 고맙다.
원문 보정 · 앱 보충원문은 이 마무리 절과 바로 다음 에필로그에서 같은 맺음말(“
fetch두 줄에서 출발한 여정”, “함께 걸어 준 당신에게, 진심으로 고맙다”)과 다음 걸음 안내를 거의 그대로 되풀이한다. 에필로그는 책 전체를 한 번 더 정리하는 글이니, 겹치는 문장은 건너뛰어도 된다.
에필로그 — 키는 끝까지 당신이 쥐자
fetch 두 줄에서 시작한 여정이 여기까지 왔다. 잠시 숨을 고르고, 우리가 무엇을 얻었는지 한 번 더 또렷이 새겨 두자.
처음 이 책을 펼쳤을 때, 서버는 블랙박스였다. 요청을 던지면 JSON이 돌아오고, 빨간 에러가 뜨면 백엔드 담당자에게 슬랙을 보내는 게 우리가 할 수 있는 전부였다. 이제는 다르다. 요청 하나가 라우팅되고, 역직렬화되고, 검증되고, 처리되고, 직렬화되어 돌아오는 그 5단계를 당신은 그릴 수 있다. DTO로 입구를 지키고, 전역 예외로 에러를 길들이고, JPA의 출석부가 부리는 마법을 SQL 로그로 들여다보고, 필터체인에 인증 검문소를 끼우고, 트레이드오프를 견주어 보안 방식을 고르고, 서버가 직접 화면을 그리게 하고, 끝내 AI와 함께 기능 하나를 스펙에서 동작까지 완주했다. TaskBoard 하나가 그 모든 것을 엮어 냈다.
하지만 이 책이 진짜로 남기고 싶었던 건 Spring이나 JPA의 문법이 아니다. 그것들은 머지않아 옛것이 된다. 이 책에 적힌 버전 숫자도, API 시그니처도, 어쩌면 곧 바뀔 것이다. 정작 낡지 않는 건 읽고, 의심하고, 1차 근거로 검증하는 태도다. AI가 자신 있게 내미는 코드 앞에서 “이거 지금 시점에 맞아?”를 물을 수 있는 눈. javax인지 jakarta인지 가려내고, SQL 로그로 N+1을 잡아내고, 검증 규칙이 우리 비즈니스와 맞는지 따지고, 테스트로 동작을 단언하는 그 눈. AI가 강력해질수록 코드를 만드는 일은 점점 더 AI의 몫이 되고, 사람의 가치는 코드를 판단하는 데로 옮겨 간다. 그래서 AI 시대에 백엔드를 배우는 의미는 사라지기는커녕 더 또렷해진다.
다음 한 걸음은 당신이 고를 차례다. 테스트를 더 깊이 파거나(통합 테스트·테스트 컨테이너·TDD), 만든 API를 노트북 밖으로 내보내거나(Docker·클라우드 배포), 운영 중인 서버 안을 들여다보는 능력(로그·메트릭·추적, 곧 관찰 가능성)으로 나아갈 수 있다. 한꺼번에 다 갈 필요는 없다. 다만 이제 당신은 이 지도를 보고 스스로 다음 목적지를 정할 수 있는 사람이 됐다.
도구는 동반자다. 그러나 키는 끝까지 당신이 쥐자. 여기까지 함께 걸어 준 당신에게, 진심으로 고맙다. 이제 당신만의 길이 시작된다.
1. (1장) 서버를 5단계 파이프라인으로 볼 때 올바른 순서는?
2. (4장) 아무것도 new 하지 않았는데 컨트롤러에 서비스가 들어와 있는 이유는?
3. (5장) React 앱에서 CORS 에러가 났다. 허용 여부를 정하는 쪽은?
4. (7장) save()를 부르지 않았는데 UPDATE가 나간 이유는?
5. (8장) “목록 + 페이징 + 컬렉션 연관관계”에서 피해야 할 조합은?
6. (9장) 필터체인에서 인증 정보가 없는 요청과 권한이 없는 요청이 돌려받는 상태코드는 각각?
7. (10장) AI가 준 Security 설정에서 신선도 함정으로 의심해야 할 것은?
8. (11장) 브라우저로만 접속하는 단일 웹 앱이고 즉시 로그아웃이 중요하다면 책의 가이드는?
책을 덮기 전에 내 프로젝트가 지금 어느 버전 위에 서 있는지부터 확인합니다.