푸른영혼의 별 | Tech Blog
Java Backend Engineer의 기술 블로그입니다.
Spring Boot, MSA, JPA, Kafka, Kubernetes 등 실무 경험을 공유합니다.
주요 프로젝트: Settlement MSA · ASAT · GitHub
Posts (총 505편 · 25 / 51 페이지)
-
*아키텍처 *vs *SOLID *vs *의존성 역전 (DIP) *vs *의존성 주입 (DI)* — *4 개 가 *왜 *자꾸 *섞이는가*
“아키텍처 가 *중요하다” 와 “SOLID 를 *지켜야 한다” 와 “DIP 를 *적용 했다” 와 “Spring 의 *DI 를 *쓴다” 를 같은 *뜻 으로 말하는 사람과 *이 4 개 가 *서로 다른 *층 의 서로 다른 *개념 이라고 말하는 사람은 *PR 리뷰 를 완전히 다르게 *한다.
4 개 는 *서로 *포함 / 실현 / 근거 의 관계 다. 아키텍처 는 시스템 전체 의 경계와 흐름, SOLID 는 클래스/모듈 수준 의 5 가지 *설계 원칙, DIP 는 SOLID 의 *D — 추상화 의 *방향 에 대한 원칙, DI 는 DIP 를 *실현 하는 구현 기법 중 하나. 위 → 아래 로 추상도 가 *낮아지고 *구체성 이 *높아진다.
이 글은 4 개 의 *경계 를 그려 흔한 *오해 (예: “DI = DIP”, “SOLID = 아키텍처”, “Spring 쓰면 *아키텍처 좋아짐”) 를 분해 한다. Java + Spring 기준 예제 로 같은 *코드 가 4 개 *층 에서 각자 *무엇을 *해결 했는지 를 보인다.
-
*객체지향* 의 *핵심 가치* — *역할 · 책임 · 협력* 의 *진짜 의미* 와 *settlement 에서 의 *살아있는 적용***
“객체지향이 뭐예요?” 라고 물으면 대부분 “클래스, 상속, 다형성, 캡슐화” 라고 답한다.
그런데 알란 케이 (Alan Kay) — 객체지향이라는 단어를 만든 사람 은 말했다 :
“I’m sorry that I long ago coined the term ‘objects’ for this topic because it gets many people to focus on the lesser idea. The big idea is messaging.”
“오래전 ‘objects’ 라는 용어를 만든 것을 후회한다. 사람들이 *더 작은 개념 에 집중하게 만들었다. 진짜 큰 아이디어 는 *메시징”*
-
*객체 지향 개발* 에서 *테스트 를 학습* 한다는 것 의 *의미* — *JUnit 을 외우는 일* 이 아니라 *생각 의 형태 를 바꾸는 일**
“테스트 를 학습 한다” — 처음 듣는 신입 에게 이 말 은 JUnit 의 어노테이션 을 외우는 일 처럼 들린다.
@Test,assertEquals,Mockito.when().thenReturn()의 문법 학습.그러나 *9 년 을 지나고 보면 이 단어 의 *진짜 의미 는 전혀 다른 영역 에 있다. *테스트 를 배운다 는 것은 내 코드 의 *형태 자체 를 바꾸는 학습. 내 객체 가 *어떻게 *남과 대화 하는지, 어디서 *경계 가 깨지는지, 무엇이 *내 책임 이고 무엇이 *남의 책임 인지 를 눈에 보이는 형태 로 드러내는 학습*.
즉 *테스트 의 학습 은 객체 지향 의 학습 의 다른 이름.
-
*DB 배치 처리* 의 *성능 향상* *2 축* — *커버링 인덱스* (테이블 안 보기) + *데이터 청킹* (한 번에 다 안 들기)
settlement-service 의 월 정산 집계 배치. 수억 row 의 *결제 데이터 를 셀러 별 로 합산. 처음 *돌렸을 때 *6 시간 걸림. *튜닝 후 *18 분. 20 배 단축.
마법 은 없었다. 두 가지 만 *제대로 한 결과. *커버링 인덱스 + 데이터 청킹.
-
오프셋 과 어셈블리어 의 관계 — 어셈블리어 는 결국 오프셋 의 산술 언어 였다는 깨달음
gdb 에서 disas main 을 친다. 화면 가득 수십 줄 의 어셈블리. 무엇이 보이는가 :
mov -0x10(%rbp), %rax ; rbp 에서 -16 만큼 떨어진 곳 call 0x4011a0 <printf@plt> ; 현재 위치 에서 *상대* 점프 mov 0x20(%rdi), %rcx ; rdi 가 가리키는 곳 에서 +32 lea 0x2e9b(%rip), %rsi ; 현재 명령어 의 *다음 주소* 에서 *상대* jne 0x401234 ; 조건 분기 — *상대* 오프셋전부 *오프셋. 예외 없이. 어셈블리어 의 *모든 메모리 접근, 모든 호출, 모든 분기, 모든 변수 가 결국 *기준점 + 거리 의 산술**.
-
*CPU 와 *DB* 의 *관계* — *메모리 와 *SSD* 를 *포함* 해서 *하드웨어 → 기계어 → 어셈블리 → 자바* 4 단 으로 *내려간다*
“DB 가 *느리다” 라고 말하는 사람과 *“이 SELECT 가 *L3 미스 → DRAM 1 회 + SSD random read 1 회 + JIT 컴파일 안 된 ResultSet 루프 라서 느리다” 라고 말하는 사람은 *프로파일러를 *완전히 다르게 *읽는다.
DB 한 줄 의 *결과 가 *Java 의 *Long id 에 들어오기까지 — CPU → L1 → L2 → L3 → DRAM → NVMe SSD → 페이지 캐시 → DB 버퍼풀 → JDBC → JIT → JVM Heap — 최소 8 개 의 *계층 을 통과 한다. 각 계층 의 지연 시간 (latency) 은 수십 배 / 수천 배 / 수십만 배 로 불연속 적 으로 튄다.
이 글은 그 한 줄 이 어떻게 *흐르는지 를 하드웨어 → 기계어 → 어셈블리 (x86-64) → 자바 (JDBC + JIT) 의 4 단 추상화 로 내려가 *분해 한다. 4 단 을 동시에 *볼 수 있게 되면 *프로파일러의 *flame graph 도, DB 의 *EXPLAIN ANALYZE 도, GC 로그 도 같은 *언어 로 읽힌다.
-
*APM* 과 *응답 시간 분포* — *백엔드 서버 개발자* 의 시각 에서 *왜 평균 이 거짓말 인가*
“우리 평균 응답 200ms 인데요”. 그런데 사용자 한 명 이 Slack 으로 “왜 *오늘 결제 가 *10 초씩 걸리냐” 한다.
둘 다 사실. 평균 이 200ms 라는 것 이 99 명 이 *50ms 인데 1 명 이 *15,000ms 라는 극단 적 분포 와 수학적 으로 동일 할 수 있다.
백엔드 서버 개발자 의 책임 은 평균 을 보는 것 이 아니라 *분포 를 보는 것. 그리고 *그 분포 의 *long tail 이 왜 길어졌는지 를 추적 가능 하게 만드는 것 — 그 도구 가 APM.
-
*Kubernetes 의 로드밸런서* — *L4 (Service) vs L7 (Ingress)* 의 *네트워크 계층* 과 *알고리즘 의 *진실*
L4 (Service) 의 kube-proxy 는 iptables 모드 = *랜덤 선택, IPVS 모드 = round-robin. L7 (Ingress) 의 nginx-ingress = round-robin, Traefik = weighted round-robin. 같은 “로드밸런서” 라도 계층과 도구 에 따라 알고리즘 이 다르다.* -
*AI 코드 PR* 머지 전, *7 가지 질문* — *vibe coding 의 *마지막 게이트***
AI 가 만든 코드의 PR 머지 전 던져야 할 7 가지 질문 — 신뢰할 수 없는 입력 / 동시 요청 / 경계값 / 외부 의존 다운 / 100만 건 데이터 / 도메인 규칙 / 로그·알람. Rule of thumb: “이게 운영에서 죽을 수 있는 5 가지 시나리오는?” — 머지 전 항상. -
*ELK + Beats* — *Filebeat / Logstash / Elasticsearch / Kibana* 의 *4 단계* 와 *production 로깅 의 *진짜 그림*
서비스/앱 → Filebeat (경량 수집) → Logstash (파싱·변환) → Elasticsearch (색인·검색) → Kibana (시각화). 이 4 단계 의 *각자 책임 분리 가 production 로깅 의 진짜 그림.*