_

Always be tactful

MAIN/Java & Spring 48

Variable Hiding / Shadowing

자바 상속과 관련하여과거, 김영한님의 자바 강의를 통해 상속의 개념과 다형성, 메서드 오버라이딩에 대해 학습했다. 비슷한 내용으로 글도 올렸었는데, 이번에 정보처리기사 실기를 벼락치기 하는 과정에서 무언가 착각을해도 단단히 착각했다는 것을 깨달았다. 자바에서는 상속 관계에 있는 클래스들 간에 이름이 같은 멤버가 있을 때, 변수 숨김 또는 메서드 오버라이딩이 동작하게 된다. 내가 착각하고 있던 부분은 변수 또한 메서드 오버라이딩처럼 동작할 거란 막연한 생각이었다. 아래 예시를 보자.public class Main { public static void main(String[] args) { Base a = new Derivate(); Derivate b = new Derivate(); ..

MAIN/Java & Spring 2025.07.19

자료구조 힙(Heap), 자바에 TCO가 없는 이유는?

들어가며자바에서는 java.util.PriorityQueue라는 표준 라이브러리에서 우선순위 큐(최소 힙)를 편리하게 제공하고 있다. 그럼에도 불구하고 힙의 동작 원리를 직접 파고들어 구현 방법까지 알아두는 것은 단순히 라이브러리 사용을 넘어, 자료구조에 대한 더 깊은 이해를 돕는다.힙(Heap)은 우선순위 큐 구현부터 다익스트라, 프림 알고리즘 등 다양한 곳에 활용되는 중요한 자료구조다. 이번 포스트에서는 "힙이란 무엇이고, 어떻게 동작하며, 왜 그렇게 동작하는지" 그리고 "배열을 사용한 직접 구현 과정과 최적화 가능성"까지, 여러 궁금증을 바탕으로 알기 쉽게 설명하고자 한다.힙(Heap)이란 무엇인가?힙은 완전 이진 트리의 한 종류이며, 다음과 같은 중요한 특징을 지닌다.힙 속성(Heap Proper..

MAIN/Java & Spring 2025.06.27

JPA 프로젝트에서 타임스탬프 자동화를 위한 세 가지 전략

타임스탬프타임스탬프(Timestamp)는 어떤 사건이나 데이터가 발생한 정확한 시간을 기록한 값이다. 예를 들어 특정 데이터가 생성된 시점이나 수정된 시점을 저장하는 데 사용된다. 타임스탬프는 왜 남겨야 할까?1. 데이터가 언제 생성되고 수정되었는지가 기록되기 때문에 변경 내역을 명확히 알 수 있다. 따라서 시스템 장애나 보안 사고 발생 시, 언제 어떤 변경이 있었는지를 추적하고 원인을 규명할 수 있다.예를 들어, 은행 시스템에서 고객 계좌 정보가 잘못 변경되었다고 가정하자. 타임스탬프가 남아 있다면 누가 언제 계좌 정보를 수정했는지 정확히 알 수 있고, 문제가 발생한 시점을 추적하고 원인을 파악해 빠른 대응이 가능하다. 단순히 기록을 넘어 실시간 문제 대응 및 복구 작업의 도구로 활용될 수 있다. (E..

MAIN/Java & Spring 2025.06.10

JPA 스펙에는 컬럼 순서에 대한 명확한 규정이 없다.

JPA와 컬럼 순서최근, ReadWe 프로젝트를 시작했다. 가장 먼저 Sign-up API를 설계하고 테스트해 보았는데, 엔티티 클래스에서 선언한 필드들이 정작 DB에 생성된 테이블을 보니 컬럼 순서가 뒤죽박죽이었다. 이유는 간단했다. JPA는 기본적으로 자바 리플렉션을 통해 엔티티 클래스의 필드 정보를 읽어온다. 그런데 리플렉션으로 필드 정보를 읽을 때는 자바 소스 코드에 작성한 순서가 보장되지 않는다. 쉽게 말해 아래와 같이 코드를 작성해도 DB에 생성된 테이블에서는 순서 상관없이 나타날 수 있다.@Entity@Table(name = "User")public class User { private String userId; private String email; private Strin..

MAIN/Java & Spring 2025.05.28

Spring Boot 드라이버 인식 오류 (driver-class-name)

📢 해결법이 궁금하신 분은 맨 밑줄만 보세요.도커로 MySQL 띄우고 연결하는 과정에서 드라이버 인식 오류가 발생했다.application.yml에서 MySQL 드라이버를 못 찾고 자꾸 mysql 패키지를 생성하겠냐는 알림이 떠서 난감했다.# 오류 발생 구문driver-class-name: com.mysql.cj.jdbc.Driver사실 스프링 부트는 드라이버명을 적어주지 않아도 알아서 찾아준다.그러나, 적었을 때 발생한 오류에 대해 해결하고 싶었다. (단순히 생략해서 해결하고 싶지 않았음) AI한테 물어보니 Gradle 빌드 파일을 다시 확인하라더라.의존성 주입이 안 된 것 아니냐는 의미였는데 내가 실수했을 리 없었다.Gradle 리프레시를 안 해서 그렇다는 답변도 받았는데, 역시나 말이 안 된다. ..

MAIN/Java & Spring 2025.05.23

Spring Boot에서 JPA로 Docker MySQL 연동하기

들어가며자바는 프로그래밍 언어고, 스프링은 자바 기반 웹 애플리케이션 프레임워크다.그런 스프링을 더 쉽게 쓰도록 돕는 툴킷이 스프링 부트다. ▼ 과거 배포 과정 (대략적)더보기WAS 설치 (서버): 톰캣 같은 WAS를 OS에 설치하고 직접 설정IDE 내 개발: 이클립스 같은 IDE에서 복잡한 코딩 후 컴파일WAR 생성 (파일): 애플리케이션을 .war(웹 아카이브) 파일로 패키징WAR 배포: 톰캣 같은 WAS의 'webapps' 폴더에 넣거나 직접 업로드하여 배포웹 앱 실행: WAS가 WAR 안에 들어있는 웹 애플리케이션을 풀어 서버 구동▼ 스프링 부트 도입 후더보기WAS 직접 설치 및 설정→ WAS(톰캣)을 내장 서버로 포함하여 바로 실행 가능WAR 파일 생성 후 WAS에 배포→ 실행 가능한 JAR 파..

MAIN/Java & Spring 2025.05.22

자바 표준 라이브러리 함수 Arrays.sort()에 대하여

더보기최근 두 달 동안 너무 바빴다.본 전공(경영) 중간고사, 개인 과제, 팀 프로젝트개인 프로젝트(크롬 익스텐션 개발, 웹 보안 찍먹)멋사 아이디어톤 준비, 자격증 시험 등 아무튼 알고리즘을 놓고 산 지가 벌써 두 달 조금 안 된 것 같은데,조금이나마 여유가 생기기도 했고 입과 전까지 목표한 게 있어서 다시 시작했다. 문제는, 자바 자체를 오랜만에 봐서 그런가 조금 낯설었다.나름 백준 골드5인데 애초에 IDE 자동완성 도움이 컸던지라 프로그래머스부터 켰다. 수고스럽지만 직접 타이핑해서 풀어야지.. 프로그래머스에서 몇 문제 풀다 보니, 정렬 알고리즘이 필요했는데 당장 생각나는 게 거품 정렬이었다.근데 제출하고 나니까 몇몇 테케에서 시간초과가 뜨더라. 거품 정렬이 느린 건 알고 있었다.분명 더 효율적인 정..

MAIN/Java & Spring 2025.05.20

RESTful API에서 '응답 설계'가 반이라고?

ResponseEntity응답 설계 핵심 도구우리는 ResponseEntity에 대해 왜 알아야 할까?이유는 간단하다.스프링 프레임워크에서 HTTP 응답을 정교하게 제어하기 위한 핵심 도구이기 때문이다.단순한 "값 반환"이 아니라, HTTP 상태 코드, 헤터, 본문까지 직접 다룰 수 있다. 1. RESTful API에서 '응답 설계'는 감히 절반이라 할 수 있다.REST는 HTTP 자체를 프로토콜로 삼는다.응답에 상태 코드, 헤더, 본문을 정밀하게 제어해야 하며, 이걸 직접 제어하는 대표적인 도구가 ResponseEntity다.return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found");→ 단순한 return "User not fou..

MAIN/Java & Spring 2025.04.13

비즈니스 로직이니까 서비스에 있어야지!

비즈니스 로직, 무조건 서비스에 두어야 할까?도메인 주도 설계(DDD)를 공부하다 보면 흔히 맞닥뜨리는 질문이 있다."비즈니스 로직이면 원래 서비스 레이어에 두는 거 아닌가?" 이 질문은 언뜻 맞는 말처럼 들리지만, 사실 절반만 맞는 말이다. 이 글에서는 비즈니스 로직의 위치에 대해 하나씩 짚어보며, 헷갈릴 수 있는 지점들을 정리해본다.서비스에 로직을 두는 게 맞는 경우다음과 같은 경우에는 비즈니스 로직을 서비스 레이어에 두는 것이 자연스럽다.여러 도메인 객체 간의 상호작용이 필요한 경우외부 시스템과의 연동이 포함되는 경우 (예: 메일 전송, 결제 API 호출 등)도메인 객체 내부에 두기엔 과도하거나 부적절한 경우예를 들어, "예약을 저장하고, 알림도 보내고, 결제도 트리거하는 흐름"이라면 이는 하나의 ..

MAIN/Java & Spring 2025.04.09

DDD에서는 private을 안 쓴다면서?

DDD에서는 private을 지양한다?객체지향에서는 정보를 감추라고 하는데, 도메인 주도 설계에서는 왜 자꾸 public을 강조할까? 들어가며객체지향에서는 이렇게 배운다."메서드와 필드는 최대한 감춰라.""캡슐화를 통해 객체의 내부 구현을 보호해야 한다."그런데 도메인 주도 설계(DDD)를 공부하다 보면 이렇게 말한다.“비즈니스 규칙은 숨기지 말고, 드러내라.” 그럼 결국, private 쓰지 말라는 건가?헷갈릴 수밖에 없다.도메인 개념은 감추지 말고 드러내야 한다스케줄을 체크하는 것은 꽤 중요한 도메인 개념이다.👉 그래서 다음과 같은 메서드를 외부에 열어주는 게 좋다.public boolean isSchedulable(LocalDateTime start, LocalDateTime end) { r..

MAIN/Java & Spring 2025.04.08

[메모] 도메인 로직과 비즈니스 로직

도메인 로직(Domain Logic)도메인의 규칙과 행위 자체를 다루는 로직비즈니스의 본질적인 규칙들 (예: "환자가 같은 시간에 두 번 예약할 수 없다", "의사는 하루에 최대 20명만 진료 가능하다")Entity나 Value Object 안에 담기는 게 일반적변화 가능성은 낮고, 오히려 잘 구조화하면 유지보수성이 높아짐 비즈니스/애플리케이션 로직(Application Logic)요청 흐름을 제어하거나 유즈케이스 단위로 처리하는 로직예: "예약 요청을 받아서, 예약 가능한지 확인하고, 저장하고, 결과를 반환한다"보통 Service 계층에서 구현도메인 로직을 조합하고 orchestration 함도메인 모델은 이 시스템이 어떤 규칙을 가지는지 에 집중하고,애플리케이션 계층은 그 규칙을 언제, 어떻게 실행할..

MAIN/Java & Spring 2025.04.08

[메모] DTO와 record

record란 무엇인가? record는 자바 14부터 도입된 클래스의 일종이다. 따라서 내부적으로도 final class로 컴파일된다.즉, record는 불변 객체를 간편하게 만들기 위한 클래스의 축약 문법인 것이다!record 선언을 통해 자동 생성되는 것들은 다음과 같다.- 모든 필드 private final 선언- 생성자- Getter (필드명과 동일한 이름의 메서드)- equals() / hashCode()- toString()요즘엔 DTO를 record로 선언한다. 사실 DTO는 필드를 외부에 노출하고, 읽기만 하는 경우가 많다.그래서 불변성 + 간결함을 모두 가진 record랑 찰떡궁합이라고 볼 수 있다!DTO 클래스 이름 짓기는 어떻게? 이름 짓기라는 게 사실 스타일 차이라서 어떤 게 맞다고..

MAIN/Java & Spring 2025.04.06

무분별한 Getter & Setter 사용은 OOP 원칙을 위배한다.

들어가기에 앞서, 우리는 Getter와 Setter에 대해 학습했다. OOP 원칙 중 캡슐화에 대해 인지하였고, 따라서 Setter 사용을 지양해야 한다는 것 정도는 이미 알고 있는 사실이다. 그렇다면 왜 Getter 사용도 지양해야 하는 걸까?또는, Setter를 지양해야 하는 명확한 이유는 뭘까?Getter와 Setter의 탄생 객체 지향은 정보 은닉에서 시작한다.객체 지향 언어의 장점은 물론 다양하겠지만, 가장 큰 장점 중 하나가 유연성이다. 이러한 설계 방식은 변화하는 요구사항에 쉽게 대응할 수 있도록 한다. 유연성을 가능하게 하는 요소는 무엇일까?바로, 1. 캡슐화 2. 상속 3. 다형성이다. 그중 캡슐화, 이하 정보 은닉은 내부 구현을 숨기고 필요한 부분만 외부에 공개하도록 한다. 외부 코드가..

MAIN/Java & Spring 2025.03.27

[Spring] OOP: SOLID 원칙

Object-Oriented Programming 👉 객체지향 프로그래밍을 위한 다섯 가지 중요한 설계 원칙을 SOLID 원칙이라고 한다. *더보기는 관련 예시임 1. Single Responsibility Principle (단일 책임 원칙)하나의 클래스는 단 하나의 책임만 가져야 한다.즉, 여러 기능을 한 클래스에서 처리하지 않는다.더보기✅ 정보 저장 기능과 정보 출력 기능을 별도의 클래스로 분리2. Open/Closed Principle (개방-폐쇄 원칙)확장에는 열려 있고, 수정에는 닫혀 있어야 한다.즉, 기존 코드를 변경하지 않고 새로운 기능을 추가할 수 있도록 설계한다.더보기✅ 조건문 대신, 인터페이스나 추상 클래스를 사용하여 새로운 기능을 확장3. Liskov Substitution Pri..

MAIN/Java & Spring 2025.03.26

[Java] 제네릭과 명명 관례

제네릭  제네릭은 용어에서 알 수 있듯이 범용적으로 사용하는 데 목적이 있다. 이는 메서드에 매개변수를 추가하는 것과 비슷한 맥락이지만 결정적인 차이가 있다.  메서드는 매개변수에 인자를 전달해서 사용할 값을 전달한다. 반면, 제네릭 클래스는 타입 매개변수에 타입 인자를 전달해서 사용할 타입을 결정한다.더보기를 생략한 Raw Type도 가능하지만 사용하지 않는다. Raw Type이 존재하는 이유는 과거 코드와의 하위 호환이 필요했기 때문에 지원할 뿐이다. 제네릭 명명 관례E - ElementK - KeyN - NumberT - TypeV - ValueS, U, V, etc.더보기타입 인자로 기본형(int)을 사용할 수 없으며, 대신 래퍼 클래스(Integer)를 사용한다.

MAIN/Java & Spring 2025.03.24

[Java] BOJ 18870: 좌표 압축과 랭킹 알고리즘

문제수직선 위에 N개의 좌표 X1, X2, ..., XN이 있다. 이 좌표에 좌표 압축을 적용하려고 한다. Xi를 좌표 압축한 결과 X'i의 값은 Xi > Xj를 만족하는 서로 다른 좌표 Xj의 개수와 같아야 한다. X1, X2, ..., XN에 좌표 압축을 적용한 결과 X'1, X'2, ..., X'N를 출력해보자.이해하기좌표 압축을 적용한 값 X'i가  Xi > Xj를 만족하는 서로 다른 좌표 Xj의 개수와 같다. 중복되는 원소가 같은 순위를 가진다는 점이 마치 SQL Server에서의 DENSE_RANK 느낌인데, 이 문제에서 추가로 고려할 점은 값이 작을수록 순위가 높다는 것과 가장 높은 순위는 0순위라는 점이다. 중복되는 원소를 같은 순위로 둔다는 점을 고려할 때, 일단 Set이나 Map을 활용..

MAIN/Java & Spring 2025.02.24

큐 구현체 LinkedList vs ArrayDeque

문제정수를 저장하는 큐를 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오. 명령은 총 여섯 가지이다.push X: 정수 X를 큐에 넣는 연산이다.pop: 큐에서 가장 앞에 있는 정수를 빼고, 그 수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.size: 큐에 들어있는 정수의 개수를 출력한다.empty: 큐가 비어있으면 1, 아니면 0을 출력한다.front: 큐의 가장 앞에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.back: 큐의 가장 뒤에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다. BOJ에서 제공하는 큐 문제다. LinkedList와 ArrayDeque 모두 큐 자료구조를 구현할 ..

MAIN/Java & Spring 2025.02.21