디버거 (Debugger)란?
프로그래밍을 하다 보면 점점 새로운 기능을 만드는 시간보다 버그를 찾는 시간이 많아집니다.
처음에는 print를 하거나 console.log를 찍는 등 원시적인 방법으로 해도 충분하지면 점점 복잡한 프로그램과 복잡한 버그들을 다루면서 이런 단순한 기능으로는 충분하지 않게 됩니다.
이럴 때 버그를 찾기 위해 편한 여러 기능을 제공해 주는 걸 디버거 (Debugger)라고 합니다. 보통은 IDE에 내장 돼 있고, 흔히 제공되는 기능들이 정해져 있습니다.
- Breakpoints: 프로그램 코드의 특정 부분에서 일지정지 하는 기능
- Step Through: 코드를 1줄 1줄 차례대로 실행하는 기능
- 프로그램의 특정 순간에서 여러 변수들의 값을 볼 수 있는 기능
- 특정 시점에서 여러 코드를 직접 실행해 볼 수 있는 기능
그중에서도 Java와 Kotlin에서 자주 쓰는 IDE인 IntelliJ의 디버거 기능을 알아보겠습니다.

사용법
사용법은 의외로 간단합니다. 우선 내가 디버깅을 하고 싶은 코드로 가고 거기에 Breakpoint를 추가하면 됩니다. Breakpoint는 2가지 방법으로 추가할 수 있습니다.
- Line 번호가 있는 부분 마우스로 클릭하기
- Command + F8 단축키 사용하기

요렇게 Breakpoint를 추가한 뒤 프로그램을 실행하면 Breakpoint가 추가된 줄을 실행할 때 프로그램이 멈추고, 밑에 부분에 디버깅용 창이 나타납니다. 이 창은 (Command + 5 단축키로도 진입할 수 있습니다.)

기능 둘러보기
우선 디버깅 창을 살펴보면 크게 4가지 부분이 있습니다.

🐜 1 - Call Stack
모든 Java 프로그램은 실행하면 main method를 호출합니다. 처음 Java를 배울 때 주구장창 썼던 아이입니다.
public static void main(String args) {}
그리고 이 main method는 또 다른 method/class를 호출하고... 이게 계속 이어져서 내가 Breakpoint를 건 이 method까지 왔습니다. 이 모든 과정이 기록 돼 있는 게 Call Stack입니다.
프로그램의 전반적인 흐름을 볼 때 매우 유용합니다. 예를 들어 보안 토큰을 잘 처리했는지를 보고 싶으면 Call Stack을 밑으로 따라 가면 됩니다.
🐜 2 - 관련 변수들
모든 프로그램은 실행하기 위해 각종 데이터를 변수에 저장하고 이 변수들에 연산을 합니다. 보통 디버깅을 한다고 하면 이 각각의 변수에 내가 의도한 대로 값이 들어가 있는지, 예상하지 못 한 값이 들어가 있다면 그 원인은 무엇인지 보면서 시작하게 됩니다.
만약 내가 원하는 값이 없다면 (변수를 데이터가 바뀔 때 마다 쪼개지는 않으니깐 보통은 없습니다) 위의 칸에 보고 싶은 값을 넣고 엔터를 누르면 변수 목록에 추가됩니다.

🐜 3 - 디버깅에서 취할 수 있는 동작들 모음
Resume Program | Breakpoint에서 멈춘 프로그램을 이어서 돌립니다. 다음 Breakpoint를 만날 때 까지는 프로그램이 계속 진행됩니다. |
Pause Program | 프로그램을 멈추고 Debug 모드로 진입합니다. 이미 Breakpoint로 멈췄으면 비활성화 돼 있습니다. |
Step Over | 현재 줄에서 다음 줄로 갑니다. Breakpoint가 없어도 있는 것 처럼 멈추고, 다른 함수를 호출한다면 알아서 호출이 끝나고 결과를 얻은 상태에서 다음 줄로 갑니다. |
Step Into | 함수를 호출한다면 그 함수 안에 들어갑니다. |
Step Out | 현재 함수 호출을 끝내고 이 함수를 호출한 곳으로 갑니다. |
View Breakpoints | 현재 내가 추가한 모든 Breakpoints 들을 볼 수 있습니다. |
Mute Breakpoints | Breakpoints 들을 무시하고 평범하게 프로그램이 돌아갈 수 있게 합니다 |
🐜 4 - 관련 변수들 외에도 쓸 수 있는 기능 전환
Threads & Variables | 현재 Breakpoint가 걸린 지점의 Thread와 관련 변수 정보를 볼 수 있습니다. |
Console | print를 하거나 local에서 log를 찍을 때 나오는 그 Console입니다. |
Beans | Spring Container에 등록된 Bean을 모두 볼 수 있습니다. 여러 Type의 Bean이 있다면 내가 의도된 Bean이 들어갔는지 확인하는게 디버깅에 도움이 될 수 있습니다. 개인적으로 Runtime에 디버깅이 필요할 정도로 Spring Bean을 복잡한 조건으로 등록하는건 좋아하지 않지만 아쉽게도 가끔 레거시 코드가 있습니다. |
Health | 현재 시점의 여러 Metric을 보여 줍니다. (CPU 사용량, Memory 사용량, Thread 지표 등) Actuator를 사용한다면 Actuator도 보입니다. |
Mappings | Spring Web의 Controller로 등록된 API들과 그 API를 호출하면 호출하는 method들의 목록이 있습니다. |
Environment | 현재 시점에 등록된 모든 환경 변수를 볼 수 있습니다. application.yml 등으로 등록된 값들 뿐만 아니라 OS, JVM 등이 사용하는 환경 변수도 모아서 볼 수 있습니다. |
단축키 사용하기
사실 디버깅 UI만 사용해도 충분히 디버깅을 진행할 수 있지만 디버깅의 핵심은 단축키가 아닐까 생각합니다. 단축키를 사용하면 빠르게 중요하지 않은 부분을 훑고, 중요한 부분을 타닥 들어가서 보고 다시 나오고 등을 굉장히 빨리 할 수 있습니다.
처음에는 욕심이 나서 많은 단축키를 사용하려고 하실 수도 있는데 저는 처음에는 3가지만 사용하면서 익숙해 지면 늘리시기를 추천드립니다.
Step Over | F8 | 현재 줄에서 다음 줄로 갑니다. |
Step Into | F7 | 함수를 호출한다면 그 함수 안에 들어갑니다. |
Step Out | Shift + F8 | 현재 함수 호출을 끝내고 이 함수를 호출한 곳으로 갑니다. |
'👨💻 프로그래밍 > 📦 Backend' 카테고리의 다른 글
Gradle 기반 프로젝트에 Ktlint 적용하기 (2) | 2025.02.15 |
---|---|
@FunctionalInterface란? (0) | 2025.01.30 |
(Spring 위주로) AOP 용어 정리 (0) | 2025.01.26 |
MDC로 풍부한 로그 쉽게 남기기 (0) | 2025.01.12 |
🥒 피클 (PKL): 새로운 설정 관리 언어 알아보기 (0) | 2024.11.02 |