[프로젝트 고도화 3편] 로컬을 넘어 클라우드로: 이미지 호스팅부터 도커 배포까지
·
Study
1. 들어가며 공지사항과 이벤트 게시판을 만들며 프로젝트의 내실을 다진 후, 이번에는 로컬 환경에서 벗어나 실제 웹 서비스로 배포하는 작업을 진행했다. 내 컴퓨터에서만 돌아가는 서비스는 온전한 웹 서비스라 할 수 없기 때문이다. 단순히 서버에 코드를 올리는 것을 넘어, 이미지 호스팅 마이그레이션, 클라우드 DB 이전, 도커(Docker) 기반 배포까지 적용하며 겪었던 문제들과 해결 과정을 정리해 본다.2. 로컬 저장소의 한계와 Cloudinary 도입기존에는 서버의 물리적 폴더(C드라이브 등)에 이미지를 저장했다. 하지만 Render, Vercel 같은 클라우드 배포 환경에서는 서버가 재시작될 때마다 내부 파일이 초기화되는 문제가 있다. 이를 해결하기 위해 이미지 호스팅 서비스인 Cloudinary를 도..
[프로젝트 고도화 2편] 이벤트 게시판 구축과 쿠키를 활용한 조회수 어뷰징 방지
·
Study
1. 들어가며 지난 포스팅에서 공지사항 게시판과 에디터를 도입하며 마무리 글로 다음 목표 네 가지를 세웠었다. 이번에는 그 목표들 중 첫 번째와 두 번째였던 이벤트 게시판 구축과 조회수 어뷰징 방지 로직을 구현한 과정을 정리해 본다. 추가로, 프론트엔드 개발자라면 놓칠 수 없는 사용자 경험(UX) 개선을 위해 스켈레톤 UI까지 도입해 보았다. 프로젝트가 점점 장난감이 아닌 실제 서비스의 형태를 갖춰가는 과정이 꽤나 흥미롭다.2. 이벤트 게시판 구축: 투박한 HTML 달력은 그만 공지사항 게시판의 뼈대를 재활용해 이벤트 게시판을 만드는 것 자체는 수월했다. 하지만 이벤트 게시판만의 핵심 속성인 대표 썸네일과 이벤트 기간(시작일/종료일)을 입력받는 화면을 만들면서 UI/UX적인 고민에 빠졌다. 처음에는 HT..
[프로젝트 고도화] API 주소 환경변수 분리부터 에디터 도입, 공지사항 게시판 구현까지
·
Study
1. 들어가며 팀 프로젝트로 진행했던 쇼핑몰 배포가 끝난 후, 아쉬웠던 부분들을 고도화해보고 싶어서 로컬로 환경을 옮겨 대대적인 리팩토링과 신규 기능 추가를 시작했다. 특히 관리자나 사용자가 글을 쓸 때 텍스트만 입력되는 게 답답해서 React-Quill 에디터를 도입하고 공지사항 게시판을 새롭게 만들어봤는데, 그 과정에서 고민과 해결 과정을 개발 기록으로 남겨본다.2. API 주소 하드코딩 제거 및 환경변수 적용 처음 코드를 열어보고 가장 먼저 부딪힌 문제는 수많은 파일에 배포 서버의 IP 주소가 하드코딩되어 있다는 점이었다. "이거 나중에 서버나 포트 바뀌면 다 찾아다니면서 고쳐야 하는데?"라는 생각이 번쩍 들었다. 이런 비효율적인 구조를 해결하기 위해 프론트엔드 최상단에 .env 파일을 만들어서 ..
[Week 3] 쇼핑몰 백엔드 테스트 완성: Controller 계층 API 검증과 MockMvc 도입기
·
Study
1주차의 순수 비즈니스 로직(Service) 검증, 2주차의 H2를 활용한 진짜 DB(Repository) 검증에 이어 드디어 3주차다. 이번 주의 핵심 과제는 클라이언트의 요청을 최전선에서 받아내는 Controller 계층 API 테스트다. 웹 브라우저나 모바일 앱에서 들어오는 HTTP 요청이 내가 만든 로직을 거쳐 알맞은 JSON 응답으로 잘 변환되는지 두 눈으로 확인해 보고 싶었다.웹 계층만 날카롭게 잘라내기: @WebMvcTest와의 만남 실제 서버를 띄우고 Postman 같은 툴로 일일이 요청을 보내며 테스트할 수도 있지만, 매번 전체 애플리케이션을 실행하는 것은 너무 무겁고 비효율적이다. Controller가 HTTP 요청과 응답을 잘 처리하는지만 빠르고 독립적으로 검증하기 위해 새로운 도구들..
[Week 2] 쇼핑몰 백엔드 테스트: Repository 계층 검증과 H2 DB 도입기
·
Study
1주차에서는 가짜 객체(Mock)를 방패 삼아 외부 요인에 흔들리지 않는 순수 비즈니스 로직(Service)을 검증했다. 그렇다면 2주차의 핵심 과제는 무엇일까? 바로 내가 짠 쿼리가 DB에서 데이터를 정확하게 가져오는가?를 확인하는 Repository 계층 테스트다.단순한 저장/조회를 넘어 통계를 위한 커스텀 쿼리, 다중 조건이 걸린 동적 쿼리(Specification)까지 제대로 작동하는지 두 눈으로 확인해 보고 싶었다.무거운 Oracle 대신 가벼운 H2로: @DataJpaTest와의 만남 실제 운영 환경이나 로컬 개발 시에는 무거운 Oracle DB를 사용한다. 하지만 테스트 코드를 돌릴 때마다 네트워크를 타고 Oracle에 데이터를 썼다 지우는 것은 너무 느리고, 다른 데이터와 충돌할 위험도 있..
[Week 1] 쇼핑몰 백엔드 테스트 시작: 계층형 카테고리와 Mockito 단위 테스트
·
Study
부트캠프에서 진행했었던 팀 프로젝트인 ShoppingMall-Coco의 테스트를 진행해보고 싶어 개발을 진행해 보았다. 첫 주차의 핵심 과제는 쇼핑몰의 기틀이 되는 카테고리와 상품 도메인의 핵심 비즈니스 로직을 구현하고, 이를 꼼꼼하게 테스트하는 것이었다. 가장 먼저 다룬 것은 카테고리 도메인. 쇼핑몰 특성상 카테고리는 [스킨케어 > 토너/스킨] 처럼 부모-자식 관계를 가지는 계층형 구조(Hierarchical Structure)로 설계되어야 했다. 이를 구현하기 위해 하나의 엔티티가 자기 자신을 참조(parentCategory)하도록 설계했고, 부모가 없는 최상위 카테고리와 부모를 가지는 하위 카테고리 생성 로직을 분리하여 구현했다.테스트 코드는 나의 방패: Mockito와의 만남 비즈니스 로직 구현만..
[Spring Boot] Mockito를 활용한 단위 테스트 작성기
·
Study
팀 프로젝트에서 포트폴리오용 레포지토리 분리를 무사히 마치고, 본격적으로 비즈니스 로직 검증을 위한 단위 테스트(Unit Test)를 작성하기 시작했다. 첫 번째 타겟은 쇼핑몰의 뼈대가 되는 CategoryService의 카테고리 생성 로직이다. 실제 DB까지 연동하는 통합 테스트를 진행할 수도 있지만, 이번에는 Service 계층의 로직이 순수하게 잘 동작하는가를 빠르고 독립적으로 검증하기 위해 Mockito 프레임워크를 도입했다.1. 왜 진짜 DB 대신 가짜(Mock) 객체를 쓸까?단위 테스트의 핵심은 외부 환경으로부터의 의존성 분리다. Service 클래스는 Repository를 통해 DB와 통신하는데, DB의 상태나 네트워크 문제로 인해 테스트가 실패한다면 온전한 Service 로직의 검증이라고 ..
[Java] 문자열과 배열의 길이 구하기: length와 length()의 차이
·
Study/코딩테스트
프로그래머스의 편지 문제를 풀었다. 할머니께 드릴 편지지의 가로 길이를 구하는 단순한 문제였다. 글자 하나당 2cm이므로, 메시지의 전체 길이에 2를 곱하면 되는 간단한 로직이다. 하지만 코드를 작성하던 중 익숙하면서도 낯선 에러를 마주했다. 자바에서 길이를 구하는 방식이 데이터 타입에 따라 다르다는 점을 간과했기 때문이다.1. 문제의 원인내가 처음에 작성했던 코드는 다음과 같았다.// 오류가 발생했던 코드for(int i=0; i 여기서 발생한 문제는 message.length였다. 자바에서 String 객체의 길이를 가져오려면 필드가 아닌 메서드를 호출해야 한다. 즉, length가 아니라 length()를 써야 한다. 또한, 전체 길이에 2를 곱하는 단순한 연산이므로 굳이 반복문을 사용할 필요도 없..