-
만들고 난 뒤에 톤빛 기획 문서를 쓰면서 고친 것들
이미 돌아가고 있는 톤빛을 보면서 기획자였다면 썼을 문서 여덟 편을 거꾸로 채웠다. 쓰는 동안 서비스에 빠져 있던 것 아홉 가지가 나왔고, 다섯 가지는 그날 고쳐서 배포했다. 어떤 문서가 실제로 서비스를 바꿨는지 정리했다.

-
[백엔드 입문 #9] 레거시 MyBatis 코드로 본 SQL 매핑과 SQL 인젝션
SQL을 XML에 직접 쓰는 레거시 MyBatis 코드를 따라가며 정리했다. Mapper 인터페이스와 XML의 연결, 동적 SQL, #{}와 ${}의 차이와 SQL 인젝션, 그리고 FOUND_ROWS()에 같은 DB 연결이 필요한 이유.

-
셀카 퍼스널 컬러 진단 서비스를 만들고, 립 추천 서비스로 바꾸기까지
셀카 한 장으로 퍼스널 컬러를 가늠하는 서비스를 만들었다가, 3주 만에 '내 얼굴에 맞는 립을 골라 주는' 서비스로 방향을 바꿨다. 왜 시작했고, 어디서 막혔고, 무엇을 기준으로 바꿨는지 정리했다.

-
[백엔드 입문 #8] JUnit과 Mockito로 도메인, UseCase, 통합 테스트 작성하기
Jest에 익숙한 프론트 개발자가 JUnit과 Mockito를 따라가며 정리한 백엔드 테스트. 도메인, UseCase, 통합 테스트의 세 층과 각각이 잡는 문제, 그리고 설계가 테스트를 쉽게 만드는 이유.

-
[백엔드 입문 #7] Spring 예외가 프론트 에러 응답이 되는 과정
프론트에서 매일 꺼내 쓰던 e.response.data.message가 서버 어디에서 만들어지는지 따라갔다. 예외 전파, 전역 예외 처리기, message/errorCode/logMessage의 역할, 예외 종류와 HTTP 상태 코드, warn과 error의 구분까지.

-
[백엔드 입문 #6] 출고 상태 규칙을 도메인 모델에 두는 이유와 멱등성
"이 상태에서는 이걸 하면 안 된다" 같은 규칙을 코드 어디에 둘까? WMS 출고를 따라가며 빈약한/풍부한 도메인 모델, 캡슐화, 같은 요청이 두 번 와도 버티는 멱등성, 전략 패턴을 정리했다.

-
[백엔드 입문 #5] @Transactional의 동작과 롤백 범위
거의 모든 UseCase 메서드 위에 붙어 있던 @Transactional을 정리했다. 트랜잭션이 하는 일, save 없이 저장되는 시점, 롤백되는 예외와 안 되는 예외, 그리고 트랜잭션이 되돌리지 못하는 외부 API 호출까지.

-
[백엔드 입문 #4] JPA Entity 매핑과 Repository 메서드 이름 규칙
지난 글에서 Spring이 객체를 대신 만들어 연결해 주는 의존성 주입(DI)을 정리했다. 이번에는 메서드 이름만 썼는데 SQL이 실행되는 이유, 그리고 Java 객체가 DB 테이블과 어떻게 연결되는지 JPA를 정리한다.

-
Web Locks를 검토하며 정리한 브라우저 저장소 경계
같은 사이트를 같은 브라우저에서 열었는데도 저장소를 공유하지 않는 경우가 있다. 그 경계를 정하는 게 브라우저 프로필이다. 업무에서 사용자가 여러 창을 띄워 같은 작업을 동시에 진행하다가 브라우저 스토리지의 데이터가 꼬이는 문제를 다룬 적이 있다. 해결책으로 Web Locks…
-
[백엔드 입문 #3] Spring 의존성 주입과 Bean 싱글톤
지난 글에서 Java 문법을 정리하면서 계속 마음에 걸리는 코드가 있었다. final 필드는 생성자에서 반드시 값을 넣어야 한다. 그런데 생성자도 없고, new DeleteFeatureFlag(...)를 부르는 곳도 없다. 그런데도 null이 아니다. 이 두 가지를 각각 다른…

-
[백엔드 입문 #2] TypeScript와 비교하며 읽은 Java 문법
지난 글에서 API 요청 하나가 백엔드에서 처리되는 흐름을 따라갔다. 이번에는 그 코드를 읽으며 헷갈렸던 Java 문법을 TypeScript와 비교하며 정리한다. 새 예제는 가져오지 않고, 지난번에 본 피처 플래그 코드를 문법 관점에서 다시 읽었다. 가장 낯설었던 점:…

-
[백엔드 입문 #1] API 요청 하나가 백엔드에서 처리되는 과정
프론트엔드 개발자로 일하면서 백엔드는 늘 "API 문서 너머의 무언가"였다. axios.post 한 줄을 보내면 응답이 돌아오는데, 그 사이에 무슨 일이 일어나는지는 잘 몰랐다. 그래서 회사에서 쓰는 WMS(창고관리시스템) 백엔드 코드(Java 17 + Spring Boot)를…

-
PDA용 모바일 웹을 Expo WebView 앱으로 전환한 과정
물류 현장 작업자들이 PDA로 사용하는 WMS 모바일 웹을, 브라우저 접속 방식에서 설치형 하이브리드 앱으로 전환한 경험을 정리했다. 기술적으로 아주 복잡한 작업은 아니었지만, "서비스를 제공하는 방식 자체"를 바꾼 작업이라 과정과 판단 기준을 기록해두려고 한다. 이전에는 작업자가…

-
레거시 화면 이관 QA를 Playwright로 자동화한 과정
레거시 화면을 새 앱으로 옮기면서 가장 어려웠던 건 화면을 옮기는 일 자체가 아니었다. 옮긴 화면이 예전과 똑같이 동작한다는 걸 증명하는 일이 훨씬 어려웠다.이번 글에서는 레거시 기능을 빠짐없이 테스트 케이스(TC)로 만들고, headless 브라우저가 TC를 하나하나 직접 눌러…

-
1,056줄 Express 커스텀 서버를 Next.js API Routes로 옮긴 과정
레거시 코드를 리팩토링할 때 가장 어려운 점은 "왜 이렇게 만들어졌을까?"를 이해하는 것이다. 내가 개발하고 있는 WMS(Warehouse Management System) 프로젝트도 마찬가지였다. Next.js 기반 프로젝트임에도 불구하고 별도의 Express 커스텀 서버를…

-
Babel에서 SWC로 전환해 Next.js 빌드 시간 66% 줄이기
Babel에서 SWC로 전환하고 번들을 정리해 빌드 시간을 235.81초에서 80.32초로 66% 줄였다. GitHub Actions 빌드는 약 6분에서 약 3분으로 줄었다. 로컬 빌드에 약 4분, GitHub Actions 빌드에 약 6분이 걸렸다 빌드가 CI/CD 파이프라인의…

-
레거시 Next.js를 모노레포로 옮기기 위한 설계와 전환 계획
본 문서에서는 Legacy Web과 Mobile을 모노레포 프로젝트로 통합하는 설계와 전환 전략을 제시한다. Next.js 12.3.6 + JavaScript(ES6) MobX 6.5.0, Material-UI v4 React Query v3, Axios, npm 개발 환경 복잡…

-
setState 직후 값이 바로 바뀌지 않는 이유
이번 글에서는 useState가 비동기적으로 동작하는 원리와 올바른 사용 패턴에 대해 다뤄보겠다. 먼저 비동기적이라는 것은 setState를 호출한 직후에 상태가 즉시 반영되지 않음을 의미한다. 위 코드에서 handleClick을 호출하면 setCount(count + 1)이…
-
key를 바꿔 React 컴포넌트 상태를 초기화하는 방법
React에서 key prop은 리스트나 iterable 객체 렌더링 시 중요한 역할을 하지만, 상태(state) 관리에도 영향을 미칠 수 있다. React에서 key는 각 컴포넌트의 고유성을 보장하여 변경 사항을 효율적으로 감지하고 업데이트하는 역할을 한다. 리스트를 렌더링할 때…
-
setInterval 타이머 지연을 requestAnimationFrame으로 해결한 방법
코드 리뷰를 진행하던 중, 기존 구현된 타이머에서 인터벌 시점이 지연되는 문제가 있다는 피드백을 받았다. 문제를 해결하기 위해 두 가지 방법을 생각해보았다. inboundProcessStartTime 변경 시 항상 현재 시간을 기준으로 경과 시간을 계산하므로, 인터벌 시작/취소로…

-
CDN 동작 원리와 CloudFront 캐싱 설정
CDN의 동작 원리와 장단점, 캐싱 전략, 그리고 AWS CloudFront로 CDN을 구성하는 방법을 조사해 정리했다. CDN(콘텐츠 전송 네트워크)은 지리적으로 분산된 여러 개의 서버 웹 페이지, 이미지, 동영상 등의 콘텐츠를 사용자의 실제 위치와 가까운 서버에 캐싱 사용자와…

-
블루-그린, 롤링, 카나리 배포 비교와 AWS 구현 방법
배포 환경을 개선하면서 무중단 배포의 대표적인 세 가지 방식(블루-그린, 롤링, 카나리)을 비교하고, AWS에서 각각 어떤 서비스로 구현하는지 조사했다. 무중단 배포는 서비스 장애와 배포의 부담을 최소화하기 위해 운영 중인 서비스를 중단하지 않고 신규 소프트웨어를 배포하는 기술

-
EC2 배포 환경을 이해하려고 정리한 PM2 클러스터 모드
입사 초기 프론트엔드 서비스 배포 환경이 EC2와 PM2로 구축되어 있었다. PM2에 대해 공부하며 리서치한 내용이다. PM2는 Process Manager의 약자로 NodeJS 프로세서를 관리하는, 원활한 서버 운영을 위한 패키지 서비스를 제공하고 있는 도중 갑자기 서버가…

-
React 공식 문서로 정리한 Server Component의 장점
React 공식 문서의 Server Components 문서를 번역하며 핵심을 정리하고, 서버 컴포넌트를 써야 하는 이유를 다른 관점의 글과 함께 정리했다. 서버 컴포넌트(Server Components)는 새로운 유형의 컴포넌트로, 번들링 전에 미리 렌더링되며, 클라이언트…

-
GSAP Tween과 Timeline 사용법 정리
웹 애니메이션 라이브러리 GSAP의 기본 개념인 Tween과 Timeline, 그리고 애니메이션 순서를 정하는 position parameter 사용법을 정리했다. 프론트엔드 개발자와 디자이너들이 쉽게 사용할 수 있는 아주 강력한 타임라인 기반의 애니메이션 자바스크립트 라이브러리이다.

-
ES6부터 ES2023까지 버전별 추가 기능 정리
ES6(2015)부터 ES2023까지, 버전별로 추가된 주요 기능을 정리했다. ECMAScript(ECMA-262) 는 Javascript 명세 또는 스펙을 의미한다. ECMA-262 : ECMA인터내셔널(표준기구)은 ECMAScript 언어의 공식 사양인 ECMA-262 표준을…
-
웹 표준, 크로스 브라우징, 웹 접근성 정리
웹 표준은 어떤 환경에서도 이용할 수 있는 웹페이지를,웹 접근성은 어떤 사람이든 이용할 수 있는 웹페이지를 만들 수 있는 방법을 담고 있다. W3C(World Wide Web Consortium)에서 권고하는 웹에서 표준적으로 사용되는 기술이나 규칙 사용자가 어떠한 운영체제나…
-
모듈 번들러가 필요한 이유와 Webpack의 번들링 방식
JavaScript 프레임워크인 React, Vue, Svelte, Angular 등을 사용하다 보면 모듈 번들러(module bundler)는 필수적으로 언급되는 내용이다. 모듈 번들러는 JavaScript 모듈을 브라우저에서 실행할 수 있는 단일 JavaScript 파일로 묶는…

-
Promise와 async/await 사용법 정리
지난 글에서 다룬 비동기 처리를 코드로 다루는 방법인 Promise와 async/await를 정리했다. 자바스크립트 Promise 객체는 비동기 작업의 최종 완료 또는 실패를 나타내는 독자적인 객체이다. 비동기 작업이 끝날 때까지 결과를 기다리는 것이 아니라, 결과를 제공하겠다는…
-
호출 스택과 이벤트 루프로 본 자바스크립트 실행 순서
자바스크립트는 싱글 스레드인데도 비동기 작업을 처리할 수 있다. 그 비밀은 호출 스택과 이벤트 루프에 있다. 자바스크립트 런타임 환경의 구성 요소와 이벤트 루프가 작업을 처리하는 순서를 정리했다. Call stack과 Event loop는 자바스크립트의 동작 원리를 이해하기 위해…

-
싱글 스레드 자바스크립트가 비동기를 처리하는 방법
자바스크립트는 싱글 스레드 언어이기 때문에 한 번에 하나의 작업만 수행할 수 있다. 이전 작업이 완료되어야 다음 작업을 수행할 수 있다. 이러한 코드 순차 실행을 동기(Synchronous)라고 한다. 그러나 작업이 오래 걸리거나 응답이 늦어지는 경우에 전체적인 성능에 영향을 줄…
