개발 고민
-
카테고리 없음
[여운 Yeowun ] AI/LLM을 활용해 API 스펙 자동 동기화로 업무 효율 높이기
1. 배경팀 프로젝트를 진행하며 핵심 기능 외의 부가 기능들도 계속 기획/추가되는 과도기 상황이었다. 아직 기능 명세서가 구체화 되지 않은 상황속에서 백엔드 팀의 미션은 PM이 기획한 문서가 기술적으로 실현 가능한지 레퍼런스를 검토하고, 기능이 확정되는 즉시 개발에 들어갈 수 있도록 인프라를 미리 준비해두는 것이었다. 궁극적으로는 프론트 개발자가 프론트 개발에만 집중할 수 있도록 API를 최대한 빠르게 제공하는 것이 목표였다. 순조롭게 잘 진행되고 있는 것 같았는데, 예상치 못한 노가다가 존재했다. API의 기능 자체는 변하지 않았지만, 요청/응답 스펙은 세부적으로 계속 바뀌었다. 이 변경 사항을 프론트 개발자가 매번 수기로 확인하고 코드에 반영해야 하는 구조였다. 특히 우리 팀의 프론트 개발자는 1명뿐..
-
카테고리 없음
60명을 48명으로 깎았다가 결국 상한 자체를 없앤 기록 — 대기열 시스템 만들기
들어가며블랙프라이데이, 매초 20명씩 대기열에서 참여열로 무한히 들어오는 구조를 만든 시점에서, 참여열의 사람들이 아무도 주문하지 않는 상황을 그려봤다. 아무도 주문하지 않으면?스케줄러는 1초마다 20명씩 대기열에서 참여열로 데려온다. 근데 참여열에 들어온 유저가 바로 주문하는 건 아니다. 상품을 구경하고, 고르고, 배송지를 입력하는 동안 참여열에 계속 머물러 있고, 그 사이에도 스케줄러는 멈추지 않는다. 아무도 주문하지 않는 극단적 상황을 그려봤다. TTL 5분 동안 스케줄러가 데려오는 인원은 20명 × 300초 = 6,000명이었다. 6,000명이 참여열에 있는 상태에서 동시에 주문 버튼을 누른다면, DB 커넥션 풀 100개에 6,000건이 몰리게 된다. 대기열을 세운 이유가 이런 동시 요청을 ..
-
카테고리 없음
머릿속이 복잡해서 일단 그려본 랭킹 시스템 설계
시작하게 된 배경패션 이커머스 도메인을 다루다 보니, 인기 있는 상품을 발견할 수 있는 수단이 부족하다는 게 계속 마음에 걸렸습니다. 유저 행동 데이터(조회, 좋아요, 주문)는 이미 수집되고 있었지만, 정작 이 데이터가 유저에게 직접적인 탐색 가치로 연결되지는 못하고 있었습니다.그래서 "지금 인기 있는 상품을 빠르게 발견할 수 있게 해주자"라는 목표로 일간 상품 랭킹 시스템을 도입하기로 했습니다. 홈 메인의 "오늘의 인기 상품", 상품 목록의 "인기순 정렬", 상품 상세 페이지의 "현재 순위 표시" 같은 기능들을 1인 기초 설계부터 구현해야 하는 미션이 생겼습니다. 랭킹이라는 도메인 고민하기설계를 고민하면서 제가 정리한 랭킹의 특징은 다음과 같습니다.1. 랭킹에는 순서가 있습니다. 순서를 정하려면 정렬 ..
-
DB
비관적락은 정말 순서를 보장할까? - MySQL의 트랜잭션 스케줄링 CATS
개요낙관락과 다르게 나는 비관락은 순서를 보장하는 매커니즘이라고 생각했었다. 왜? 검색했더니 "작업 순서 보장" 이라는 말을 다른 트랜잭션 요청들의 순서 보장이라고 멋대로 오해했기 때문이다. 여기에 개인적인 유추가 더해졌다. 비관락은 먼저 온 트랜잭션이 락을 잡고 사용하는 동안, 다른 트랜잭션은 커넥션을 점유한 채 타임아웃까지 대기한다. 이 동작에서 자연스럽게 대기 큐가 연상되었고, FIFO 구조라면 도착 순서대로 잠금이 허가될 것이라고 예상했다. 그러나 비관락은 정확한 트랜잭션 요청 순서를 항상 보장하지는 않는다. 왜 그럴까? 전통적으로 MySQL은 트랜잭션의 잠금 허가(Grant)를 순수하게 대기(Waiting) 순서에만 근거해 결정해 왔다. 이 방식을 FCFS(First Come First Se..
-
카테고리 없음
Claude Code로 개발하며 만든 컨벤션 검증 시스템 — Skills, Hook, ArchUnit, 서브 에이전트
서론컨벤션은 있는데 왜 안 지켜질까? 팀 프로젝트에서 느낀 한계사이드프로젝트 동아리에서 팀 개발을 하면서, 코딩 컨벤션 문서를 꽤 공들여 만든 적이 있다. 패키지 구조부터 Entity 설계 방식, DTO 네이밍 규칙까지 나름 상세하게 정리했다. 그런데 실제로 코드를 작성하기 시작하면 문제가 반복됐다. 하지만 매번 확인하는게 정말 쉽지 않다. 점점 문서를 확인하지 않고 각자의 감으로 작성했다. 주간 회의가 끝나고 나서 따로 컨벤션 관련 이야기하는 시간이 많아졌었다.돌이켜보면 문제의 근본 원인은 컨벤션 문서의 품질이 아니었다. 첫째, 암기에 의존하는 구조였다. 컨벤션이 있어도 결국 개발자가 기억해서 적용해야 했다. 둘째, 피드백 시점이 너무 늦었다. 컨벤션 위반은 커밋 후 코드 리뷰에서야 발견됐다. ..
포스팅
-
카테고리 없음
MySQL COUNT의 동작 원리와 성능
들어가며 - 목록 조회 API의 응답 지연과 원인 격리전시 정보 앱의 전시 목록 조회 API를 개발하고 있다. 커서 페이지네이션으로 20건씩 내려주고, 응답에 총 건수(totalCount)를 함께 담는 구조다. 개발 초기 데이터 313건일 때는 11.6ms였다. 데이터를 늘려가며 부하를 걸어보니 100만 건에서 8,890ms가 나왔다. 화면에 뿌리는 건 여전히 20건인데 9초 가까이 걸린 것이다.측정 조건MySQL 8.4 · InnoDB 버퍼풀 128MB(기본값) · 매 측정 전 MySQL 재시작으로 콜드 상태 통일앱은 호스트 JVM(java -Xmx1g -jar), MySQL만 Docker(2 vCPU)로 분리. 서로 CPU를 다투지 않게 하기 위함k6 · VU 2 · 경로별 표본 고정 · 시드 고정 ..
-
카테고리 없음
[여운 Yeowun ] AI/LLM을 활용해 API 스펙 자동 동기화로 업무 효율 높이기
1. 배경팀 프로젝트를 진행하며 핵심 기능 외의 부가 기능들도 계속 기획/추가되는 과도기 상황이었다. 아직 기능 명세서가 구체화 되지 않은 상황속에서 백엔드 팀의 미션은 PM이 기획한 문서가 기술적으로 실현 가능한지 레퍼런스를 검토하고, 기능이 확정되는 즉시 개발에 들어갈 수 있도록 인프라를 미리 준비해두는 것이었다. 궁극적으로는 프론트 개발자가 프론트 개발에만 집중할 수 있도록 API를 최대한 빠르게 제공하는 것이 목표였다. 순조롭게 잘 진행되고 있는 것 같았는데, 예상치 못한 노가다가 존재했다. API의 기능 자체는 변하지 않았지만, 요청/응답 스펙은 세부적으로 계속 바뀌었다. 이 변경 사항을 프론트 개발자가 매번 수기로 확인하고 코드에 반영해야 하는 구조였다. 특히 우리 팀의 프론트 개발자는 1명뿐..
-
카테고리 없음
트랜잭션 아웃박스(Transactional Outbox) 고민 내용 정리
이전 글 - 트랜잭션 아웃박스(Transaction Outobx) 에서 트랜잭션 아웃박스 학습 내용을 정리했었다.실무 경험이 부족하다보니, 트랜잭션 아웃박스를 도입하면서 고민되는 부분들이 있었고, 멘토링으로부터 얻은 답변들과 배운점들을 이번 글에 정리했다. TL;DRQ1. 아웃박스 저장 위치: 패턴의 본질은 '명시적 보장'이다. 이벤트로 흐름을 감추기보다, DIP를 활용해 기록 행위를 코드에 명시해야 한다.Q2. 성능과 멱등성 보장: 대부분 RDB(단순 INSERT, Unique Key, Lock)만으로 충분히 방어할 수 있다. 분산 환경의 복잡도를 높이는 Redis 도입은 최후의 수단이다.Q3. 실무 도입 기준: 유실 비용이 운영 복잡도를 압도할 때만 도입하라. 비즈니스 중요도(Tier)를 나누어 사후..
-
DB
트랜잭션 아웃박스 (Transaction Outbox)
트랜잭션 매니저는 단일 커넥션 안에서 여러 쿼리의 원자성을 DB 차원에서 보장한다. 하지만 DB 저장과 이메일 발송(또는 외부 메시지 발행)처럼 서로 다른 시스템을 교차해서 다루는 작업에서는 이 원자성이 깨지기 쉽다. "비즈니스 DB 저장과 다른 작업을 어떻게 유실 없이(Atomic) 처리할 것인가?" 이 한계를 풀어내는 방법으로 Transactional Outbox 패턴을 접하게 됐고, 학습 내용을 정리하는 글이다.1. TL;DR1.DB와 MQ는 하나의 트랜잭션으로 묶을 수 없다. 이 물리적 한계가 이벤트 유실과 유령 이벤트를 만든다.2.아웃박스 패턴은 이벤트를 외부로 바로 보내는 대신, 같은 DB 트랜잭션 안에 먼저 영속화한다. 유실 문제를 지연 문제로 전환하는 것이 핵심이다.3. 릴레이 프로세스는 ..
-
카테고리 없음
DB 인덱스 학습 정리
서론인덱스를 걸었지만 느린 문제인덱스를 걸면 빨라진다라는 상식에는 뒷받침되는 많은 전제들이 존재하기 때문에, 항상 효과적인건 아니다.느린 쿼리에 인덱스를 추가했는데 여전히 느리거나, 오히려 다른 쿼리가 느려지는 상황이 그 대표적인 예다. 인덱스를 제대로 쓰려면 자료구조 + 옵티마이저의 선택 + 쓰기 비용 세 가지를 같이 봐야 한다.관점내용읽기 성능잘못된 컬럼 순서 하나로 풀 스캔 발생쓰기 성능인덱스 하나 추가할 때마다 INSERT/UPDATE 비용 증가저장 공간인덱스 크기가 본 테이블을 넘을 수 있음옵티마이저통계가 틀어지면 인덱스가 있어도 안씀 인덱스 인덱스의 개념과 특징인덱스는 저장 성능을 희생하고 검색 성능을 높이기 위해 만들어진 자료구조다. 책의 색인과 구조가 비슷한데, 색인이 있으면 원하는 내용을..
-
카테고리 없음
DB Lock과 동시성 제어 학습 정리
서론이전 글 DB 트랜잭션 학습 정리 에서 트랜잭션과 ACID를 다루며, 격리성 레벨에 따른 읽기 이상 현상들을 MySQL의 MVCC와 넥스트 키 락으로 해결하는 구조를 정리했다. 읽기 이상은 격리 수준으로 해결하고, 쓰기 이상은 명시적 락으로 해결한다는 구분이 핵심이었다. 이번 글은 그 쓰기 이상 영역을 다룬다. MVCC는 스냅샷 기반으로 읽기 일관성을 보장하는 메커니즘인데, 이 스냅샷은 SELECT에만 적용되고 UPDATE나 DELETE는 항상 최신 데이터를 본다. 즉, 읽는 시점과 쓰는 시점이 분리된 구조다. 이 간격에서 핵심 문제가 발생한다. 재고 100개인 상품을 두 트랜잭션이 동시에 읽고 각자 1개씩 차감하면, 둘 다 100을 읽고 99로 업데이트한다. 재고는 98이어야 하는데 99가 된다. ..
-
카테고리 없음
DB 트랜잭션 학습 정리
서론트랜잭션을 설명할 때 "개념의 정의 + 트랜잭션 속성별 설명 + 주의점"이라는 구조로 말하고 싶었다.이 글은 그 구조를 기준으로 부족한 부분들을 질문 중심으로 정리했다.1. 트랜잭션과 ACID트랜잭션이란 무엇이고 ACID란 무엇인가?트랜잭션은 데이터베이스의 논리적인 작업의 단위이며, 장애가 발생했을 때 데이터를 복구하는 작업의 단위이기도 하다.ACID는 트랜잭션이 보장해야 하는 4가지 특성이다.속성설명원자성 (Atomicity)전부 실행되거나 하나도 실행되지 않아야 한다 — All or Nothing일관성 (Consistency)트랜잭션 전후로 제약 조건에 맞게 데이터가 변경되어야 한다격리성 (Isolation)다른 트랜잭션이 끼어들지 못하도록 보장한다 — 동시성 제어지속성 (Durability)커밋..
-
카테고리 없음
'이 잡이 느리다'가 아니라 '얼마나 걸릴지 모른다' — Spring Batch 비선형 곡선 추적기
1. 시작하며패션 이커머스 서비스를 만들면서 이번에는 실시간 랭킹을 확장하여, 주간/월간 랭킹 집계 배치를 만드는 것이었습니다. 일간 누적 집계 테이블을 입력으로 받아, 중간 테이블에 누적한 뒤 TOP 100을 갱신하는 4-Step 파이프라인을 AI에게 요청해 일단 굴러가는 형태까지 만들어봤습니다. 처음에는 100만 건으로 한 번 돌려보고 20분 정도에 끝나길래 별 의심 없었지만, 데이터를 500만 건으로 늘려서 같은 잡을 돌렸더니 2시간 30분이 걸렸습니다. 5배 데이터에 7.5배 시간단순한 상수 차이가 아니라 곡선 자체가 휘어 있다는 신호였고, 이대로는 운영에 올릴 수 없겠다고 판단했습니다. 예측 불가능한 잡이 만드는 운영 리스크이 잡은 1CPU 1GB 서버 1대로 구성된 배치 서버 위에서 돌고 있습..
-
카테고리 없음
머릿속이 복잡해서 일단 그려본 랭킹 시스템 설계
시작하게 된 배경패션 이커머스 도메인을 다루다 보니, 인기 있는 상품을 발견할 수 있는 수단이 부족하다는 게 계속 마음에 걸렸습니다. 유저 행동 데이터(조회, 좋아요, 주문)는 이미 수집되고 있었지만, 정작 이 데이터가 유저에게 직접적인 탐색 가치로 연결되지는 못하고 있었습니다.그래서 "지금 인기 있는 상품을 빠르게 발견할 수 있게 해주자"라는 목표로 일간 상품 랭킹 시스템을 도입하기로 했습니다. 홈 메인의 "오늘의 인기 상품", 상품 목록의 "인기순 정렬", 상품 상세 페이지의 "현재 순위 표시" 같은 기능들을 1인 기초 설계부터 구현해야 하는 미션이 생겼습니다. 랭킹이라는 도메인 고민하기설계를 고민하면서 제가 정리한 랭킹의 특징은 다음과 같습니다.1. 랭킹에는 순서가 있습니다. 순서를 정하려면 정렬 ..
-
카테고리 없음
Redis SortedSet은 어떻게 동작하는 걸까?
랭킹 대쉬보드를 구현하는 SortedSet 자료구조Redis SortedSet = SkipList + HashTable 2가지 구조를 합친 하나의 구조입니다.Skip List: score(ex.시간)를 기준으로 유저들을 정렬 상태로 유지하며, 삽입, 삭제, 범위 조회가 O(log n)입니다.Hash Table: 유저를 key로 잡아서, 해당 유저의 존재 여부와 score를 O(1)로 조회합니다.단순 설명만으로는 SortedSet을 이해하기 어려운 것 같습니다. 이제부터 자세히 알아봅니다.SkipList는 어떻게 동작하는 걸까?이미지와 설명은 레디스 SortedSet 어떻게 구현됐는지 아는척 하기 를 참고했습니다.SKipList는 연결리스트가 계층을 구성하는 자료구조입니다. 위를 보시면 0레벨부터 2레벨..
-
카테고리 없음
60명을 48명으로 깎았다가 결국 상한 자체를 없앤 기록 — 대기열 시스템 만들기
들어가며블랙프라이데이, 매초 20명씩 대기열에서 참여열로 무한히 들어오는 구조를 만든 시점에서, 참여열의 사람들이 아무도 주문하지 않는 상황을 그려봤다. 아무도 주문하지 않으면?스케줄러는 1초마다 20명씩 대기열에서 참여열로 데려온다. 근데 참여열에 들어온 유저가 바로 주문하는 건 아니다. 상품을 구경하고, 고르고, 배송지를 입력하는 동안 참여열에 계속 머물러 있고, 그 사이에도 스케줄러는 멈추지 않는다. 아무도 주문하지 않는 극단적 상황을 그려봤다. TTL 5분 동안 스케줄러가 데려오는 인원은 20명 × 300초 = 6,000명이었다. 6,000명이 참여열에 있는 상태에서 동시에 주문 버튼을 누른다면, DB 커넥션 풀 100개에 6,000건이 몰리게 된다. 대기열을 세운 이유가 이런 동시 요청을 ..
-
카테고리 없음
락을 줄이는 게 아니라 락이 필요한 구조를 없앴다 — 선착순 쿠폰 다시 설계기
선착순 100개의 쿠폰을 1,000명이 동시에 요청한다면 어떤 일이 벌어질까? 현재 시스템은 단일 서버,단일 DB 구성이다. 쿠폰 발급 API는 "누구나 다운받을 수 있는 쿠폰"을 전제로 설계했기 때문에, 수량 경합이 발생하지 않는 시나리오를 기본으로 두고 낙관적 락과 재시도만으로 동시성을 처리하고 있다. 그렇다면 이 구조에 수량 제한이라는 조건이 붙으면 어떻게 될까? 100개 한정 쿠폰에 1,000건의 동시 요청을 보내 확인해보았다. SLA 설정선착순 쿠폰 발급 SLA- 응답 시간 - 쿠폰 발급 성공 요청의 P99 응답 시간은 500ms 이하를 목표로 한다. - 쿠폰 발급 거절 요청의 P99 응답 시간은 200ms 이하를 목표로 한다.- 가용성 - HTTP 요청 실패율(5xx)은 0.1% 미만으로..
-
카테고리 없음
Spring ApplicationEvent 로그 찍으며 이해하기 - @EventListner, @TransactionEventListner, @Async
1. 들어가며1. @EventLisnter2. @TransactionEventListner3. @EventLisnter + @Async러닝 커브2. @TransactionEventListner + @Async Spring ApplicationEvent를 학습하기 위해 AI를 이용하여 예제 프로젝트를 만들어 위 조합들이 어떻게 동작하는지 궁금해서 로그를 찍어가며 다루는 법을 익혔다. 이 글에서는 기초적인 구현 방법에 대해서 다루지 않는다.개요회원가입을 처리하는 서비스가 있다고 하자. 회원을 저장한 뒤 환영 이메일을 보내고, 가입 이력을 남기고, 쿠폰을 발급해야 한다. 이 모든 로직을 signup() 메서드 안에 직접 작성하면 서비스 클래스는 점점 비대해지고, 이메일 발송 실패가 회원가입 자체를 롤백시키는..
-
카테고리 없음
Events vs Commands 차이점 및 주의사항
들어가며커맨드(Command)와 이벤트(Event)의 차이점은 무엇일까? 둘 다 메시지이며 다른 서비스가 알아야 할 정보들을 가득 담고 있는 직렬화된 페이로드(payload)이다. 그런데 왜 굳이 두 가지 다른 이름을 사용하는 걸까? 문제를 바라보는 몇 가지 관점이 있겠지만, 우선 그 이면에 담긴 의도를 파악하기 위해 일상적인 영어에서 '커맨드(command)'와 '이벤트(event)'라는 단어가 실제로 무엇을 의미하는지부터 살펴보자. Command커맨드는 지시나 요구와 같다. "가서 이 일을 해라"라고 말하는 것이다. Event반면에 이벤트는 이미 일어난 사건을 의미한다. 이것은 단지 "그 일이 완료되었다"라는 사실일 뿐이다. 1. 발생 시점의 차이Command한 가지 핵심적인 차이점은 어떤 일이 ..
-
카테고리 없음
상품 정렬 조회 2,490ms → 35ms, 무엇이 병목이었나
AS - IS (Before)조건: 상품 10만 건, 좋아요 41만 건, 브랜드 100건API: GET /api/v1/products?sort=likes_desc&page=0&size=20 API를 호출하면, 상품 테이블에 like_count 컬럼이 없어, 매 요청마다 3단계를 거친다.단계처리량실제 필요량likes 41만 건 GROUP BY 집계 (~550ms)41만 건-상품 10만 건 Java로 전체 로드10만 건20건인메모리 정렬 + subList10만 건20건쿼리 실행 계획: type=ALL, rows=99,598, Extra=Using where, Using temporary, Using filesort평균 응답 시간: 2,490ms정렬을 DB에 위임(LEFT JOIN + GROUP BY + O..
-
카테고리 없음
인덱스 개념 - 클러스터링, 세컨더리, 커버링 인덱스
들어가며앞선 글에서 MySQL이 왜 B+Tree를 인덱스 구조로 택했는지 살펴봤다. 이번 글은 MySQL의 인덱스하면 듣게 되는 인덱스들을 Cluade로 학습 후 정리했다.클러스터링 인덱스 → 세컨더리 인덱스 → 커버링 인덱스 순서로, 각 단계가 왜 이렇게 설계됐는지 이유 중심으로 학습했다.클러스터링 인덱스 (Clustered Index)# 리프 노드에 뭘 저장하는가B+Tree에서 리프 노드에 실제 데이터를 저장한다고 했다. 그렇다면 MySQL InnoDB는 리프 노드에 정확히 무엇을 저장할까?답은 실제 행(row) 전체다. InnoDB는 테이블을 생성할 때 PK를 기준으로 B+Tree를 자동으로 만드며, 이 트리를 클러스터링 인덱스라고 부른다.리프 노드 하나가 곧 데이터 행 하나다. PK 순서로 정렬되..
-
카테고리 없음
MySQL은 왜 B+Tree일까? - 이진탐색트리, B-tree, B+tree
들어가며MySQL의 인덱스 기능을 사용하여 조회속도를 올리려고 한다.그런데 인덱스가 항상 조회속도를 올리나? 안되는 순간은 언제인가?그러면 어떻게 사용해야 되는데.. 왜 그렇게 사용해야 되는데.. 어떤 구조로 되어 있어서 그걸 따라야 하는데 .. B+tree B+tree가 뭐야? 검색하면 이제 이진탐색트리..B-tree, B+tree가 쏟아진다. 이 내용을 검색하면 정말 많은 내용이 쏟아진다. 유투브에도 흔한 내용이고 블로그글들도 많다.그런데 이 내용들을 보다보면 지식들이 다 따로 존재하고 연결짓기가 어려웠다. 이게 설명을 해주는데 구조랑 안그리고 말만 설명하면 왜 이렇게 되는데? 왜 여기까지만 알려주는데? 이런 생각이 많이 들어서 학습이 잘 안됐었다.그래서 나는 문답으로 학습할 수있는 클로드와 함께 ..
-
카테고리 없음
@Lock을 사용하지 않았는데 데드락이 터지는 문제 - InnoDB FK 잠금전파
1.들어가며 Long fk -> fk를 가지는 방식으로 바꾸면 데드락이 터진다.비관락이 안 잡혀 있는데도 터진다. @Version 낙관락까지 걸려있는데도 터진다.낙관락은 락을 안잡는 방식으로 알고있었는데 사실이 아니었다.- @Column(name = "product_id", nullable = false)- private Long productId;+ @ManyToOne(fetch = FetchType.LAZY)+ @JoinColumn(name = "product_id", nullable = false)+ private ProductModel product; 읽었던 블로그 아티클상품 주문 동시성 문제 해결하기 - DeadLock, 낙관적 락(Optimistic Lock) & 비관적 락(Pessimisti..
-
DB
DeadLock 미리 고민하고 예방하자.
들어가며1.1 DB 락은 왜 존재하는가MySQL에서 DB락은 S,X락이 있으며, 동시 트랜잭션이 같은 데이터를 동시에 건드릴 때 무결성을 지키기 위한 장치다. 두 트랜잭션이 아무런 통제 없이 같은 row를 읽고 쓰면 한쪽의 변경이 다른 쪽의 변경에 덮이는 Lost Update가 발생하고, 읽는 도중에 값이 바뀌는 Non-repeatable Read가 발생한다. 락은 이러한 간섭을 막기 위해 "이 데이터를 누군가 다루는 동안 다른 쪽은 기다린다"는 규칙을 강제한다. 락은 보통 두 가지 모드로 나뉜다. 공유 모드(S, Shared)는 여러 트랜잭션이 동시에 들고 읽을 수 있는 락이고, 배타 모드(X, eXclusive)는 한 트랜잭션만 들 수 있어 쓰기에 쓰인다. 두 모드의 동시 가능 여부는 단순한 행렬로 ..
-
카테고리 없음
[Spring] catch로 예외를 잡았는데 왜 롤백 된거지?
들어가며상품 좋아요 기능을 개발하던 중, 따닥 동시성 문제(한번에 2번 눌러지는경우) 를 해결하기 위해 아래처럼 코드를 작성했다.@Servicepublic class ProductLikeService { @Transactional public void like(Long userId, Long productId) { try { productLikeRepository.save(ProductLikeModel.create(userId, productId)); } catch (DataIntegrityViolationException e) { // 동시에 같은 좋아요 요청이 들어오면 UK 위반이 발생할 수 있으니까 // ..
-
카테고리 없음
JPA 비관락을 위한 InnoDB 락 구조 이해
1. 들어가며JPA를 공부하다가 낙관락(Optimistic Lock)과 비관락(Pessimistic Lock)을 접하게 되고, 비관락을 잡는 SQL을 보면 FOR UPDATE가 붙는데 이게 raw락을 의미한다는 말을 들었고, 이게 MySQL에서는 로우락이 아니라 인덱스에락이 걸린거라는 말을 들었다. "비관락이 DB 락을 직접 사용한다는데, 그럼 MySQL에서 락이 어떻게 동작하는 거지?""인덱스가 없으면 테이블 전체가 잠긴다는 게 무슨 말이지?"이게 다 뭐지? 그게 뭔데? 디깅하다보니 MySQL이 락잡는 방식에 대한 이해가 없으면 알기 어려웠다.아래 내용은 CLAUDE와 이야기하며 학습한 내용을 기반으로 정리한 글이다. 이 글에서 다루는 것MySQL 읽기락(S락)과 쓰기락(X락)의 동작 방식JPA ..
-
DB
Lost Update를 막는 두 가지 방법 — SERIALIZABLE vs 비관락 비교하기
서론재고, 좋아요, 쿠폰 같이 같은 row의 카운트를 갱신하는 로직에서는 같은 동시성 문제가 반복적으로 등장하는데, 이를 흔히 Lost Update라고 부른다. N개의 트랜잭션이 같은 row를 동시에 수정할 때 마지막에 커밋된 값만 반영되고 나머지 변경이 묻히는 현상을 가리킨다. 트랜잭션 ACID와 격리 수준을 학습하면서 SERIALIZABLE이 다른 트랜잭션의 읽기·수정을 모두 막는 강력한 방법이지만 그만큼 동시성을 떨어뜨린다는 점을 알게 됐다. 한편 비관락(SELECT ... FOR UPDATE)도 다른 트랜잭션의 읽기·수정을 막는다는 비슷한 설명이 따라붙는데, 둘이 정확히 어디서 어떻게 다른지가 궁금해 직접 실측해봤다. 다루는 두 후보를 Spring 표기로 옮기면 격리 수준 선언과 비관락 어노테이션..
-
카테고리 없음
동시성 처리 방법론과 기준 세우기
1. 개요이커머스 프로젝트를 진행하면서 재고 수, 좋아요 수, 쿠폰 수처럼 자주 변경되는 데이터의 동시성 문제를 정리하고 있다. 흔히 "비관락 vs 낙관락"이라는 비교가 먼저 떠오르지만, 막상 코드를 들여다보면 "따닥 이슈"로 생기는 동시성 문제는 락이 아니라 DB 제약으로 더 자연스럽게 해결된다. 컴퓨터 안에서 진짜 "동시"라는 시점은 존재하지 않는다. 한 요청이 진행되는 중간에 다른 요청이 끼어들면서 트랜잭션 실행 구간이 겹치는 상황이 동시성 문제로 드러난다. 따라서 극단적인 부하가 아니더라도, 두 트랜잭션의 구간이 겹치기만 하면 동시성 문제가 발생한다. 이 글은 프로젝트에서 마주친 동시성 지점들을 두고 어떤 기준으로 어떤 전략을 선택했는지를 정리한다. 정답을 제시하려는 글이 아니라, "왜 이걸 골랐..
-
DB
동시성 테스트로 레이스 컨디션을 재현하는 방법
서론동시성 충돌컴퓨터 세계에 진짜 "동시(simultaneous)"라는 건 없다. CPU 코어가 아무리 많아도 OS 스케줄러 관점에서는 여러 스레드의 명령어가 시간축 위에서 잘게 쪼개져 끼워 넣어지는 인터리빙(interleaving)으로 처리된다. "동시 요청"이라고 부르는 것도 실제로는 "거의 같은 순간에 인터리빙되는 요청들"에 가깝다. 그렇다면 충돌은 무엇인가. 인터리빙 자체는 문제를 일으키지 않고, 트랜잭션 임계영역(critical section)이 겹칠 때에만 문제가 된다. 임계영역이란 공유 자원을 읽고 판단하고 쓰는 구간을 가리킨다. 재고 차감을 예로 들면 재고 조회 → 0보다 큰지 확인 → 1 차감 세 단계 전체가 하나의 임계영역에 해당한다.T1: |--조회--확인--차감--|T2: ..
-
DB
비관적락은 정말 순서를 보장할까? - MySQL의 트랜잭션 스케줄링 CATS
개요낙관락과 다르게 나는 비관락은 순서를 보장하는 매커니즘이라고 생각했었다. 왜? 검색했더니 "작업 순서 보장" 이라는 말을 다른 트랜잭션 요청들의 순서 보장이라고 멋대로 오해했기 때문이다. 여기에 개인적인 유추가 더해졌다. 비관락은 먼저 온 트랜잭션이 락을 잡고 사용하는 동안, 다른 트랜잭션은 커넥션을 점유한 채 타임아웃까지 대기한다. 이 동작에서 자연스럽게 대기 큐가 연상되었고, FIFO 구조라면 도착 순서대로 잠금이 허가될 것이라고 예상했다. 그러나 비관락은 정확한 트랜잭션 요청 순서를 항상 보장하지는 않는다. 왜 그럴까? 전통적으로 MySQL은 트랜잭션의 잠금 허가(Grant)를 순수하게 대기(Waiting) 순서에만 근거해 결정해 왔다. 이 방식을 FCFS(First Come First Se..
-
카테고리 없음
[JPA] (4) CASCADE, orphanRemoval, 그리고 Aggregate Root의 생명주기 관리
트러블슈팅: CascadeType.PERSIST + JpaRepository.save()현상Order E2E 테스트에서 orderJpaRepository.save(OrderModel)로 주문을 저장할 때, 자식 엔티티인 OrderItemModel의 brand_name 컬럼이 null로 INSERT되어 SQLIntegrityConstraintViolationException이 발생했다.스프링 추상 예외 DataIntegrityViolationException으로 래핑되어 올라온 상태// arrangeOrderItemModel.create(productId, 50000, 2, "오버사이즈 코트", "ACNE STUDIOS")// actinsert into order_items (brand_name,...) ..
-
카테고리 없음
[JPA] (3) ORM 엔티티 매핑
들어가며JPA에서 가장 중요한 개념 2가지를 꼽으라면 객체-관계 매핑(ORM)과 영속성 컨텍스트(Persistence Context)다. 이번 글에서는 ORM 엔티티 매핑을 다루며, 크게 4가지 매핑으로 구분한다.객체 - 테이블 매핑필드 - 컬럼 매핑기본 키 매핑연관관계 매핑마인드맵으로 매핑을 공부하고 있는데, 대부분 옵션을 알고 사용하는 거에 초점이 맞춰져 있다. 그 중에서 조금 조심히 봐야할건 기본 키 매핑의 옵션별 특징인 것 같고, 주의 깊게 봐야할 매핑은 연관관계 매핑이다.객체-테이블,필드-컬럼 매핑은 주의점만 확인하고 다른 매핑들은 자세히 다루는 글이다.1. 객체-테이블 매핑@Entity가 붙은 클래스는 JPA가 관리하는 엔티티가 된다. JPA를 사용해서 테이블과 매핑할 클래스라면 @Entity..
-
카테고리 없음
[JPA] (2) 영속성 컨텍스트
들어가며JPA에서 가장 중요한 개념 2가지를 꼽으라면 객체-관계 매핑(ORM)과 영속성 컨텍스트(Persistence Context)다.ORM이 "어떻게 매핑하는가"의 문제라면,영속성 컨텍스트는 "매핑된 엔티티를 어떻게 관리하는가"의 문제다.JPA가 제공하는 대부분의 이점 '1차 캐시, 동일성 보장, 쓰기 지연, 변경 감지, 지연 로딩' 은 모두 이 영속성 컨텍스트라는 하나의 메커니즘에서 파생된다. 영속성 컨텍스트를 잘 이해하고 까먹지만 않으면 AI로 JPA 개발 시 왠만한 코드 흐름은 파악 가능한 것 같다. 학습하자.영속성 컨텍스트란?사실 우리는 이미 사용하고 있다.Spring Data JPA로 개발할 때, 영속성 컨텍스트를 의식하지 않아도 대부분의 코드는 잘 동작한다. 회원을 저장하는 로직을 떠올려보..
-
카테고리 없음
같은 상품에 좋아요를 두 번 누르면 어떻게 될까?
동시성과 중복 방지 상품 좋아요(Like)는 "한 유저가 한 상품에 대해 하나의 좋아요만 가질 수 있다"는 비즈니스 규칙을 가진다. 단순해 보이지만, 이 규칙을 시스템에서 보장하는 것은 생각보다 더 생각할 필요가 있다.유저가 좋아요 버튼을 빠르게 두 번 누르면?네트워크 지연으로 같은 요청이 두 번 전송되면? 우연히 한번 클릭했는데 흔히 따닥이라는 2번 클릭하게 되는 경우가 종종 생긴다면? 이런 상황에서 중복 좋아요가 생성되지 않도록 어떻게 방어할까?애플리케이션 레벨에서 조회 후 검증하는 방식DB 레벨에서 유니크 제약으로 강제하는 방식,혹은 두 계층을 조합하는 방식이 있다.각 방식은 정합성 보장 수준, 구현 복잡도, 예외 처리 전략 사이에서 서로 다른 트레이드오프를 가진다. Case A. 애플리케이션 레벨..
-
카테고리 없음
상품이 바뀌면 좋아요(찜) 데이터는 어떻게 해야 할까?
상품 변경과 좋아요 상품 좋아요는 특정 시점의 상품에 대한 사용자의 관심 표현이다. 그런데 상품은 살아있는 데이터다. 가격이 바뀌고, 이름이 바뀌고, 판매 중단될 수도 있다. 이때 기존에 좋아요 해둔 사용자들의 데이터를 어떻게 다뤄야 할까? 이 질문은 두 개의 축으로 나뉜다.첫 번째 축: 좋아요 데이터를 삭제할 것인가, 유지할 것인가 (정책)상품이 변경됐을 때 기존 좋아요 데이터를 정리할지, 그대로 둘지를 결정하는 비즈니스 정책의 문제다. 두 번째 축: 삭제한다면 언제, 어떻게 처리할 것인가 (구현)삭제라는 정책이 결정됐다면, 이를 어떤 시점에 어떤 방식으로 실행할지를 결정하는 기술적 구현의 문제다.각 축에서 선택지마다 서로 다른 것을 확보하고, 서로 다른 것을 감수해야 한다.축 1. 삭제할 것인가, 유..
-
카테고리 없음
Claude Code로 개발하며 만든 컨벤션 검증 시스템 — Skills, Hook, ArchUnit, 서브 에이전트
서론컨벤션은 있는데 왜 안 지켜질까? 팀 프로젝트에서 느낀 한계사이드프로젝트 동아리에서 팀 개발을 하면서, 코딩 컨벤션 문서를 꽤 공들여 만든 적이 있다. 패키지 구조부터 Entity 설계 방식, DTO 네이밍 규칙까지 나름 상세하게 정리했다. 그런데 실제로 코드를 작성하기 시작하면 문제가 반복됐다. 하지만 매번 확인하는게 정말 쉽지 않다. 점점 문서를 확인하지 않고 각자의 감으로 작성했다. 주간 회의가 끝나고 나서 따로 컨벤션 관련 이야기하는 시간이 많아졌었다.돌이켜보면 문제의 근본 원인은 컨벤션 문서의 품질이 아니었다. 첫째, 암기에 의존하는 구조였다. 컨벤션이 있어도 결국 개발자가 기억해서 적용해야 했다. 둘째, 피드백 시점이 너무 늦었다. 컨벤션 위반은 커밋 후 코드 리뷰에서야 발견됐다. ..
-
카테고리 없음
Claude Code 커스텀 상태 라인 쉽게 만들기
서론Claude Code를 쓰다 보면 "지금 어떤 모델이지?", "컨텍스트 얼마나 남았지?" 같은 걸 자꾸 확인하게 된다. 매번 /model이나 /context를 치는 대신, 이 정보들을 터미널 하단에 항상 띄워두는 상태 표시줄을 만들어 보자.적용 결과Claude Opus 4현재 모델명 (테마 색상으로 강조)📁my-project작업 디렉토리🔀main (2 files uncommitted, synced 3m ago)Git 브랜치 + 미커밋 파일 수 + 리모트 동기화 상태🔌3 MCP활성 MCP 서버 수██▄░░░░░░░ 18% of 200k tokens컨텍스트 사용량 프로그레스 바💬 이 프로젝트의...마지막으로 보낸 메시지 미커밋 파일이 하나뿐이면 파일명까지 표시되고, Git 리포지토리가 아닌 폴더에..
-
카테고리 없음
[JPA] (1) 왜 복잡하다고 생각 드는 걸까?
서론JPA를 공부하다 보면 지연 로딩, fetch join, N+1, 프록시, 영속성 컨텍스트… 개념이 꼬리에 꼬리를 물고 나온다. 대학교 2학년 때 김영한 JPA 강의로 학습을 마쳤지만, 시간이 흐르고 AI가 등장하면서 JPA 메커니즘을 깊게 생각하지 않고 그냥 쓰게 되는 아쉬움이 남았다. AI가 생성한 JPA 코드를 보고 흐름을 파악하고, 잘못된 방향으로 흘러가면 제어하고, AI가 제안하는 기술 간 트레이드오프를 판단해서 결정을 내리려면, JPA의 각 기능이 왜 존재하고 어떤 결과를 만드는지를 '가볍게' 라도 확실히 알고 있어야 한다고 느꼈다. 이 글은 코드 레벨의 최적화 기법이나 동작 원리를 상세히 다루지 않는다.대신 "JPA에서 왜 이런 개념들이 존재하는가?"를 하나의 맥락으로 연결하여 "이렇게 ..
-
카테고리 없음
스프링은 예외를 어떻게 처리할까
서론스프링에서 프로젝트를 시작하면, 공통 예외 처리를 위한 보일러플레이트로 @RestControllerAdvice 단일 클래스에 N개의 @ExceptionHandler를 몰아넣는 패턴을 누구나 사용한다. 왜 다들 이 방식을 쓰는 걸까? 떠오르는 질문들을 적어봤다.Q. 왜 @ExceptionHandler로 스프링 예외처리를 맡기는 거지? 다른 예외처리 옵션도 있는데, 이것만의 뾰족한 장점이 뭘까?Q. @ExceptionHandler는 어떻게 예외처리를 하는 걸까? 어떤 코드를 편리하게 감싸주는 거고, 그 원본 코드는 뭘까?Q. @ExceptionHandler는 스프링 MVC의 편의 스펙이다. 이 도움 없이 원래 스프링에선 어떻게 예외처리를 하는 걸까?Q. MVC 스펙에서 벗어난 예외처리는 어떻게 하는 걸까..
-
카테고리 없음
변경에 흔들리는 시퀀스 다이어그램을 다시 그리며 배운 것
서론기능 요구 사항 정리 후, 설계의 초석으로 시퀀스 다이어그램을 그려봤고 실용성에 의문을 품게 됐다. 위에서 시퀀스 다이어그램을 왜,어떻게 그려야하는지 설명을 잘 해주고 있지만, 나의 시퀀스 다이어그램은 높은 변동성으로 유지보수가 어려운 단점이 있었다. 참… 그냥 AI한테 맡기고 편해질까 하는 생각도 들었다. 동기그런데 사이드 프로젝트 동아리를 하면서, 망해가던 팀의 커뮤니케이션을 회복을 위해 고군분투 했던 나에게, 이 시퀀스 다이어그램을 제대로 다룰 수 있게 된다면, 내 커뮤니케이션 스킬도 함께 올라가고 협업 부스팅에 기여할 수 있지 않을까? 하는 욕심이 생겨서, 도전해보기로 했다.목표나의 잘못된 습관을 찾고/고치고/개선한다. 시퀀스 다이어그램을 그려보면서 아키텍처 설계 과정임을 느끼고 나의 부..
-
카테고리 없음
순수 Java API 요청 vs Servlet API 요청
스프링 MVC를 공부하다 보면 가장 먼저 만나는 개념이 서블릿(Servlet)이다. "HTTP 요청을 처리해주는 자바 표준"이라는 설명만 들으면 와닿지 않는다. 그래서 서블릿 없이 순수 자바로 HTTP 서버를 만들어보고, 서블릿이 얼마나 많은 일을 대신 해주는지 체감해보기로 했다.HTTP 요청-응답의 9단계웹 서버가 하나의 HTTP 요청을 처리하려면, 아래 9단계를 거쳐야 한다.이 중에서 개발자가 진짜 하고 싶은 일은 비즈니스 로직 실행(7단계)뿐이다. 나머지 8개 단계는 모두 HTTP 통신을 위한 인프라 코드다.직접 Java로 소켓열고 회원가입 API요청을 .http에서 보내어 요청/응답 메세지를 받은 결과도 같이 있다.Servlet 없는 API 전체 코드package spring_mvc.pure_h..
-
카테고리 없음
회원 요구사항 분석부터 도메인 책임 분배까지
기능 요구 사항 1. 요구사항 정리'요구사항 정리'로 먼저 사용자 니즈를 파악하자. 구현 후 "이건 내가 원하는 기능이 아니야.." 라는 말을 듣지 않기 위해, 또 나중에 객체, 테이블, API 설계로 연결하기 위해서 정리한다. 정리하면 바로 도메인 모델링, 코드 구현 하기 전에, 잠깐 정리하는 구간이다.어떻게 접근해야할까 고민했다. 1.1. 유저 시나리오를 문장으로 정리사용자 니즈 파악이 목적이기 때문에, 첫 작업으로 유저 시나리오를 문장으로 정리했다. [유저 시나리오]비회원은 회원가입을 할 수 있다.회원가입한 유저는 내 정보를 조회한다. 회원가입한 유저는 비밀번호를 수정한다.1.2. 유저 시나리오에 예외/조건을 추가 잠깐, 다른 요구사항에도 필드 검증 조건이 흩어져 있으니 한번 전부 읽어보고 예외를..
-
카테고리 없음
Java 소켓 서버 직접 만들기 (콘솔에서 웹까지)
서론JVM에서 ServerSocekt으로 (단체채팅방) TCP서버를 만들어 N개의 클라이언트와 Console에서 채팅하는 예제가 있어 실습해봤다. 이 과정에서 서버소켓 - 클라이언트 소켓간의 통신 과정을 디테일하게 배웠고, 정리해보려한다. JVM의 ServerSocket으로 TCP 서버를 구축하고, N개의 클라이언트와 콘솔 기반 채팅을 구현하는 예제를 실습했다. 이 과정에서 서버 소켓과 클라이언트 소켓 간 통신 메커니즘을 상세히 학습할 수 있었고, 그 내용을 정리하고자 한다. 콘솔 채팅 구현 이후, 동일한 로직을 웹 환경으로 확장해보고 싶었다. 웹 소켓 서버를 구현하는 과정에서 콘솔 환경에서는 고려하지 않았던 문제들을 마주했고, 이러한 차이점과 해결 과정도 함께 기록하려 한다. 또한 웹 채팅 구현 시 클..
-
카테고리 없음
AI 협업의 적정 지점을 찾아 네 번 부딪힌 기록
과제 목표내 학습 목표이번 과제를 시작하기 전에 세운 목표는 나의 의도를 테스트 코드로 작성하고, TDD 방식으로 AI와 함께 기능을 구현해보는 것이었다. TDD로 요구사항을 먼저 정리하는 장점을 느끼고, 작게 쪼개고 점진적으로 설계하는 과정을 경험하며, 리팩토링이 가능하다는 것을 체감하고 싶었다.그런데 과제를 진행하면서 새로운 목표가 생겼다.'설계는 내가, 구현은 AI가'라는 명확한 역할 분리를 하면서 TDD 방식으로 AI에게 코딩을 위임하되, 설계 결정권은 내가 가져가고 싶었다. 여기서 질문이 생겼는데, 기능 요구사항을 받았을 때 어떤 변환 과정을 거쳐 AI가 정확히 구현할 수 있는 프롬프트 형태로 만들어지는가였다. 이 변환 과정을 알아보는 것을 새로운 목표로 삼았다. AI와 어떻게 협업해야 할까? ..
-
카테고리 없음
Java NIO - Buffer
서론자바 NIO를 알고싶다. NIO는 "Buffer → Channel → Selector" 구조를 지닌다.그래서 이 순서대로 학습할 계획이고, 그래서 Buffer 학습이 필요했다. 학습에 어려움이 있었다.내가 알던 Buffer는 JVM에서 보조스트림으로 사용하던 그 Buffer를 '다루는' '모와서 처리하는' 이런 몇글자로 설명이 끝나는 수준으로 이해하고 있었다. 그러나 NIO의 Buffer를 깊게 팔수록, 새로운 키워드들이 발굴됐고, 계속 이어지는 학습 과정에서 OS의 I/O처리 과정에 대한 이해가 필요했다. Kernal에도 Buffer가 있고, UserSpace에도 Buffer가 있다. 헷갈리지 않도록 학습이 필요해고, 두 버퍼간의 관계 이해가 필요했다. 그래서 처음에 운영체제 I/O 구조에 대..
-
카테고리 없음
Blocking I/O vs Non-Blocking I/O
Blocking I/O란?API를 호출해서 결과를 받을 때까지 스레드가 wait하게 되어 흐름이 일시정지되는 상황을 Blocking이라고 한다.예를 들어 파일에 데이터를 쓰는 작업을 생각해보자.1. File 생성2. Hello (쓰기)3. World (쓰기)4. 출력5. ... 여기서 2번 "Hello" 쓰기가 동기 모드로 일어난다면, OS의 파일 시스템이 실제 하드웨어에 파일을 쓰라고 요청을 보낼 것이다. 요청을 보내고 return을 받을 때까지 3번 "World" 쓰기는 블로킹당해 실행되지 않고 멈춘다.GUI에서 유저에게 화면을 보여주면서 입력을 받아야 할 때를 생각해보면 더 명확하다. 스레드가 한 개라면 사용자 입력을 처리할 때 화면이 멈출 것이다. 이 문제를 해결하는 전통적인 방법은 멀티스레딩이다..
-
카테고리 없음
Non-Buffered IO vs Buffered I/O
Non-Buffered IO vs Buffered I/O 먼저 내가 배운 개념을 정리했다. Non-Buffered IO vs Buffered I/O 핵심 학습 포인트 I/O 를 출발지,목적지 관점에서 바라볼 것 Buffer 는 그냥 메모리다.이 주제는 항상 성능,효율적이냐, 비효율적이더라도 기능에따라 효율을 포기해야한다. 이런걸 따진다.먼저 I/O를 봤을 때, 입출력의 주체가 있고, 대상이 있다.Buffered I/O, Non-Buffered I/O의 단위는 파일이라고 생각하면 된다.Processor가 --> OS에게 파일에 대해서 입출력 요구를 한다. JAVA를 프로그래밍하는 사람에겐 Processor가 아닌 JVM이라고 해야 맞지 않나요? -> JVM 자체가 User Mode Application P..
-
카테고리 없음
상황별 필수 메트릭과 QL 정리(간헐적 업데이트)
서론어떤 메트릭을 수집하고 싶을 때, 그라파나 대쉬보드를 자주 제작한다.그런데 어떻게 대쉬보드 만들지? 어떻게 QL를 작성하지? 매번 LLM에게 물어본다. (가끔 이상한 답변도옴) 문제는 LLM에게 매번 물어보면, 그 순간 QL은 해결은 됐겠지만, 소중한 경험들을 놓치는 것 같다.기본적으로 애플리케이션의 어떤 정보들을 수집하는지 이해하려고 하지 않는다.과거에 알아냈던 QL을 매번 처음 물어보는 것 같이 느껴진다. 그 결과, 내가 어떤 기능을 테스트하고자 했을 때, 어떤 메트릭을 수집해야하는지 스스로 판단이 어려워지는 것 같다. 나는 어떤 하나의 QL을 검색했을 때, 그외 다른 QL들은 어떤 것들이 있는지 확인하고 싶고, 내가 검색한 QL이 사실은 지금 상황에서 필요없는 매트릭일수도 있는지 스스로 피드백 ..
-
회고
실수 투성이였던 우테코 8기 최종 코테 후기
날짜 및 시간: 2026년 1월 10일 (토) 1시 ~6시 장소: 우아한형제들 삼성생명 잠실빌딩(작은집)파트: 백엔드우형 작은집. 일찍 들어오기나는 12시 (1시간 일찍) 시험장소에 들어왔다.들어왔을 때 포비님께서 신분증 검사를 맡아주시고 계셨고, 다양한 간식들을 챙겨 갈수 있게 아래 사진의 장소에서 제공되고 있었다. 시험 자리는 지정석이였다. 칠판에서 내 자리가 어디인지 확인하고 들어갔다. 내 자리는 앞에서 왼쪽 3번째 중간석이였다. 테이블에는 3명이서 사용할 수 있는 콘센트가 1개, 물, 선물이 놓여있었다.이번 8기때의 선물은 비누,때밀이였다. 비누향은 민트향이었다. 그렇게 자리에 앉고 와이파이 세팅 할 때 즈음에, 내 테이블의 왼쪽 자리 하신분이 커뮤니티에 익숙하게 봤던 이프님이 계셨다...
-
카테고리 없음
2026 새해 스타벅스 오픈런 후기
1월 1일이 되면 스타벅스에서 선착순 무료 음료 이벤트를 한다. 무료 음료를 받기 위해서는 말 그대로 선착순이라 첫날부터 아침일찍 일어나는게 관건이다. 뭐랄까, 마치 해돋이 보기 위해 일찍 일어나는 사람과 같은 루틴으로 하루를 시작해야하는게 웃기다. 웃기기도 하고, 나름 새해가 밝았는데 하나의 챌린지로써 생각해보면 나름 재밌어 보인다. 그렇게 첫 시작한게 2024년 새해였다. 24년 숫자에서 비롯하여 - 선착순 24명에게만 무료 음료와 스티커를 증정했다.집 앞 스벅은 8시에 매장 오픈했고, 이 당시 나는 28번째 순번이라 줄을 섰지만 아쉽게도 받지 못했다.한번 실패했던 2024년 새해 스타벅스 오픈런 에씨. 5분만 일찍올걸 1년 후인 2025년에는 이벤트 하는지 모르고 있었기에 참여하지 못했다...
-
러닝
초보 러너의 MBN 하프마라톤 도전기 (2025.11. 16)
런닝 3km가 한계였던 지난 10개월들나는 런닝을 이번 신년 목표로 세워서 1월 2일부터 시작해, 9월까지 계속 3km를 뛰어왔다. 런닝을 시작하게 된 계기는 2024 우테코7기 프리코스 탈락 후 합불 결과에 정신이 좌지우지되지 않기 위해 코딩 외에도 새로운 취미가 필요하다고 느낌과 동시에, 열정보다는 체력을 키워야겠다는 깨달음 속에서 지구력을 키우기 위한 운동으로 런닝을 시작했다. 1일 차 회고글을 다시 읽어보니, 실내 밖을 잘 나가지 않던 나에게는 1km만 뛰어도 너무 힘들어했고, 3km를 뛰는 데도 제대로 뛰지 못하고 중간에 2번을 쉬고 다시 뛰었었다. 신년 목표로 1년 동안 꾸준히 런닝 뛰기를 세웠지만, 바로 포기했다. 일주일을 뛰는 것조차 나에게는 버거운 일인데, 처음부터 1년이라는 기간은 런닝..
-
카테고리 없음
Spring Security는 왜 Filter Chain으로 만들어진걸까?
스프링 시큐리티가 해결하고자한 문제들과 Filter Chain이 선택된 이유까지.들어가며. Spring Security는 왜 만들어진걸까?개인적으로 어떤 기술을 공부할 때, 무작정 외우는 것이 아니라 이게 왜 필요한 것인지를 제대로 알고 그 이유에 대해 공감하며 공부하는 편이 효과적이라고 생각한다.스프링 시큐리티도 마찬가지다. SecurityFilterChain이니 AuthenticationManager니 하는 복잡한 개념들이 난무하는데, 왜 이렇게 복잡하게 설계됐는지 알고 나면 훨씬 이해하기 쉬워진다.스프링 시큐리티는 어떤 문제를 해결하고자 했었을까? 그 역사를 자료조사하면서 아래 공식 레퍼런스를 참고했다.https://docs.spring.io/spring-security/site/docs/4.0..
-
카테고리 없음
콘솔 출력 테스트 문제로 시작한 Java I/O 학습 여정
들어가며우테코 자동차 경주 미션을 진행하면서 출력에 대한 요구사항을 정리 했기에 출력 기능을 구현했고, 이에 대한 테스트도 필요한 상황이었다.출력 기능 구현 결과각 라운드마다 자동차의 이동 결과를 출력최종 우승자를 출력콘솔 출력 테스트 코드를 작성한다. 그런데 어떻게 작성하지?출력 기능을 구현하고 테스트 코드를 작성하려고 했지만, 어떻게 콘솔에 찍히는 것을 테스트해야 하는지 방법을 모르는 문제가 있었다.System.out.println()으로 출력한 내용은 그냥 콘솔에 찍히고 사라진다. System.out.println()으로 출력한 내용을 어떻게 검증해야 할까? 이 문제를 고민하던 중, 우아한테크코스 프리코스 테스트는 콘솔 테스트를 어떻게 가능하게 했었는지 궁금해졌다.우아코스 ApplicationTe..
-
카테고리 없음
기능목록서를 잘 작성 하고 싶다. 근데 자꾸 실패한다.
개요지난 글- 나의 엔지니어 철학 - 빠른 성장에 대한 고찰 에 이어지는 내용이다. 나는 빠르게 성장하고 싶다.그런 사람이 되고 싶으니까. 그 Step1로써 문제정의를 정확하게 보는 통찰력이 필요하다고 생각한다. 그 결과, 팀프로젝트에서든 내 인생에서든 낯선 상황을 유연하게, 빠르게 대처하는 사람이 되고 싶다.낯선 요구사항으로부터 문제 정의 능력을 훈련하고 싶다.그러면 그런 낯선 상황을 어떻게 연출하지? 25년 10월에 진행되는 우테코 프리코스 과정에서 진행되는 총 4개의 낯선 요구사항으로부터, 문제 정의 능력을 훈련하기로 했다. 그렇게 프리코스 첫번 째 미션이 개봉됐다. 이렇게 요구사항을 정의 해보자나는 문제를 풀어내는데 있어서 반드시 있어야만 하는 MVP 영역과 문제를 최적화 하기위한 비기능 요구..
-
카테고리 없음
Pattern.compile()은 왜 비쌀까? 실험으로 알아보는 정규표현식 성능
개요(글을 읽으실 분들은 대부분 정규 표현식을 사용하거나, 최소한 한 번이라도 들어 보셨을 것으로 생각하지만, 정의부터 알아보면 좋을 것 같습니다.)정규 표현식(正規表現式, 영어: regular expression, 간단히 regexp 또는 regex) 또는 정규식(正規式)은 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다. 개발하면서 문자열을 다룰 때, 가장 유용한 도구는 바로 정규 표현식이다. 복잡한 패턴의 문자열을 정규 표현식 없이 찾아내려면 조건문과 반복문을 끝없이 중첩해야 할 것이다. 상상만 해도 너무 복잡하다.정규표현식 없이 유효성 검증// 핸드폰 번호 유효성 검증: 010-1234-5678public PhoneNumber(String input) { Str..
-
카테고리 없음
프로그램 종료 System.exit()의 문제점과 main return
개요다음과 같이 종료 요구사항이 있을 때 System.exit()를 사용하여 즉시 종료할 수 있었다.요구사항: 입력값이 비어있으면 0을 출력 한다, (추가 요구사항 + 0 출력 후 애플리케이션을 종료한다.)System.exit()로 종료하기public static void main(String[] args) { try { String input = input(); if (input.isBlank()) { output(0); System.exit(0); } ... 다른 로직하지만 System.exit()는 편리하지만 JVM 프로세스를 즉시 종료시켜서 다른 기능들이 마비되는 문제가 있다.System.exit()말고 ..
-
카테고리 없음
나의 엔지니어 철학 - 빠른 성장에 대한 고찰
나의 엔지니어 철학적응력이 뛰어난 엔지니어나는 행복해지고 싶다. 그 중심에는 스스로를 인정하는 자존감이 있고, 나는 그것이 전문가로 인정받는 순간에 채워진다. 나는 엔지니어다. 2025년 AI시대 모든게 빠르게 흘러가는 지금, 엔지니어링 전문성은 과거처럼 하나만 깊게 파는 능력에 머물지 않는다. 빠르게 변하는 요구사항에 신속히 적응하여 문제를 해결하는 능력, 바로 그 적응력이 내가 정의하는 전문성이다. 그리고 그 적응력을 갖추기 위해, 나는 빠르게 성장하는 실력을 갈고 다듬어야한다. 개발 뿐만 아니라 인생에 있어서도 처음 마주하는 문제를 능숙하게 처리하고 싶다. 세상이 마주한 문제에 가장 먼저 기술적인 해답을 제시하는 엔지니어세상이 빠르게 변한다는 건, 변하기 전 세상은 비효율이였다는 것. 즉, 세상..
-
카테고리 없음
속도가 전부다. (Andrew Ng)
개요 "나는 빠르게 문제를 처리하고 싶고, 빠르게 방법을 타당하게 내놓고싶다. 나는 빠르게 성장하고 싶다." "그러면 나는 어떻게 빠르게 문제를 처리하고, 방법을 타당하게 내놓을 수 있을까? " 빠르게 성장을 경험한 전문가들의 아티클을 읽다가, 유투브 '속도가 전부다' 영상을 보고 감명 깊어 강연 내용을 아래에 정리했다. https://www.youtube.com/watch?v=0HB6NIrRe2A1. 구체성의 핵심은 '빠른 검증 가능성'이다.엔지니어가 설명만 듣고 바로 만들 수 있을 정도로 구체적인 아이디어만이 속도를 만든다. 'AI로 건강을 최적화하자'처럼 해석의 여지가 넓은 문장은 실행을 늦출 뿐이다. 같은 문장을 들은 엔지니어가 서로 다른 제품을 내놓는 순간, 팀의 방향성은 흩어진다. 반대로 구체..
-
카테고리 없음
Refresh Token을 서버에 저장하면 Session과 다를 게 뭘까?
부제 - HttpOnly 설정에 따른 토큰과 세션의 저장소 접근 비용 비교 분석개요이전 글. XSS 공격을 어떻게 막을 수 있을까? 에서 XSS 공격이 일어나는 상황과 탈취 시점에 따른 방어 방법들을 살펴봤다. 특히 탈취된 이후 피해 방지 방법으로 짧은 AT + RT 회전 방법을 소개했는데, 이번 글에서는 한 발 더 나아가 RT 자체가 탈취되는 상황을 어떻게 방지할 수 있을지 고민하다가, 어 세션이랑 똑같이 저장소에 관리해야하는데 이러면 세션이랑 다를게 뭘까? 궁금증을 풀어간 내용을 정리했다.세션 방식과 토큰 방식의 차이본격적인 이야기에 앞서 두 가지 인증 방식의 차이를 짚고 넘어가자. 세션 방식은 백엔드 서버에서 사용자의 로그인 정보를 세션으로 저장하고, 짧은 유효 기간을 둔 세션 ID를 클라이언트 브..
-
카테고리 없음
XSS, CSRF 공격을 어떻게 막을 수 있을까?
개요개인적으로 문장만 봤을 때 이해가 안되는 것들이 있는데, 나에겐 대표적으로 XSS, CSRF가 있다. 이번에 잘 알아보려고 한다. 인증 기능을 구현하면서, 매번 XSS 공격을 예방해야 한다라는 이유로 쿠키는 http-only =true가 필수다 라는 이야기와 또 그런 생각들을 나도 모르게 가지게 됐다. 우리 팀은 앱 개발이고 네이티브 기능도 사용해야 하는데 http-only = false 이면 안될까? 이 방법 말고 다른 방법으로 XSS를 막을 순 없을까? 이번 글에서는 XSS 공격이 어떻게 적용되는건지 이해하여 XSS를 막는 방법들을 살펴본다. XSS의 개념은 한번만 읽고 가자. 이해가 안되도 괜찮다.XSS(Cross-Site-Scripting)란 웹 애플리케이션 취약점을 악용하여 공격자가 삽입한 ..
-
카테고리 없음
TCP 헤더에는 어떤 정보들이 담겨 있는걸까? (with 와이어샤크)
이전 글 TCP는 왜 바이트 스트림을 쓰는가의 고찰에서 바이트스트림을 보내는 TCP의 책임을 알아보기 위해 헤더 내용을 찾아봤었다. 대표적으로 Sequence Number, Acknowledgment Number, Checksum 필드들을 확인했었는데, 그 외의 필드들을 확인하고싶다. 이번 포스팅에서는 TCP의 헤더 구조와 필드들을 알아보자. TCP (Transmission Control Protocol) 이름에서 나타나듯, TCP는 서로 다른 호스트(컴퓨터)에서 실행되는 프로그램 간의 통신을 담당하는데, 통신으로 보내는 정보를 안정적으로, 순서대로, 에러없이 교환할 수 있도록 하는 것에 목적을 둔 프로토콜이다. 그리고 OSI 7계층 중 '전송 계층'에서 사용되고 있는 프로토콜이다. TCP 이전의 ..
-
카테고리 없음
TCP는 왜 바이트 스트림을 쓰는가의 고찰
왜 TCP는 바이트 스트림일까? IP Layer와는 다르게 TCP Laycer(전송 층)는 신뢰성과 순서를 보장하는 책임을 지녔다. TCP는 '바이트 스트림'을 제공하고, 그 스트림을 전송하기 위해 내부적으로 '세그먼트(흔히 패킷이라고 부르는 것)'로 쪼개어 보낸다. 왜 바이트 스트림이지? 문자 스트림이면 더 직관적이지 않나? 비트 스트림은 더 근본 아닌가? 나는 이제 막 스트림 종류를 찾아봐서 스트림간 자세한 특징들을 모르지만 한가지 유추는 할 수 있었다. 신뢰성과 순서를 보장하기위해 바이트 스트림을 사용한다는 것. 다른것들은 그렇지 않다는 것. 정말 그럴까? 확인해보자. 스트림의 종류스트림은 크게 3가지 bit / byte / String 스트림이 있다.주의. 인터넷 좀 찾아보면 byte를 비트라..
-
카테고리 없음
[ReactNative] 잠금화면이여도 실시간 위치 보내는 방법 탐색 일지
개요런닝앱에서 실시간 내 위치 공유 요구사항으로, '앱이 잠들어도 좌표를 서버로 보낼 수 있어야함'이 추가됐다. 포그라운드에서는 웹소켓/HTTP가 잘 굴러간다. 그러나 화면을 잠그면 앱은 Background -> Suspended로 내려가고, 연결(소켓)이 끊기며 우리 팀(Runky)가 세운 5초 주기 전송 규칙은 무너진다.포그라운드 전제를 버리고, 비포그라운드 전제로 재설계 해야 한다. 어떻게 구현하지? 애플 문서를 파다가 Background URLSession을 알게 됐고, 우리 팀의 프론트 스택(RN + expo-location)에서도 어떻게 이 기능을 활용해 잠금화면에서도 유연하게 전송할지 고민 및 방법을 정리해 팀에 공유하고자 포스팅으로 정리했다.Expo 안에서 답을 찾을 수 있을까?우리 팀..
-
카테고리 없음
[iOS] 앱이 잠들어도 동작하는 방법 - 백그라운드 이벤트 처리
백그라운드 모드백그라운드 모드는 포그라운드가 아닌 상태(Background/Suspended/Not Running) 에서도 OS가 앱을 잠깐 깨워 작업 기회를 부여하도록 허용하는 권한이다. 즉, 화면이 꺼져 있거나 앱이 보이지 않는 동안에도 특정 이벤트가 도착했을 때 최소한의 코드가 실행될 수 있게 만드는 장치가 백그라운드 모드다. 중요한 점은, 이벤트 자체가 백그라운드에서만 발생하는 것은 아니라는 것이다. 예를 들어 위치 업데이트는 포그라운드에서도 동일하게 들어온다. 차이는 포그라운드가 아닐 때에도 그 이벤트를 처리할 수 있게 OS가 앱을 깨워 주느냐에 있다. 포그라운드라면 단순히 델리게이트 콜백이 호출되고 끝난다. 반면 Suspended 상태에서는 '깨워 줄 수 있느냐'가 관건이며, 바로 이때 백그라..
-
카테고리 없음
[iOS] 애플리케이션 라이프사이클 Forground, Background, SusPended
Apple은 앱의 상태 변화를 크게 세 가지 전환(A, B, C) 으로 묶어 설명한다.먼저 상태부터 간단히 정의하고, 이어서 작업중인 프로젝트 러닝 앱 Runky (iOS/RN) 시나리오로 예를 들겠습니다. iOS/watchOS의 대표 상태Forground: 화면에 출력되며, 사용자의 입력을 받아들이고 사용자와의 상호 작용을 통해 작업을 수행합니다.Background: 앱 화면이 더 이상 전면에 보이지 않는 상태입니다. 곧 suspended(중단) 될 수 있으며, 위치/오디오 등 특정 백그라운드 모드만 제한적으로 동작합니다.Not Running(실행 중 아님): 프로세스가 아예 없음(종료/크래시/부팅 전)Inactive(비활성): 포그라운드지만 이벤트를 받지 않는 아주 짧은 순간(전환 중) 예: 잠금 ..
-
카테고리 없음
[Spring Websocket] 컨트롤러 예외처리 - @MessageExceptionHandler
개요웹소켓에서 발생하는 예외 처리를 학습 후 적용 하고 있다. 스프링에서의 웹소캣은 2가지 핸들러를 모두 활용해야 한다.컨트롤러 이전(파싱/인증/라우팅) 예외 --> StompSubProtocolErrorHandler내부(검증/도메인) 예외 --> @MessageExceptionHandler 이전 글에서 StompSubProtocolErrorHandler 를 다뤘다. 이번 글에서는 @MessageExceptionHandler를 다룬다.- 참고 ( [이전 포스팅 글] [Spring Websocket] 메세징 파이프라인 예외처리 - StompSubProtocolErrorHandler )@MessageExceptionHandler 학습하기무엇을 하나?MessageExceptionHandler (Spr..
-
카테고리 없음
[Spring Websocket] 메세징 파이프라인 예외처리 - StompSubProtocolErrorHandler
개요컨트롤러 내부 예외 처리는 @MessageExceptionHandler에서, 메세징 파이프라인 예외 처리는 StompSubProtocolErrorHandler에서 다룬다. 위의 말이 아직 어렵다면, StompSubProtocolErrorHandler 학습 전, 프레임의 End To End 플로우를 이해하고 가자. 프로젝트에 웹소캣을 첫 적용을 하기 위해, 블로그 검색을 하다보면 다양한 예외 처리 지점이 보게된다.(HandshakeInterceptor, ChannelInterceptor, @MessageExceptionHandler, StompSubProtocolErrorHandler 등) 내가 모르는 예외 핸들러들이 있어서 추가적으로 학습하다보면, 무엇이 어느 지점에 작동하는지 혼동될 위험이 있다..
-
카테고리 없음
Nested DTO는 반드시 static으로 선언하자. 그리고 Record
결론 DTO를 Nested Class로 쓸 거면 기본은 static 이다. record를 멤버로(Nested) 선언하면 암묵적으로 static 이 적용된다. 외부 API(Request/Response) 문서화 대상이라면 Nested 대신 top-level DTO가 가장 안전하고 깔끔하다.1. Nested Class를 사용할 때 반드시 알아야 할 static과 non-static의 차이Java의 클래스 안의 클래스(Nested 클래스)는 크게 두 가지다. static (static nested class라고 부름): 외부 클래스 인스턴스와 무관하다. new Outer.Inner()로 생성한다.non-static (inner class라고 부름): 외부 클래스 인스턴스에 종속된다. new Outer().n..
-
카테고리 없음
Nested DTO를 잘 사용하기 위한 고찰
개인적으로 DTO 파일 수가 방대하면 프로젝트가 무겁게 느껴졌다.프로젝트를 시작하면서 팀원과 DTO 컨벤션을 정할 때, DTO 파일 수를 줄이는 것에 서로 동의했다. 동시에 계속 바뀔 클라이언트 요구에 유연하게 대응하기 위해 Layer별 DTO를 두어 관심사를 분리하기로 했다. 결론적으로 레이어별 DTO는 유지하되, 각 레이어의 여러 DTO 모델은 내부 중첩 클래스(Nested)로 한 파일에서 관리하는 방향으로 시작했다.이 과정에서 static vs non-static, record의 암묵적 static 학습, sealed interface 도입까지 해봤고, 개발 생산성 한계도 확인했다.상황(Situation)프로젝트는 선형 구조에 기반한 4계층 구조를 사용한다.api → 요청/응답용 DTO: Reque..
-
카테고리 없음
[Spring WebSocket]: 웹소캣에서 사용하는 @EventListener
스프링의 STOMP 메시징은 WebSocket 세션 수명주기와 브로커 상태 변화에 대해 여러 ApplicationContext 이벤트를 발행한다. 덕분에 개발자들은 ApplicationListener 또는 @EventListener로 이 이벤트를 구독해 연결/구독/해제/끊김/브로커 가용성을 추적할 수 있다. 관련 이벤트는 org.springframework.web.socket.messaging 패키지에 정의되어 있다. ApplicationListener를 상속한 Event 객체들을 알아보자. docs에서 소개하는 이벤트들은 아래와 같다.BrokerAvailabilityEventSessionConnectEventSessionConnectedEventSessionSubscribeEventSessionUns..
-
카테고리 없음
[Spring WebSocket] @Controller에서 사용할 수 있는 애노테이션 정리
무엇을 하나?Spring은 WebSocket 위에서 STOMP 프레임을 Spring Message로 변환해 처리한다. HTTP 요청을 @Controller + @RequestMapping으로 처리하듯, WebSocket 메시지도 @Controller를 사용한다.이때 메시징 라우팅과 처리에 사용되는 대표 애노테이션은 다음과 같다. 라우팅: @MessageMapping, @SubscribeMapping데이터 바인딩: @DestinationVariable, @Header, @Headers, @Payload메시지 전송: @SendTo, @SendToUser예외 처리: @MessageExceptionHandler 어디에서 제공(Where)?이 메시징 처리 어노테이션은 2개의 모듈에서 나눠 제공하는데, spri..
-
카테고리 없음
[Spring WebSocket] 메시징 모듈 파헤치기 (3) - 프레임 flow 그리기(End To End)
https://docs.spring.io/spring-framework/reference/web/websocket/stomp/message-flow.html Flow of Messages :: Spring FrameworkBoth the Java configuration (that is, @EnableWebSocketMessageBroker) and the XML namespace configuration (that is, ) use the preceding components to assemble a message workflow. The following diagram shows the components used when the simple built-in messadocs.spring.io 공식문..
-
카테고리 없음
[Spring WebSocket] 메시징 모듈 파헤치기 (2) - 웹소캣에서의 Channel들
이전 글 [Spring WebSocket] 메시징 모듈 파헤치기 (1) - Message,MessageHandler MessageChannelSubscribableChannelExecutorSubscribableChannel근데 이 3가지 구성 요소가 뭔지 잘 모르겠다. 아까 웹소캣 다이어그램에서 여러 channel들이 등장하던데 연관 있지 않을까?(ClientInBoundChannel, ClientOutBoundChannel, BrokerChannel) 그리고 이 3개 정체가 뭘까.. 클래스를 검색해보니 계층 관계를 가지고 있었다. MessageChannel 그렇다면 스프링 메시징에서 모든 채널들은 ExecutorSubscriableChannel'들이지 않을까 MessageChannel부터 알아보자...
-
카테고리 없음
[Spring WebSocket] 메시징 모듈 파헤치기 (1) - Message,MessageHandler
이 글은 학습 일기다. spring-messagign:6.2.9spring-websocket:6.2.9 웹소캣 프레임이 스프링 애플리케이션에서 엔드투엔드로 어떻게 흘러가는지 공부한 기록이다. GPT와 블로그, 공식문서를 읽어가며 내 프로젝트의 웹소캣 기능 구현을 구현해 나가던 중, 문서에서 'Flow of Messages'라는 제목으로 소캣의 핵심을 설명하는 챕터를 읽게 됐다. 현재 나는 웹소켓 기능을 구현하면서 의도치 않은 에러가 떴을 때, 문제 파악이 어려워서 로그로 문제 지점을 확인해가며 웹소캣을 몸으로 배우고 있었다. 점차 웹소캣이 이렇게 동작하겠구나 느낌을 받았지만, 느낌이 사실인지 팩트 체크를 하기 위해 이번 챕터를 제대로 이해하기로 했다.https://docs.spring.io/spring..
-
카테고리 없음
Spring WebSocket(1): 웹소캣 HTTP 핸드쉐이크 과정 및 주의점
웹소캣 연결하기 첫단계 HTTP 핸드쉐이크HTTP 핸드쉐이크로부터 웹 소캣 연결이 시작되고 최초의 핸드셰이크 과정에만 사용된다. 일단 클라이언트와 서버 간의 연결이 성공적으로 수립되고 나면 그 이후의 모든 통신은 HTTP를 거치지 않고 WebSocket 프로토콜을 통해 이루어진다. 이 초기 연결 과정을 `HTTP 핸드셰이크` 라고 부르고, 이후 클라이언트가 서버에게 기존 HTTP 연결을 WebSocket 연결로 '업그레이드' 해달라고 요청한다. 업그레이드? 여기서 업그레이드는 비유적인 표현은 아니고, HTTP 프로토콜에 실제로 존재하는 헤더의 이름이다. 클라이언트는 이 헤더를 통해 지금부터 이 HTTP 통신을 WebSocket 프로토콜로 바꿔서 사용하고 싶어요. 라고 서버에 요청 보내는 것이다. ..
-
카테고리 없음
JWT 인증, 서버 1대로 프론트엔드 로컬/배포 환경 통합 지원하기
상황 13기 DND 동아리가 공식적으로 마무리되었지만, 우리 팀의 개발은 계속 됐다. 우리 팀은 기능 보완과 운영 준비를 위해 개발을 계속 진행했다. 8주라는 제한된 기간 동안 가장 큰 병목은 프론트엔드–백엔드 통신 환경 차이로 인한 인증 문제였다. 개발 환경:프론트엔드:로컬: https://localhost:3000)배포: https://web.runky.store백엔드:배포: https://api.web.runky.store (단일 서버)백엔드는 로그인 이후 JWT AccessToken/RefreshToken을 HttpOnly 쿠키로 내려주고, 필터에서 쿠키의 AccessToken을 디코딩해 @AuthenticationPrincipal로 주입되는 구조였다. 증상:로컬 프론트에서 로그인/인증 요청 ..
-
카테고리 없음
DND 13기 백엔드 후기 (25년 7월 5일 ~ 8월 30일)
DND 13기 활동기간 : 2025.07.05 ~ 2025.08.30 (총 8주)포지션 : 백엔드팀 인원 : 6명(디자이너2,프론트2,백엔드2) github:https://github.com/dnd-side-project/dnd-13th-6-backend 나만의 목표 이전 DND 12기 백엔드 회고글 DND 12기 백엔드 후기 (2024.12.30 ~ 2025.02.22)DND 12기 활동기간 : 2024.12.30 ~ 2025.02.22 (총 8주)포지션 : 백엔드팀 인원 : 4명(디자이너2,안드로이드1,백엔드1) 처음 우리 팀은 디자이너 2명, 안드로이드 2명, 백엔드 2명으로 총 6명이었는데, 불가피plan22plan.tistory.com 한번 더 DND IT 동아리(13기)에 참여했다. IT 동..
-
카테고리 없음
러닝 앱이 있다면 사람들은 무엇을 원할까?
사이드 프로젝트 분야가 팀원들의 다수결 투표로 러닝 어플로 정해졌다. 목표로는 동기부여를 주는 런닝 어플이다. 아직 앱의 컨셉이나 기능들이 구체화가 되진 않은 상태다. 나는 런닝 어플로 기록에 집중된 '나이키 런'을 잘 사용하고 있다. 나이키 런을 사용하면서 러닝 동기부여가 잘 되는가? 생각 해 봤을 때 그렇진 않다. 그저 기록용이다. 물론 나만의 목표를 성취할 때 동기부여가 있긴 하지만 항상 자극 받는건 아니였었다. 동기부여가 떨어지는 경우가 종종 발생했다. 예를 들어 비가 오니까 쉬어야지. 어제 뛰었으니까 쉬어야지 미루기도 해봤고, 부상으로 한 달을 쉬니까 생각이 안나기도 했다. 어떻게 하면 런닝 동기부여를 줄 수 있을까 고민해 봤을 때 고민해봤지만 번쩍이는 생각이 들지 않았다. 그래서 동기부여..
-
카테고리 없음
JDBC에서 @Transactional 까지의 변화
개요사이드 프로젝트 진행 중 조회 기능이 여러 엔티티를 생성하는 사이드 이펙트를 포함하고 있어, 데이터 정합성 보장을 위해 하나의 트랜잭션으로 처리했었지만 성능 문제를 일으켰다. 트랜잭션 사용으로 수동 커밋 모드로 전환되고 관련 데이터에 락이 걸려, 다른 DB 세션의 업데이트 쿼리가 대기되는 현상이 발생했다. 이로 인해 여러 사용자가 동시에 시스템을 이용할 때 새로운 요청들은 락이 해제될 때까지 대기 상태에 머물러 전체적인 응답 속도가 저하되고 있었다. 이 문제를 겪으며 스프링 트랜잭션의 동작 방식과 효율적인 사용법에 대한 궁금증이 생겼고, 이번 포스팅에서 김영한 강사님의 '스프링 DB 1' 강의를 통해 JDBC에서 @Transactional까지의 기술 발전 흐름을 학습했다. 이 과정에서 얻은 지식을 ..
-
카테고리 없음
2023년 돌아보기
이전 벨로그에 작성했던 글을 가져왔습니다.작성 날짜 : 2024년 1월 3일평소 생활평소에는 하루 종일 학교 도서관을 오고 가며 개발 공부 했다. (집 갈때는 밤 11~12시..)학기중 놀거나 잠시 쉰 날이 한 손가락으로 셀 수 있는 정도다...내가 학교를 늦게 들어갔으니, 더 잘해야 한다는 압박이 어느정도 있기도 하고내 분야에 전문가가 되고 싶은 마음이 사실 더 크다.더 잘하고 싶다.이러다보니 대학 생활 못 즐기고, 연애도 못 하고,공부만 하고 지냈다.노는 것보다 지금 내 개발지식을 보완하는데 관심이 더 가는 상황이라 그랬지만..아쉽긴 하다.코딩에 입문한지 1년 10개월 정도 됐다.2022 3월~ 2023 12월.이 기간 동안 내 공부 스타일은 비효율의 끝판왕을 보여줬지 않았을까?학교에서 잠깐 배운 C..
-
카테고리 없음
[치짤] 기획부터 MVP 배포까지의 과정
1. 발단 나는 일상 속에서 다양한 방식으로 짤(인터넷 유머 이미지)을 활용하고 있다. 친구들과 카카오톡으로 대화할 때 요즘 유행하는 짤들을 공유하며 대화의 재미를 더한다. 또한 카페나 커뮤니티에 글을 작성할 때도 내용에 어울리는 짤들을 함께 첨부해 게시물의 흥미를 높인다. PPT 발표 자료를 만들 때도 적절한 짤들을 활용해 내용을 더 생동감 있게 표현한다. 내가 이렇게 짤들을 자주 사용하는 이유는 단순한 텍스트보다 이미지가 주는 임팩트로 내 메시지의 전달력을 높이고, 보는 사람들의 집중도를 올릴 수 있기 때문이다. 짤들을 찾는 과정은 보통 현재 상황이나 전하고자 하는 내용에 어울리는 키워드를 먼저 생각한 후, 그 키워드로 구글 이미지 검색을 시작한다. 검색 결과 중에서 내 의도와 상황에 가장 잘 맞는 ..
-
러닝
2025년 3월 4월 러닝 후기
# 3월 - 관절염 발생 3월에 마지막 학기의 개강이 시작되고 나서 학교 주변에 뛰기 시작했다. 3km 17분 30초그러다가 12일 쯤 학교 동생을 꼬드겨서 12일날 같이 3km 러닝을 뛰었는데, 왼쪽 무릎에 관절염이 생겼다. 처음에는 별거 아닐거라 생각하고 몇일 후만 낫겠지? 생각했었는데 5일 후인 27일에 다시 뛰었더니 관절염이 재발했다. 발을 디딜 때, 특히 계단을 올라갈 때 찌릿찌릿한 기분 나쁜 통증이 일상에 동반되었다. 무릎이 나을때까지 러닝을 멈췄다. 뭐지? 나이가 먹어서 무릎 관절이 안좋아졌나 생각이 든다. 이때까지만 해도 관절염이 별 생각을 안했던 것 같다. 22일날 날이 풀려서 기분이 좋아 2km를 더한 5km를 뛰었다. 한 2km쯤에 다시 왼쪽 무릎이 쑤셔왔고, 어떻게든 5km를 ..
-
Java
중복 데이터 검증 INSERT. MySQL INSERT IGNORE 분석
한줄 요약 : 유니크키로 INSERT IGNORE 사용시 성능이 좋지 않습니다. SELECT + INSERT 방식이 효율적입니다. 발단 - 반복되는 중복 검증 쿼리 프로젝트 기능 개발 하면서, 중복 안되게 데이터 삽입 해야하는 상황이 있었다.이때 유니크 키를 만들어 SELECT로 존재 검증후 + INSERT 쿼리를 날렸다.1. 유니크키 생성2. 데이터 존재성 검사 - SELECT 쿼리3. INSERT 쿼리 점점 프로젝트 기능이 생겨나고, 또 똑같은 중복 방지 삽입 기능이 요구되어서, SELECT + INSERT 쿼리를 사용해야 했다.앞으로도 이렇게 중복 검사를 해야하는 걸까? 내가 모르는 효율적인 중복 삽입 방지 쿼리가 있지 않을까?자연스럽게 궁금해졌다. 한방 쿼리 'INSERT IGNORE' ..
-
카테고리 없음
회원/비회원 조회 기능 문제, 테이블 설계 과정 정리
기능 요구 사항 조회수 ➡️ 회원,비회원 가능➡️ 추가로 하루에 한 번만 증가!중복을 방지해야 함(IP+User-Agent 등으로 식별) 내 조회 기록 ➡️ 회원만 가능 즉, 조회수 증가 로직은 회원/비회원 모두에게 공통 적용되고, 조회 기록 조회는 회원에게만 필요한 기능이다.둘의 공통점은 모두 '조회 이력' 기능을 수행하고 있다. 따라서 하나의 조회기록 테이블을 만들어서 insert 쿼리로 첫 데이터 생성 후, 기간 검증을 통해 중복 조회수를 막고, select 쿼리로 '내 조회 기록' 기능을 만들고, count 쿼리를 날려서 '조회수' 기능 구현을 하면 되지 않을까! 자연스럽게 생각이 든다. 우선 만들어보자. 비회원을 고려하지 않고 회원 한정 조회 이력 테이블을 만들어 봤다. 회원의 조회 이력..
-
카테고리 없음
치지직 API AccessToken 발급 및 로그인 구현하기
개요프로젝트에서 치지직 로그인 기능을 만들어야 했다. 그럴려면 AccesToken을 발급받아야 했다.이때의 과정을 공유하려고 한다.애플리케이션 등록하기API 이용을 위해서는 애플리케이션 등록이 필요하다. https://developers.chzzk.naver.com/ 치지직 CHZZK지금, 스트리밍이 시작됩니다. 치지직-developers.chzzk.naver.com 이동한후, 애플리케이션 등록을 해줘야 한다. 잠깐. 애플리케이션 등록시 주의사항을 참고하자. 등록이 다 됐으면 사용하고싶은 API들의 요청을 보낼 수 있게 하기 위해 AccessToken을 발급 받아야한다.어떻게 보면 로그인 기능과 유사하다. 치지직 AccessToken을 얻어보자 1. 치지직 정보 제공 동의 화면으로 이동하기 - 클라리..
-
Spring
Spring Data JPA - Impl 네이밍으로 인한 순환 의존 문제와 해결
1. 문제 상황최근 프로젝트에서 ZzalJpaRepository라는 JPA Repository 인터페이스와, 아래처럼 ZzalJpaRepositoryImpl이라는 클래스(사용자 정의 구현체)를 만들었더니, 애플리케이션 실행 시 순환 의존성(circular reference) 에러가 발생했습니다. 에러 로그:Action:Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automat..
-
DND
DND 12기 백엔드 후기 (2024.12.30 ~ 2025.02.22)
DND 12기 활동기간 : 2024.12.30 ~ 2025.02.22 (총 8주)포지션 : 백엔드팀 인원 : 4명(디자이너2,안드로이드1,백엔드1) 처음 우리 팀은 디자이너 2명, 안드로이드 2명, 백엔드 2명으로 총 6명이었는데, 불가피하게 2명이 제명되면서 최종적으로 4명이 프로젝트를 이어가게 됐다. 나는 백엔드 파트를 맡았고, 디자이너 2명과 안드로이드 1명과 함께 협업했다.4주차까지는 격주 회고를 꾸준히 작성했지만, 5주차부터 예기치 못한 문제들이 매주 터지는 바람에 내 러닝 루틴과 회고 패턴이 크게 흔들렸다. 팀을 둘러싼 여러 이슈들을 해결하느라 정신없이 지냈지만, 다행히도 이전에 진행했던 우테코 프리코스와 12시간에 걸친 미션 구현 & 코드리뷰 연습(코딩 5시간, 코드리뷰 7시간)에서 길러..
-
카테고리 없음
git | 파일명 대소문자 불일치 문제 해결
개요 EC2에 서버 빌드에 문제가 생겼다. (./gradlew clean build)정리하면, 파일명 대소문자 문제가 있고, 롬복이 적용 안되어 있는 다양한 에러 로그들이 찍혔다. AI에게 물어봐서 파일명 대소문자 문제가 있는 걸 알게 됐다. 그래서 내 로컬 인텔리제이 코드랑, 푸쉬된 깃허브 코드를 비교해보니 대소문자 차이가 나는 문제가 발생해 있었다.당장 오늘 배포해야되는데, 이 문제 때문에 배포가 안되서 너무 스트레스였다. 결국 똑같은 프로젝트를 새로 생성해서 EC2에 긴급하게 배포로 응급처치를 하게 됐다. 이제 대소문자 문제를 해결해보자.해결 찾아보니 git은 원래 대소문자를 구별하지 않는다고 한다.git config core.ignorecase false을 입력하면 그뒤로 대소문자를 인식하게 된다..
-
카테고리 없음
AWS | 복붙해서 EC2 스왑 메모리 적용하기
개요AWS에서 프리 티어로 EC2를 띄우고, 스프링 부트를 클론 하고, jar 파일을 빌드했다.그런데 45분째 화면이 멈춰버렸다. 그래서 스왑 메모리(메모리를 늘려주는 방식)를 사용해서 이 문제를 해결했다. 설정 명령어- 명령어들을 그대로 차례대로 복사해서 붙여넣으시면 됩니다. - 스왑 메모리를 설정하기 전에, 스왑 파티션 또는 스왑 파일을 생성해야 합니다. sudo fallocate -l 2G /swapfile swapfile의 권한을 변경합니다. sudo chmod 600 /swapfile 스왑 파일을 생성합니다. sudo mkswap /swapfile 스왑 메모리를 활성화합니다. sudo swapon /swapfile 레퍼런스 https://engineerinsight.tistory.co..
-
코드 조각
[코드 조각] Spring Data JPA Audit 객체 생성
개요'실전! 스프링 데이터 JPA' 김영한 강사님 챕터6 내용 일부 발췌 실무에서 개발하시는 분들은 다 아실텐데 기본적으로 테이블을 만들 때 꼭 이걸 남기거든요.(등록일,수정일)이걸 남겨 놓으면 나중에 운영할 때 되게 편하고, 이걸 안 남겨놓으면 나중에 이제 운영할 때 진짜 지옥을 맛보거든요.이렇게 추적이 안되니까 도대체 이 데이터를 언제 바꿨어? 왜 지금 문제가 생긴 거지? 이런걸 다 알아야 되거든요.생성일,수정일 이거 두가지는 저는 사실 모든 테이블에 다 깔아요. 추가로 등록자, 수정자에 대해서도 넣습니다.그러니까 이 데이터를 도대체 누가 등록을 했고, 예를 들어서 관리자가 있는데 누가 승인을 했고 취소를 했는데 이거를 시스템적으로 다 로그인한 아이디를 기반으로 보통 많이 남기죠. 이 사람이 현재 로..
-
코드 조각
[코드 조각] 스프링 API 표준 응답 모델 구현 : ApiResponse 와 Record 타입
개요DND 활동 중, 다른 백엔드팀들의 깃허브의 커밋기록을 보고 있었다.다른 팀들의 코드는 내게 가이드역할을 해준다. 특히 팀 협업 경험이 없는 내게 나침반 같은 존재다. "아! 팀에서 프로젝트를 생성하면, 공통 기능부터 최우선으로 세팅하고 개발하는구나"를 배우게 됐다.누군가에게는 당연하겠지만, 당연하지 않는 사람이 나였다.😅 "기본으로 사용가능한 'ResponseEntity'를 사용하면 되지 않나?" 싶었는데, 예외가 발생했을 때, 성공했을 때 응답의 모양이 달라지는 문제가 있다고한다. 이렇게 경우에 따라 응답 데이터의 형식이 달라진다면 해당 응답을 전달받는 주체에게 사용하기 어려운 데이터가 될 수 있을것이다. 따라서 성공했을 때 형식과 실패했을 때 응답형식을 항상 json으로 통일시킬 필요가 ..
-
러닝
[2025. 러닝] 4주차 러닝 후기
4주차 기록 목표: 3km 5번뛰기할말:이제는 3km 잘 뛴다. 3km를 다 뛰고 나서 확 오는 탈진감이 완화됐다.러닝 루틴이 생긴 것 같다.뭔가 오늘 할일을 하나 마치고 나면 -> 바람 쐴 겸 러닝 뛰었다.이번 주 내내 그랬다. 어느새 1달 러닝을 뛰었는데, 1~2주차때 너무 힘들었던 걸 생각하면, 현재 많이 성장한게 느껴진다.
-
DND
DND 커피챗 | ERD - 좌표(latitude·longitude)만 저장하는 것과 주소(address)까지 함께 저장하는 것 중, 어느 쪽이 더 효율적인가요?
준비한 질문좌표(latitude·longitude)만 저장하는 것과 주소(address)까지 함께 저장하는 것 중, 어느 쪽이 더 효율적인가요? 배경 및 상황프로젝트 주요 기능: "사용자가 설정한 동네 반경 내에서 사건/사고 게시글이 올라오면 알림 발송"클라이언트에서 (위도, 경도) 좌표를 받고, 서버에서 이를 주소로 변환해 테이블에 저장하려고 합니다.현재 ERD에는 `address`(동 단위 예: 효자동)와 `latitude`, `longitude`를 모두 넣어두었는데, 이 세 항목이 중복되거나 필요 이상이 아닐까 고민됩니다.(예: 좌표만 저장하면 주소는 필요할 때만 변환해서 조회하면 될 수도 있는데, 괜히 `address`까지 같이 저장해둬야 하나?)GPT 4.0 모델이 "전부 관리하라"고 조언해..
-
DND
DND 커피챗 | ERD - 테이블에 여러 타입이 있을 때, 분리해야 할까?
준비한 질문테이블에 여러 타입이 있을 때, 분리해야 할까? (알림 테이블의 두 타입 : 전체 알림, 지역 알림) 배경 및 상황 저희 시스템에서 "알림"은 크게 두 종류입니다. 1. 전체 알림 (예: 전국 단위 공지나 긴급 재난 알림) 2. 지역 알림 (특정 지역 혹은 반경을 설정한 사용자에게만 발송)현재 알림 테이블에는 지역 정보를 참조하는 외래 키(FK)가 있는데, 전체 알림일 때는 이 FK가 `NULL`이어야 하는 상황이 발생합니다. "단일 테이블로 관리하되, 지역 정보 컬럼에 `NULL`을 허용하면 되지 않나?"라고 생각하고 있지만, "NULL 컬럼이 늘어나는 것"에 대한 우려도 있습니다. 한편, 알림 유형별로 테이블을 분리하면 스키마가 깔끔해지지만, 과연 그만한 가치가 있는지는 확신이 ..
-
DND
DND 커피챗 | ERD - 1:1(@OneToOne) 연관관계에서 테이블을 합칠지, 분리할지에 대한 기준
준비한 질문1:1(@OneToOne) 연관관계에서 테이블을 합칠지, 분리할지에 대한 기준을 물어보고 싶습니다. 배경 및 상황제 ERD에서 `User` 테이블과 `UserProfileImage` 테이블이 1:1 관계입니다.사실상 라이프 사이클이 같고(프로필 이미지는 항상 존재하며, 유저가 삭제되면 이미지도 삭제됨) 이미지 변경도 빈도가 낮습니다. 그래서 굳이 두 개로 나누지 않고 한 테이블에 합쳐버리면, 조인을 한 번 덜 해도 되니 쿼리 효율이 좋아 보이기도 합니다.다만 테이블을 분리하면 "책임 분리"가 명확해지고, 확장성도 좋아질 것 같다는 장점이 있습니다.이번 기회에 "1:1 관계 테이블 설계 기준"을 제대로 잡아보고 싶습니다.구체적인 궁금증1:1 관계에서 테이블을 분리할지 합칠지를 결정할 때 최우선..
-
DND
DND 커피챗 | ERD - 모든 테이블에 createdAt, updatedAt을 두는 것에 대한 고민
준비한 질문모든 테이블에 createdAt, updatedAt을 두는 것이 바람직한지 여쭤보고 싶습니다. 배경 및 상황현재 거의 모든 테이블(예: 이모지 테이블 등)에 createdAt, updatedAt 컬럼을 두고 있습니다.운영 중 발생한 이슈 추적이나 변경 이력 파악에 편리하다고 알고 있지만, 클라이언트가 굳이 필요로 하지 않는 컬럼까지 일괄로 두는 것이 성능 저하로 이어지지 않을까 걱정됩니다. 특히 "한 컬럼의 데이터를 읽을 때 같은 블록 단위의 모든 데이터를 읽는다"고 들었는데,이 때문에 불필요한 I/O가 발생할 여지가 있다고 생각합니다."모든 테이블에 다 넣어도 괜찮을까?" 또는 "어떤 기준으로 컬럼을 두고/빼야 할까?"에 대해선뜻 결정하기 어렵습니다. 구체적인 궁금증createdAt, upd..
-
DND
[DND 12기] 3~4주차 회고
DND 3~4주차 시작 과제1. 이슈 관리 도구2. 프로젝트 아키텍처 3. 컨벤션 문서추가 할일 :4. ERD 작성하기 1. 이슈 관리 도구는 Jira로 관리한다.Jira를 이용하면 깃헙 이슈와는 다르게 개발자 아니여도 쉽게 같이 진행 상황을 공유 할 수 있고, 프론트,백엔드 깃이슈 관리를 한번에 할 수 있는 장점이 있다. 2. AWS 구조도는 간단하게, 프로젝트 아키텍처는 DDD 선형아키텍처 처음 접하는 AWS 구조도이전 기수가 제출한 미션 문서들에서는 공통적으로 AWS 구조도를 그려서 제출했었다. 이번에 AWS 구조도라는 키워드를 처음 접해보고, 무엇인지 인터넷에서 찾아보고 펼쳐봤다.이때 '이참에 AWS구조도를 많이 그려보고, 다음에는 어렵지 않게 잘 그릴 수 있게 하자!' 마인드로 과제를 했었다..
-
러닝
[2025. 러닝] 3주차 - 평소보다 느리게
이번 3주차 기록 목표: 3km 안쉬고 달리기. 이걸 5번하기 할말:뛰다보니까 힘들어서 못뛰겠다 싶었는데, 아는분께서 천천히 뛰라고 하셨다.근데 천천히(평소보다 가볍게 뛰었는데 통계적으로 한 10% 느리게 측정됨)뛰었는데 효과가 진짜 좋았다. 원래라면 700m에서 폐에 통증이 느껴졌다. 숨참은 느낌.근데 0.9배속으로 뛰니까, 2.3km까지 무난하게 뛰는 마법이 발생했다.먼가 싶다.
-
일기
나만의 System 만들기 - 그러니까 이것저것 다 시도해보세요 (스콧 애덤스)
https://www.youtube.com/watch?v=nSQudySPmW4 위 강연에서 성공 비법 3가지조언을 해줍니다. 1. 시스템을 만드세요. 2. 열정은 본질이 아닙니다. 3. 운에 본인을 노출시키세요. 아래 글은 "목표보다 시스템이 중요하다"는 강연 내용을 바탕으로, 제가 솔직한 감상을 덧붙여 정리한 것입니다. 지금까지 많이 들어온 ‘성공 공식’과도 비교해보면서, 각자에게 맞는 방법을 고민해보시면 좋을 것 같습니다.1. 시스템을 만드세요.목표는 패배자나 세우는 것이라구요..?솔직히 “목표는 패배자나 세우는 겁니다” 이 말은 자극적이죠. 저도 처음엔 “목표가 있어야 성공하는 것 아닌가?”라고 생각했습니다. 그런데 이 강연자는 100년 전 농부가 “겨울 전까지 40에이커 갈아야 해”라고 하던..
-
이펙티브 자바
[이펙티브 자바] 아이템 7. 다 쓴 객체 참조를 해제하라.
메모리 누수를 예방하자.자바는 강력한 객체 지향 프로그래밍 언어로, 다양한 기능과 안정적인 메모리 관리 메커니즘을 제공합니다. 특히, 자바의 가비지 컬렉션(GC) 시스템은 개발자가 메모리 관리를 직접 신경 쓰지 않아도 되도록 도와주지만, 잘못된 코드 작성 방식으로 인해 메모리 누수가 발생할 수 있습니다. 이번 포스팅에서는 자바의 메모리 관리 특징과 메모리 누수 문제, 그리고 이를 방지하기 위한 좋은 코드 작성법에 대해 살펴보겠습니다.GCJava는 가비지 컬렉션(GC)이라는 강력한 메모리 관리 메커니즘을 제공합니다. GC의 핵심 작업은 크게 두 가지입니다.1. 힙(heap) 내의 객체 중에서 가비지(garbage)를 찾아낸다.2. 찾아낸 가비지를 처리해서 힙의 메모리를 회수한다.최초의 Java는 GC 과정..
-
DND
[DND 12기] 2주차 회고
DND 2주차 시작과제2주차는 설문조사, 사용자 모델링 이후 -> 정보 구조 설계를 수행해야한다. 이 미션을 받았을 때, 정말 설문조사를 실시하는 건가? 의문이 들었다. 한번도 상상치 못했던 일이라서 그랬던 것 같다. 그리고 팀원들간 어떻게 이 미션을 함께 수행할지 고민이 들었다.할일 :1. 필드 리서치2. 사용자 모델링3. 정보 구조 설계(IA) 어라.. 전부 생소한 미션들이였고, 처음보는 단어들이 많았었다. 이러한 사람들을 위해 DND에서는 가이드 문서까지 함께 제공해준다.이 미션들을 어떻게 수행하지? 하지만 가이드 문서의 참조 아티클들을 읽어봤음에도, 어떻게 진행해야할지 감이 덜 잡혔었다.Slack에서 팀원분이 다음 회의 때 어떤 이야기들을 하실지 정리해주셔서, 가이드문서를 어떤 시각으로 봐야 될..
-
러닝
[2025. 러닝] 2주차 - 폐활량이 쓰레기구나
러닝 2주차 시작 목표 : 5일 뛰기(3km) 2주차 러닝 회고- 500m~1km 사이에 호흡이 금방 딸린다. 폐활량이 좋지 않다. 폐활량을 늘리는 것을 서브 목표로 해야겠다.- 날씨가 추운날에는 어쩔 수 없이 러닝은 뛰지 말아야 겠다. 진짜 잘못하다간 감기 걸릴 것 같은 느낌이 들었다.- 2km에 더 달리는 것에 한계를 느낀다(폐활량 이슈). 쉬어야 하는 타이밍인데 안쉬고 3km까지 완주한다면 내게 보상을 주고 싶어졌다.만약 안쉬고 3km까지 달리는 횟수가 3번이면, 하루 안뛰게 하도록 해야겠다.- 3주차때는 5일 뛰는 것을 목표로 하는데, 열심히 해서 4일 뛰도록 해야겠다. - 집에서만 살다보니까 건강문제 때문에 러닝을 시작했었다.(머만 하면 금방 피곤해짐)- 1주차까지만 하고, 사실 2주차때 ..
-
Bean Validation
@NotNull , @NotEmpty, @NotBlank 비교
@NotNull , @NotEmpty, @NotBlank 비교출처 : https://docs.jboss.org/hibernate/validator/6.2/reference/en-US/pdf/hibernate_validator_reference.pdf Bean Validation에는 “값이 있어야 한다”는 의도를 표현하기 위해 여러 가지 제약 어노테이션이 있습니다.가장 자주 혼동되는 세 가지가 @NotNull, @NotEmpty, 그리고 @NotBlank입니다.각각의 차이점은 다음 표로 정리할 수 있습니다.어노테이션검증 조건대상 타입목적@NotNullNull 허용 X빈 문자열("") 허용 O공백(" ") 허용 O모든 타입 (숫자, 객체, String, Collection 등)단순히 "null이 아님"..
-
IDEA
내 프로젝트에 불필요한 IntelliJ 파일이 올라가지 않도록 하는 방법
개요인텔리제이 내부 설정을 건드렸더니, 커밋에 나도 잘모르는 파일들이 생겼고, 실제로 새로 파일들이 생겼다. 새로 생긴 파일들은 무엇이고, 왜 생기는 걸까?IntelliJ IDEA가 프로젝트를 열거나 빌드/런 등 내부 설정을 저장하면서 자동 생성하는 프로젝트 설정 파일들입니다. 예를 들어 아래와 같은 파일들은 프로젝트별 혹은 모듈별 설정을 담고 있습니다.checkstyle-idea.xml : checkstyle 관련 설정compiler.xml : 컴파일 설정gradle.xml : Gradle 관련 설정modules.xml, xxx.iml : 프로젝트 구조 및 모듈 설정 정보vcs.xml : 버전 관리(VCS) 관련 설정 등이들은 IntelliJ에서 프로젝트를 열면 자동으로 생성/변경될 수 있기 때문에, ..
-
Map
[Java] EnumMap 깊게 배우기 (HashMap보다 빠른 이유)
개요Enum을 Key로 사용하는 HashMap을 사용하고 있었다. 그러다 다른분들 코드를 보다가 Enum에 특화된 EnumMap 자료구조를 알게 됐다. 우선 내가 아는 정보는 다음과 같은데, Enum을 Key로 사용할때 HashMap대신 EnumMap을 사용한다면 성능상 이점이 있다는 정도이다. EnumMap의 자료구조 특성을 정리해봤다. Chapter1. EnumMap 기본 이론 EnumMap의 JavaDoc 설명을 번역해서 정리한 내용은 다음과 같습니다. 1. Enum 타입 전용 MapEnumMap은 enum 타입 키 전용으로 최적화된 맵 구현체이다.맵에 사용되는 모든 키는 하나의 enum 타입에서만 가져올 수 있다.내부적으로 배열을 사용하므로 메모리 사용량이 작고 효율적이다.2. 키의 정렬 및 반..