자, 이런 상황을 상상해 보자. Cursor 채팅창에 “Spring Boot로 로그인 API 만들어줘”라고 한 줄 적었더니, 몇 초 만에 그럴듯한 코드가 주르륵 쏟아진다. @RestController, 시큐리티 설정, 토큰 발급까지 빠짐없이 들어 있다. 컴파일도 된다. 화면에는 응답까지 찍힌다.
그런데 묘하게 마음 한구석이 찜찜하다. 이게 맞는 코드인지, 좋은 코드인지, 심지어 지금 시점에 쓰면 안 되는 옛날 코드인지 나로서는 판단할 길이 없기 때문이다. 동작은 하는데 왜 동작하는지를 모르니까. 프런트엔드를 하던 시절을 떠올려 보자. useEffect가 두 번 도는 이유를 모른 채 의존성 배열만 이리저리 바꿔 가며 운에 맡겨 본 적 있지 않은가? 딱 그 느낌이다. 다만 이번엔 그 블랙박스가 서버 전체로 커졌을 뿐이다.
그렇다면 우리는 무엇을 더 배워야 할까? AI가 코드를 다 써 주는 시대에, 굳이 Spring을 직접 공부하는 의미는 어디에 있을까? 이 장에서 우리가 맺을 약속, 곧 이 책 전체를 관통하는 학습 계약이 그 질문에 대한 답이다.
AI가 잘하는 것과, 결국 내 몫인 것
먼저 솔직해지자. AI는 정말 잘한다. 특히 세 가지에 강하다. 처음 보는 개념을 눈높이에 맞춰 설명해 주는 일, 매번 똑같이 반복되는 보일러플레이트를 대신 타이핑해 주는 일, 그리고 빈 프로젝트에 뼈대(스캐폴드)를 빠르게 세워 주는 일이다. 엔티티 클래스 하나 만들어 달라거나, 컨트롤러 기본 틀을 잡아 달라는 부탁에는 거의 실수가 없다. 이런 일을 사람이 손으로 하던 시절과 비교하면, AI는 분명 강력한 학습 가속기다.
그런데 여기서 한 가지 의문이 생긴다. 그렇게 다 잘하면, 나는 뭘 해야 하나?
남는 건 판단이다. 이 검증 규칙이 우리 서비스의 비즈니스 요구와 맞는가, 이 API가 잘못된 요청을 품위 있게 거절하는가, 이 코드가 운영 환경에서 터지지는 않을까, 그리고 무엇보다 — 이 코드가 지금 이 버전에 맞는 코드인가. 이런 판단은 AI에게 통째로 맡길 수 없다. AI는 일반론을 말하고, 우리 상황의 결정은 사람이 내린다.
| AI가 잘하는 것 | 결국 내 몫인 것 |
|---|---|
| 개념 설명, 보일러플레이트, 스캐폴드 | 비즈니스 로직·검증 규칙 설계 |
| “이거 어떻게 해?”의 첫 답 | “이게 우리한테 맞아?”의 최종 판단 |
| 코드를 빠르게 만들어내기 | 만들어진 코드를 읽고 검증하기 |
이 표가 이 책에서 맺는 첫 번째 약속이다. AI는 코드를 만들고, 검증은 사람이 한다. 그래서 우리는 Spring을 배운다. 코드를 처음부터 타이핑하기 위해서가 아니라, AI가 건넨 코드를 읽고 옳고 그름을 가려내기 위해서. 그 눈을 갖는 것이 이 책의 목표다.
AI가 자신 있게 틀리는 순간 — 신선도 함정
이제 이 책에서 가장 자주 부딪히게 될 함정 하나를 미리 꺼내 두자. 워낙 중요해서 책 전체를 관통하는 보조 서사이기도 하다. 바로 버전 신선도 함정이다.
상황을 가정해 보자. AI에게 Spring Security 설정을 부탁한다. 그러면 십중팔구 이런 코드가 돌아온다.
// AI가 자신 있게 건네는 코드 — 그런데 이건 옛날 방식이다
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
}
이 코드를 Spring Boot 3.5(Spring Security 6.x) 프로젝트에 그대로 붙여 넣으면?
원문 보정 · 앱 보충원문은 “컴파일이 될 수도 있다”, “
antMatchers도 더는 권장되지 않는다”고 했지만 실제로는 더 단호하다. Spring Boot 3.x가 쓰는 Spring Security 6.x에는WebSecurityConfigurerAdapter도,antMatchers·mvcMatchers도 아예 없다. 그래서 위 코드는 3.x 프로젝트에서 컴파일되지 않는다. 컴파일이 되던 건 Spring Boot 2.x 시절 이야기다(2.7이 쓰는 Security 5.7부터는 deprecated 경고와 함께).authorizeRequests만은 6.x에 남아 있지만 deprecated라서, 새 코드에서는authorizeHttpRequests를 쓴다.
AI는 왜 옛날 코드를 이렇게 자신 있게 내밀까?
ReactDOM.render(<App />, root), 클래스 컴포넌트의 componentWillMountWebSecurityConfigurerAdapter, antMatchers, javax.*javax→jakarta나 Security 6.0의 어댑터 제거 같은 메이저 경계에서는 옛 코드가 아예 컴파일되지 않는다. 대신 실패가 빨리, 크게 드러난다.이런 함정은 한둘이 아니다. 대표적인 것만 미리 이름표를 붙여 두자.
javax.*→jakarta.*(예:javax.persistence가jakarta.persistence로)WebSecurityConfigurerAdapter(제거됨 →SecurityFilterChain빈으로)authorizeRequests→authorizeHttpRequestsantMatchers→requestMatchers
지금은 이 패턴들을 외울 필요는 없다. 그저 “이런 식으로 옛 코드와 새 코드가 갈린다”는 감만 챙겨 두면 된다. 첫 번째 javax.*/jakarta.* 함정은 바로 다음 장에서 직접 프로젝트를 만들며 import 한 줄로 마주한다. WebSecurityConfigurerAdapter가 터지는 보안의 클라이맥스는 9장에서 제대로 다룬다. 여기서는 “AI가 자신 있게 옛날 코드를 줄 수 있다”는 사실 하나만 마음에 새겨 두자. 이 한 문장이 앞으로 모든 코드를 의심의 눈으로 다시 보게 만들 테니까.
원문 보정 · 앱 보충장 번호를 바로잡자.
WebSecurityConfigurerAdapter함정은 9장에서 예고만 하고, before/after로 정면에서 다루는 곳은 10장(JWT)이다. 서문의 “10장(보안)에서 정면으로 터뜨리고”가 맞다.
왜 하필 3.x로 배우는가
여기서 정직하게 짚고 넘어갈 게 하나 있다. 우리는 이 책에서 Spring Boot 3.x(특히 3.5)를 기준으로 배운다. Java는 17 또는 21 LTS, 네임스페이스는 jakarta.*다. 그런데 사실을 숨기지 말자. 2026년 5월 시점에서 보면, 이미 더 새 버전이 나와 있다.
- 최신 stable은 Spring Boot 4.0.6(2026-04-23 릴리스)이고, 그 바탕인 Spring Framework도 7.0이다.
- 게다가 우리가 배울 3.5의 OSS 커뮤니티 지원은 2026-06-30에 끝난다. (상용 지원은 2032년까지로 더 길게 이어진다.)
원문 보정 · 앱 보충원문은 2026년 5월 기준이다. 3.5의 OSS 지원 종료일(2026-06-30)은 이미 지났고, 2026년 10월에 확인해 보니 start.spring.io는 Spring Boot 4.0 이상만 고를 수 있게 바뀌어 있었다. 3장에서 프로젝트를 만들 때 이 차이를 어떻게 다룰지 따로 짚는다. 버전 정보는 이렇게 빨리 낡는다. 지원 일정은 spring.io나 endoflife.date에서 직접 확인하자. 이 장이 말하는 “1차 근거로 되짚기”를 여기서 바로 써먹는 셈이다.
“아니, 곧 지원도 끝나는 버전을 왜 배우라는 거지?” 이런 의문이 드는 게 당연하다. 답은 이렇다. 3.x가 여전히 프로덕션의 주류이기 때문이다. 지금 현업에서 돌아가는 수많은 서비스가 3.x 위에 서 있고, 채용 시장에서 마주칠 코드도 대부분 3.x다. 입문자가 가장 먼저 익혀야 할 것은 “현장에서 실제로 쓰이는 토대”다. 그리고 3.x에서 익힌 jakarta.* 같은 핵심 전환은 4.x로 넘어가도 그대로 자산이 된다. 토대를 단단히 다진 뒤 다음 한 걸음을 내딛는 편이 낫다.
그러니 이렇게 약속하자. 우리는 3.x로 배우되, “이건 곧 4.x로 옮겨 갈 수 있는 토대다”라는 사실을 잊지 않는다. 4.x로의 마이그레이션 전망은 책의 마지막 장에서 다시 만난다. 버전이라는 건 빠르게 바뀌니, 늘 공식 문서를 함께 확인하는 습관을 들여 두자.
AI를 동반자로 길들이는 작은 습관들
그렇다면 AI를 어떻게 다뤄야 할까? 맹신하지도, 외면하지도 않으면서 말이다. 거창한 방법론이 아니라, 오늘부터 바로 쓸 수 있는 작은 습관 몇 가지로 정리해 두자.
첫째, 프롬프트에 버전을 못 박는다. “Spring으로 시큐리티 설정해줘”가 아니라 “Spring Boot 3.x, Spring Security 6.x, jakarta 네임스페이스 기준으로 시큐리티 설정해줘”라고 적는다. 버전을 명시하는 것만으로도 신선도 함정에 빠질 확률이 눈에 띄게 줄어든다. AI에게 시점을 알려 주는 셈이다.
둘째, “왜?”를 끝까지 캐묻는다. 코드를 받으면 거기서 멈추지 말고 되묻자. “왜 필드 주입 대신 생성자 주입을 썼어?”, “이 코드가 실제로 실행하는 SQL을 보여줘.” AI는 답을 만들 뿐 아니라 설명도 잘한다. 이 설명을 끌어내는 것이 곧 학습이다. 답을 받는 데서 그치면 영영 블랙박스를 못 벗어난다.
셋째, 모호하면 AI가 되묻게 한다. 프롬프트 끝에 “Ask me questions”(궁금한 걸 나에게 먼저 물어봐)를 붙여 보자. 그러면 AI가 곧장 코드를 쏟아내는 대신 “인증 방식은 토큰인가요 세션인가요?” 같은 질문을 던진다. 모호함을 끌어안은 채 만들어진 코드보다, 한 번 명료해진 뒤 만들어진 코드가 훨씬 낫다.
넷째, 그리고 가장 중요한 — 받은 코드는 반드시 내 눈으로 검증한다. 검증에는 순서가 있다. 먼저 읽는다. 무엇이 무엇으로 연결되는지 따라간다. 다음으로 버전을 식별한다. javax인가 jakarta인가, 제거된 API를 쓰고 있지는 않은가. 마지막으로 동작을 확인한다. 실행해 보고, 필요하면 SQL 로그를 켜서 진짜로 무슨 일이 벌어지는지 눈으로 본다. 읽기 → 버전 식별 → 동작 확인. 이 세 박자가 앞으로 이 책의 모든 장 끝에 붙는 “AI 페어코딩 학습 포인트”의 뼈대다.
“Spring Boot 3.5 기준으로 할 일 엔티티에 제목 검증을 붙이고,
/api/public/**만 열어 두는 보안 설정도 같이 만들어줘.”의심스러운 줄을 모두 눌러 표시한 뒤 “검토 끝”을 누르세요. 함정은 3개입니다.
그런데 도구가 여러 개던데 — 언제 뭘 쓰나
마지막으로 도구 이야기를 짧게 하고 넘어가자. AI 페어코딩 도구가 여러 개라 헷갈릴 수 있다. 크게 두 갈래로만 나눠 두면 충분하다.
하나는 Cursor 같은 IDE 내장형이다. 코드를 쓰다가 그 자리에서 인라인으로 자동완성을 받거나, 선택한 코드 조각에 대해 즉석에서 물어보는 데 강하다. “이 메서드 한 줄만 고쳐줘”, “이 부분 무슨 뜻이야?” 같은 빠른 왕복에 잘 맞는다. 코드를 읽고 손보는 흐름을 끊지 않는 것이 장점이다.
다른 하나는 Claude Code나 Codex 같은 터미널 기반 도구다. 이쪽은 여러 파일에 걸친 긴 작업, 프로젝트 전체를 탐색하며 기능 하나를 처음부터 끝까지 만들어내는 장기 작업에 강하다. 예컨대 Claude Code의 Plan Mode(Shift+Tab으로 진입)를 쓰면, 곧장 코드를 짜는 대신 먼저 기존 코드를 둘러보고 작업 계획을 세우게 할 수 있다. 스펙을 함께 다듬고 큰 흐름을 잡는 데 제격이다. (도구의 구체 단축키·기능은 빠르게 바뀔 수 있으니 공식 문서를 함께 확인하자.)
둘을 어떻게 쓰면 될까? 거칠게 말하면 이렇다. 짧고 즉각적인 손질에는 IDE 내장형, 길고 구조적인 작업에는 터미널 도구. 물론 칼같이 나뉘는 건 아니고, 익숙해지면 둘을 자연스럽게 오가게 된다. 이 두 도구를 실제 기능 개발에 함께 투입하는 본격적인 워크플로우는 13장에서 직접 해 본다. 지금은 “용도가 다른 두 종류가 있다”는 정도만 알아 두면 충분하다.
마무리
이 장에서 우리는 코드를 한 줄도 직접 짜지 않았다. 대신 그보다 더 중요한 것, 곧 AI와 함께 배우는 태도를 약속했다. AI는 강력한 동반자다. 설명하고, 만들고, 거들어 준다. 하지만 동시에 시간이 멈춘 평균값을 자신 있게 내미는 의심의 대상이기도 하다. 그러니 우리의 자세는 하나다 — AI가 만들고, 검증은 끝까지 내가 한다.
이제 충분히 약속했으니, 슬슬 손을 움직일 차례다. 다음 장에서는 npm 세계에서 건너온 우리가 응답하는 Spring 서버를 가장 빠르게 직접 띄워 본다. 그리고 바로 거기서, 이 장에서 예고한 신선도 함정의 첫 실물 — AI가 슬쩍 끼워 넣는 javax.* import — 을 우리 손으로 잡아낼 것이다.
1. Spring Boot 3.x 프로젝트에서 AI가 준 코드가 import javax.persistence.Entity;로 시작한다. 어떻게 할까?
2. 신선도 함정을 줄이려고 프롬프트에 가장 먼저 넣을 것은?
3. 받은 코드를 검증하는 세 박자의 순서는?
4. 한 파일에 jakarta import와 SecurityFilterChain 빈이 보인다. 나머지 줄도 최신이라고 봐도 될까?
오늘은 서버 대신 AI 도구를 엽니다. 같은 부탁을 버전 없이, 버전을 붙여 각각 해 보고 결과를 비교합니다.