_

Always be tactful

분류 전체보기 109

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

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

토스페이먼츠 3년 이하 서버 개발 챌린지

후기어느덧 개발을 시작한 지 반년이 지났다. 처음 시작했을 때보다는 확실히 아는 것도 많아지고 점차 익숙해지고 있지만 여전히 부족하다.스스로 부족한 걸 알기에 감히 이력서를 넣을 생각은 추호도 없었다.(SSAFY 입과 후 어느 정도 기본은 잡고 이곳저곳 지원해보려 했음) 그러다 정말 감사하게도 지인의 추천으로 토스 서버 개발 챌린지에 지원하게 되었다.'과제 테스트 경험이나 해 보자'라는 생각을 갖고 지원했기 때문에 큰 부담은 없었다.게다가, 하나도 못 건들고 끝낼 거라 생각했는데 그래도 6개월 간 열심히 공부해서 그런지 건드릴 순 있었다.(테스트에 대해 하고 싶은 얘기가 많지만 보안 서약을 했기 때문에 적을 수 없다..) 아무튼 당연한 얘기겠지만, 나는 과제 전형에서 탈락했다.모든 프로세스가 낯설었지만 ..

Common vs Global: 패키지 구조 이해하기

들어가기 전에가장 흔하게 사용되는 Common 패키지에 대해 말하자면, 결국 핵심은 구조화 및 가독성 향상이다.프로젝트를 진행하다 보면 프로젝트 내 여러 모듈이나 레이어에서 공통으로 쓰이는 코드가 생기기 마련이다. 코드 재사용성을 극대화하고 중복 코드를 방지하기 위해, 나아가 유지보수 측면에서 편리하기 위해 우리는 공통 코드들을 따로 빼게 된다. 이러한 코드들의 모음집이 Common 패키지인 셈이다.※ 사실 패키지 구조라는 게 명확한 답이 있는 건 아니다 보니 가벼운 마음으로 읽었으면 한다. Common vs GlobalCommon으로 퉁쳐서 사용하는 경우가 많은데 사실 Common 패키지와 Global 패키지는 서로 의미가 다르다.Common: 공통으로 사용되는 모든 코드를 모아두는 패키지Global:..

.prettierrc

import 정렬하기Code formatter로 Prettier를 쓰고 있었다.그동안 import는 신경 쓰지 않고 살았는데, 프로젝트 규모가 커지면서 상당히 지저분해짐을 느꼈다. 찾아보니 sort-imports 익스텐션을 추천하더라.그러나 막상 적용하고 보니 정렬 기준이 이상했고 커스텀하기도 어려웠다. 다른 방법도 여럿 시도했지만 썩 마음에 들지 않았다. prettier-plugin 사용하기결국 선택한 방법은 Prettier 플러그인을 사용하는 것이다.(그동안 Prettier 플러그인으로 sort-imports가 있는 줄 몰랐다.)# 플러그인 설치npm install --save-dev prettier @ianvs/prettier-plugin-sort-imports플러그인 설치 후, 루트 디렉토리에 아..

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

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

Database driver: undefined/unknown

문제 상황Spring Boot 3.4.3에서 JPA를 추가하니 아래와 같은 로그가 출력되었다. Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)'] Database driver: undefined/unknown Database version: 9.3 Autocommit mode: undefined/unknown Isolation level: undefined/unknown Minimum pool size: undefined/unknown Maximum pool size: undefined/unknown 해결 방법연결부터 제대로 해야 한다는 생각에 고칠 생각부터 했다. "왜..

Docker Compose에서 MySQL 데이터 영속성 설정하기

🐳 도커 컴포즈최신 버전에서는 Docker Desktop이 기본적으로 Docker Compose v2를 포함하고 있어서 별도로 설치할 필요 없이 사용할 수 있다.과거에는 도커 컴포즈가 별도 바이너리로 취급되어 직접 설치하는 과정이 요구되었으며, dokcer-compose 명령어를 사용했다.# 설치 확인docker compose version# 출력 예시Docker Compose version v2.34.0-desktop.1docker-compose.yml # 기본 공통 구성docker-compose.override.yml # 로컬 전용 설정 (자동 인식)docker-compose.prod.yml # 운영 환경 전용.env # 환경변수데이터..

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

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

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

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

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

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

도커 설치하기 (MySQL 포함)

도커 설치개발환경과 완전히 같은 환경을 구축하기 위해 도커를 설치하자. Docker: Accelerated Container Application DevelopmentDocker is a platform designed to help developers build, share, and run container applications. We handle the tedious setup, so you can focus on the code.www.docker.comMac / Windows 정도는 당연히 구분하겠지만, 간혹 AMD64와 ARM64를 구분하지 못하는 경우가 있다.실행 단축키 (Win + R) → `cmd` 입력 → 명령어 `wmic os get osarchitecture` 입력`64-bit`이 ..

정보처리기사 필기 2일 합격 수기

기출문제 풀고 오답 확인하는 방식으로 진행했습니다. (1일 1회, 총 2회 분량)1일 차2022년 4월 24일 기출문제1과목: 60점, 2과목: 50점, 3과목: 55점, 4과목: 55점, 5과목: 35점최종 51점 불합격2일 차2022년 3월 5일 기출문제1과목: 75점, 2과목: 65점, 3과목: 65점, 4과목: 70점, 5과목: 65점최종 68점 합격25년 정기 기사 2회1과목: 70점, 2과목: 90점, 3과목: 60점, 4과목: 60점, 5과목: 60점최종 68점 합격혹여 필기 준비하시는 분들은 바로 기출 돌리시길 추천드립니다.공부법이라고 하기에도 애매할 정도로 비전공자에게도 쉬운 시험입니다. 다음엔 실기 합격 수기로 돌아오겠습니다.

자격증 2025.05.11

유휴 상태 콜백 메서드와 병렬 처리로 최적화 할 수 있을까?

스크롤 이벤트일부 로직이 로컬 스토리지를 사용하는 경우, 메인 스레드를 차단할 우려가 있어 requestIdleCallback을 통해 브라우저가 유휴 상태일 때만 실행되도록 고려하였으나, 현재 실질적으로 사용하고 있는 로직은 간단한 연산 후 DOM에 스타일만 반영하는 수준이므로 쓰로틀 + 디바운싱 구조만으로도 충분하다고 판단하였다. 오히려 requestIdleCallback을 사용하면 불필요한 지연이 발생할 수 있다. 메인 스레드를 막을 정도로 무거운 작업이 추가된다면 그때 다시 고려해야겠다. 현재로서는 성능보다 UX 측면에서 지연으로 인한 부작용이 생길 가능성이 다분하다. *Progress Bar가 실질적으로 사용자 경험 향상에 도움이 되지 않는다면, 완전 삭제도 고려하고 있다. 스크롤 이벤트 자체가 ..

세이브 취소/타이틀 축약/잔여 용량 체크/기억 잔존율 시각화

일단 기능 구현부터 마치기로 했다.최적화 문제는 어차피 아무리 고민해도 끝이 없다. 막상 배포하고 나면 예상하지 못한 곳에서 새로운 이슈가 분명 터질 것이다.구현 목록1. 매뉴얼 세이브 취소 *아주 작은 이슈가 있었는데 해결했다.이제는 사용자가 직접 등록한 웹 페이지에 대해 직접 삭제할 수 있다.*HTML이 익숙하지 않아 컨테이너 실수한 거랑 삭제 후 갱신된 정보로 새로 호출하지 않아 미적용되던 문제였다.2. 타이틀 축약 및 툴팁 제공 타이틀이 너무 긴 웹 페이지인 경우, 타이틀을 축약해 표시하도록 패치했다.사용자가 마우스를 갖다 대면, 툴팁 형식으로 풀 타이틀이 제공된다.3. 잔여 용량 정보 확인 사용자가 현재 사용 중인 용량을 직접 알 수 있게 되었다.이를 통해 조금 더 원활한 관리가 가능할 것으로 ..

배열 순회 문제와 팝업 진행률 이슈

현재는 savedSites 배열을 순회하며 새로 넘겨받은 url과 일치하는 사이트가 있는지, 인덱스를 통해 중복을 판단한다. 만약 중복이라면 url을 제외한 모든 요소를 갱신하고 있다. (title, lastAccessed, scroll, height) 팝업의 경우, Manual Save를 누를 때마다 진행률이 갱신된다.실제 진행률을 동적으로 반영하지 않아, 사용자가 직접 갱신해 주는 것이나 다름없다. 아쉬운 점이 몇 가지 보인다.일단 첫째, Map으로 관리했다면 어땠을까?왜 배열로 관리했을까?Map을 사용할 경우, 직렬화 이슈가 발생한다.배열은 JSON으로 자동 변환되지만, Map은 그렇지 않기 때문이다. 그럼에도 불구하고, 로직상 Map이 훨씬 깔끔하고 빠른 건 명백하다.적절한 변환 과정만 거치면 충..

크롬 확장 프로그램을 개발하자 (Where Was I?)

Where Was I?Where-Was-I?는 크롬을 통해 여러 웹 페이지를 오가는 사용자들을 위해 만들어졌다. 바쁜 현대 사회 속에서, 우리는 참 다양한 웹 페이지를 이용하게 되는데,여기서 문제는, 자주, 혹은 가끔이라도 재방문해야 하는 경우가 존재한다는 것이다.북마크는 WWI를 대체할 수 없다.크롬에서는 자주 이용하는 웹 페이지를 북마크로 관리할 수 있다.그렇다면 Where-Was-I?는 왜 필요한 걸까? 답은 간단하다.북마크는 Where-Was-I?를 대체할 수 없다.1. 북마크의 관리 범위는 상당히 제한적이다.웹 페이지를 북마크에 직접 등록해야 하는 수고스러움이 있다.나는 이것에 대해 사용자 의존도 문제라고 부른다.사용자가 북마크 하는 것을 깜빡할 수 있다.사용자는 북마크 대상을 명확히 구분할 능..

깃 히스토리는 중요할까? 중요하다면 왜 중요한 걸까?

체리픽 결과이전 커밋 메시지 이슈로 git rebase 하다 보니, 중복된 커밋들이 있다.기능별 브랜치 히스토리를 남기기 위해, develop 브랜치를 다시 분기해 체리픽 하고 push 했다.Merge pull request #2 커밋에서 분기해 feature/* 작업했더라면 깔끔했겠지만, 대신 체리픽이 불가능하다.일관된 커밋 메시지를 작성하고자 한 git rebase, 기능별 브랜치 히스토리를 추적할 수 있도록 다시 분기해 git cherry-pick 한 것이 오히려 히스토리를 난잡하게 만든 감이 없지 않아 있다.깃 히스토리많은 생각이 들었다. 고작 대소문자 구분을 위해 강박적으로 수정한 것과 히스토리에 집착해 이미 했던 작업을 다시 분기해 체리픽 하는 과정에서 너무 많은 시간을 투자하였고, 결과적으로..

실수를 통해 성장하는 개발자가 되자 (rebase? cherry-pick?)

커밋 메시지 실수어제 오랜 시간 작업하다 보니, 커밋 메시지를 일관되게 작성하지 못 했다.문제의 커밋은 아래 이미지를 통해 볼 수 있다.커밋에 있어서 정말 신경 써서 남기고 있었는데, 한 커밋에서 대문자로 시작한 걸 미처 인지하지 못 한 채 병합까지 해버렸다. 슬픈 사실은 이미 PR 날리고 병합까지 하고 나서야 이 사실을 알게 되었다는 것이다. 사실, 이미 push 한 상태에서 해당 커밋을 수정한다는 게 얼마나 위험한 일인지는 알고 있다. 그리고 본 프로젝트를 시작할 때 다짐했던 것이 개인 프로젝트지만 협업처럼 작업하자는 것이었기 때문에, 모순되는 행동일 수도 있지만 수정하고 싶은 욕구를 이겨내지 못 하고, 마침내 일을 저지르게 되었다.git rebase -i HEAD~10물론 아무 생각 없이 시도한 것..