예외 처리 전략: "시스템의 안전벨트와 에어백"
견고한 시스템은 에러가 전혀 발생하지 않는 시스템이 아니라, 에러가 발생했을 때 우아하게 복구되는 시스템입니다. 이를 위해 자바의 예외 계층 구조와 전략적 보고 체계를 이해해야 합니다.
1. Throwable 계층 구조: "적을 알아야 나를 지킨다"
자바의 모든 예외와 에러의 조상은 Throwable이며, 성격에 따라 두 갈래로 나뉩니다.
- Error (불가항력 → 건물 붕괴): OutOfMemoryError처럼 시스템 레벨의 치명적 문제입니다. 잡아내려 애쓰기보다 인프라 점검이 우선입니다.
- Exception (관리 가능 → 전구 교체): 개발자가 로직으로 대응할 수 있는 문제입니다.
- Checked Exception: 컴파일 시점에 체크하며 처리를 강제합니다. (외부 I/O, DB 등)
- Unchecked (RuntimeException): 실행 시점에 발생하며, 주로 개발자의 논리적 실수(NullPointerException 등)를 방어해야 하는 영역입니다.
2. 자원 관리의 진화: Legacy vs Modern
데이터를 읽고 쓸 때 사용하는 자원(Resource)은 반드시 닫아주어야 합니다.
- 고전적 방식 (try-catch-finally): finally 블록에서 null 체크와 중첩된 try-catch를 통해 수동으로 close()를 호출했습니다. 코드가 지저분해지고 실수하기 쉽습니다.
- 현대적 표준 (try-with-resources): 자바 7부터 도입된 방식으로, try() 괄호 안에 자원을 선언하면 로직 종료 시 자동으로 반납됩니다. 코드가 훨씬 간결하고 안전해집니다.
3. 전략적 보고 체계: "현장 조치인가, 보고인가"
모든 예외를 발생한 곳에서 즉시 처리하는 것은 대규모 프로젝트에서 독이 될 수 있습니다.
- 현장 즉시 조치 (try-catch): 로직 내에서 충분히 복구가 가능할 때 사용합니다.
- 책임의 전가와 보고 (throws): 하위 계층(Service, DAO)에서는 예외를 위로 던지고, 가장 상위 계층(Controller)에서 공통 예외 처리기를 통해 한꺼번에 처리하는 것이 대규모 프로젝트의 정석입니다.
4. 비즈니스 복구: 의미 있는 Custom Exception
단순히 Exception을 던지는 것은 불친절합니다. 비즈니스 상황에 맞는 예외를 직접 정의하여 소통해야 합니다.
- 예시: OutOfBalanceException (잔액 부족 예외)
- 효과: "왜 실패했는지"를 명확히 소통함으로써, 프론트엔드나 기획 파트에서 사용자에게 훨씬 정확한 안내 문구를 보여줄 수 있습니다.
★ AX/DX 시대의 안정성 인사이트
AI가 코드를 생성하고 기획과 개발이 융합되는 시대, 예외 처리는 단순히 '버그 잡기'가 아닌 **'비즈니스 시나리오 설계'**입니다.
- 기획자 관점: "이 서비스가 실패했을 때 사용자가 어떤 경험을 해야 하는가?"를 예외 메시지 수준에서 기획할 수 있어야 합니다.
- 개발자 관점: 시스템의 경계에서 예외를 어떻게 수집하고 모니터링할 것인지 아키텍처를 설계하여, 수백억대 시스템의 가용성을 99.99%로 유지하는 근육을 키워야 합니다.
"좋은 코드는 성공 경로보다 실패 경로를 더 치밀하게 설계합니다."
멀티스레딩: "한 지붕 아래 여러 일꾼"
현대 소프트웨어는 수천 명의 사용자가 동시에 접속하는 환경을 견뎌야 합니다. 이를 위해 자바는 하나의 프로세스 안에서 여러 작업을 동시에 처리하는 멀티스레딩 기술을 사용합니다.
1. 3대 핵심 개념 정리
- 프로그램(Program): 하드디스크에 저장된 '잠자는 코드'입니다. 요리로 치면 아직 펼치지 않은 레시피 북과 같습니다.
- 프로세스(Process): 메모리에 올라와 실행 중인 '잠에서 깨어난 코드'입니다. 실제로 가동 중인 **주방(공장)**에 해당합니다.
- 스레드(Thread): 프로세스 내에서 실질적으로 움직이는 '작업의 흐름'입니다. 주방에서 각자 맡은 요리를 하는 **일꾼(요리사)**입니다.
2. 프로그램 vs 프로세스 vs 스레드 완벽 비교
| 구분 |
프로그램 (Program) |
프로세스 (Process) |
스레드 (Thread) |
| 상태 |
정적 (Static) |
동적 (Dynamic) |
실행 (Execution) |
| 메모리 |
차지하지 않음 |
독립적 공간 할당 |
|
| 비유 |
요리 레시피 (설계도) |
실제 가동 중인 주방 |
|
| 비용 |
없음 |
생성 비용 매우 높음 |
|
| 장애 영향 |
없음 |
독립적이라 타 영향 없음 |
|
3. 왜 스레드는 "한 지붕" 아래에 있는가?
자료의 하단 다이어그램이 보여주듯, 스레드의 가장 큰 특징은 공유 자원입니다.
- 독립 공간: 각 스레드는 자신만의 Stack 공간을 가져서 최소한의 독립성을 유지합니다.
- 공유 공간: 하지만 Code, Data, Heap 영역은 프로세스 내의 모든 스레드가 공유합니다.
- 장점: 일꾼들이 도구와 재료(메모리)를 공유하므로 소통이 빠르고 자원 낭비가 적습니다.
- 주의점: 여러 일꾼이 동시에 하나의 재료를 건드리면 데이터가 꼬이는 동기화(Synchronization) 문제가 발생합니다. 이것이 바로 고급 개발자로 가는 필수 관문입니다.
데이터의 이동과 영속화: I/O 스트림 & 직렬화
프로그램의 데이터가 외부(파일, 네트워크, 장치)와 소통하기 위해서는 **통로(Pipeline)**가 필요합니다. 이를 자바에서는 **스트림(Stream)**이라고 부릅니다.
1. I/O 스트림: 데이터 공장의 컨베이어 벨트
데이터의 성격에 따라 우리는 두 가지 종류의 벨트를 선택해야 합니다.
| 구분 |
바이트(Byte) 기반 스트림 |
|
| 처리 단위 |
8-bit (1 Byte) |
16-bit (2 Byte / Unicode)
|
| 대상 데이터 |
Binary (이미지, 영상, 실행파일) |
|
| 입/출력 클래스 |
InputStream, OutputStream |
Reader, Writer |
| 비유 |
무엇이든 담는 '무지개색 상자' |
|
2. 객체 직렬화(Serialization): 객체의 '냉동 보관'
메모리에 살아 움직이는 객체를 네트워크 너머로 보내거나 영구 저장하려면, 이를 일렬로 늘어선 바이트 데이터로 변환해야 합니다. 이를 직렬화라고 합니다.
- 목적: 데이터의 영속화(Persistence) 및 타 시스템으로의 객체 전송.
- 조건: java.io.Serializable 인터페이스를 구현해야 하며, 객체 내부의 모든 멤버 변수도 직렬화가 가능해야 합니다.
- 핵심: 메모리 상의 '입체적인 객체'를 '평면적인 데이터'로 변환하여 보관하는 기술입니다.
3. 기술 경쟁 분석: "어떤 포장지를 쓸 것인가?"
직렬화 기술은 시대의 흐름에 따라 진화해 왔습니다. 수백억대 프로젝트에서는 성능과 호환성을 고려한 전략적 선택이 필수입니다.
| 구분 |
Java 직렬화 (전통) |
JSON (현대 대세) |
|
| 형식 |
바이너리 (Java 전용) |
텍스트 (Human Readable) |
|
| 장점 |
구현이 매우 쉬움 |
언어 독립적, 가독성 우수 |
|
| 단점 |
보안 취약, 용량 큼, 고립됨 |
파싱 비용 발생 |
개발 공수가 더 듬 |
| 실무 용도 |
단순 자바 시스템 간 통신 |
REST API, 설정 파일 |
|
▶▷ 무엇이 바뀌고 무엇이 그대로인가? (Code View)
전통적인 자바 직렬화에서 현대적인 JSON 방식으로 넘어갈 때, 우리의 코드는 어떻게 변할까요?
- 그대로인 것: 자바 클래스 구조(User.java)는 변하지 않습니다.
- 바뀌는 것:
- 변환 주체: JVM 내장 기능에서 Jackson, Gson 같은 외부 라이브러리로 바뀝니다.
- 파일 형태: 읽을 수 없는 바이너리에서 **사람이 읽을 수 있는 텍스트(.json)**로 바뀝니다.
- 호환성: 자바끼리만 대화하던 고립에서 벗어나 파이썬, C#, 웹브라우저와도 대화가 가능해집니다.
[코드 관점에서의 변화]
- 전통: "나만 아는 비밀 기호로 바꿔서 보내!" (ObjectOutputStream)
- 현대: "모두가 이해할 수 있는 JSON 문장으로 바꿔서 보내!" (Jackson Library)
★ AX/DX 시대의 데이터 통신 인사이트
AI와 수많은 마이크로서비스가 얽히는 현대 아키텍처에서 데이터의 호환성은 생존의 문제입니다.
- 기획자 관점: 우리 서비스의 데이터가 외부 파트너사와 얼마나 자유롭게 유통될 수 있는지(JSON의 범용성)가 비즈니스 확장의 핵심입니다.
- 개발자 관점: 보안에 취약한 자바 직렬화를 지양하고, 성능이 중요한 구간(MSA 간 통신)에는 Protobuf를, 범용성이 중요한 구간(API)에는 JSON을 배치하는 **'하이브리드 전략'**이 필요합니다.
댓글 영역