본문 바로가기

프로젝트/온라인 서점

온라인 서점 #1 - 프로젝트 기획과 초기 설계

프로젝트 개요
  • 프로젝트명 : BookStore(가제)
  • 배경 : 주문, 결제를 넘어서서 다양한 이벤트 및 커뮤니티 등 책과 관련된 모든 활동을 한 플랫폼에서 할 수는 없을까?
  • 목표
    • 사용자가 책을 사고, 읽고, 기록하고, 공유하는 모든 경험을 한 곳에서 해결하는 플랫폼 구축
    • 1초 이내 응답을 보장하는 API 설계
    • 확장성과 유지보수를 고려한 도메인 중심의 MSA 구조 설계
  • 기대 효과
    • 서적, 굿즈 유통 수수료 기반 수익
    • 프리미엄 구독 모델
기술 스택
  • Java(17) & Spring(3.5.0)
    • 레거시, 생태계 : 검증된 산업 표준, 방대한 라이브러리
    • 생산성 : Spring Boot로 초기 설정 최소화
  • Gradle
    • 성능 : 병렬 빌드 및 캐싱으로 빠름
    • 가독성 : 읽기 쉽고 표현력이 뛰어남
  • MySQL
    • 비용 : 커뮤니티 에디션은 무료
    • 생태계 : MySQL Workbench, Spring Data JPA 네이티브 지원
    • 커뮤니티 : 레퍼런스 매뉴얼 많음
  • JPA
    • 생산성 : 클래스-테이블 매핑으로 코드 감소
    • 성능 : 지연 로딩, 페치 조인, 캐싱 등 자동 최적화 기법 제공
  • Git & Github
    • 분산형 모델 : 로컬에서 독립적으로 버전 관리, 브랜치 전략 사용
    • 생태계 : Github 액션,CI 통합, PR 리뷰 등 다양한 도구 제공

 

초기 설계

 

프로젝트 전체 구조 예시

bookstore/                          # 루트 프로젝트
├── catalog/			# 도서 관련 기능
│   └── src/main/java/com/bookstore/catalog/
│       ├── CatalogApplication.java
│       ├── web/                    # REST 컨트롤러
│       ├── service/                # 비즈니스 로직
│       ├── domain/                 # JPA 엔티티 & Repository
│       ├── dto/                    # 요청/응답용 DTO
│       ├── config/                 # 설정 (Swagger, Mapper 등)
│       └── exception/              # 예외 처리
│   └── src/test/java/com/bookstore/catalog/
│       ├── CatalogApplicationTests.java
│       ├── web/                    # REST 컨트롤러 테스트
│       ├── service/                # 비즈니스 로직 테스트
│       └── domain/                 # JPA 엔티티 & Repository 테스트
│   └── build.gradle
├── order/                  # 주문 및 결제 기능
│   └── src/main/java/com/bookstore/order/
│       ├── OrderApplication.java
│       ├── web/
│       ├── service/
│       ├── domain/
│       ├── dto/
│       ├── config/
│       └── exception/
│   └── src/test/java/com/bookstore/order/
│       ├── OrderApplicationTests.java
│       ├── web/
│       ├── service/
│       └── domain/
│   └── build.gradle
└── README.md

 

프로젝트 생성

 

https://start.spring.io/

Spring Initializr 사이트를 이용하면 쉽게 프로젝트를 생성할 수 있습니다

각 항목과 의존성의 의미는 다음과 같습니다

 

  • Project : 프로젝트의 빌드 툴 선택
  • Language : 사용할 언어 선택
  • Spring Boot : 사용할 스프링 부트의 버전 선택
  • Group : 메이븐 저장소에서 사용하는 프로젝트의 그룹 ID
  • Aratifact : 메이븐 저장소에서 사용하는 아티팩트 ID
  • Name : 프로젝트의 이름
  • Description : 프로젝트 설명
  • Package name : 프로젝트의 기본 자바 패키지
  • Packaging : 프로젝트 패키징 방식 선택
  • Java : 사용할 Java 버전 선택 
  • Dependecies : 프로젝트에 포함할 의존 모듈/라이브러리
    • Spring Web : REST API 개발 및 웹 어플리케이션 제작에 필요한 기본 의존성

 

모든 항목을 입력했으면 GENERATE 버튼을 클릭해 프로젝트를 생성합니다

 

프로젝트 확인

 

빌드 설정(build.gradle)

 

빌드 설정의 각 의미는 주석 부분을 참고하세요

plugins {
	id 'java' // 그래들에 자바 지원을 제공
	id 'org.springframework.boot' version '3.5.0' // 그래들에서 사용하는 스프링 부트 버전
	id 'io.spring.dependency-management' version '1.1.7' // 그래들에서 사용하는 스프링에 대한 의존성 관리 기능 버전
}

group = 'com.bookstore' // 프로젝트의 그룹 ID
version = '0.0.1-SNAPSHOT' // 애플리케이션의 버전

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(17) // 사용하는 자바 버전
	}
}

repositories { // 의존 라이브러리를 검색할 아티팩트 저장소
	mavenCentral() 
}

dependencies { // 애플리케이션에 사용될 의존 라이브러리
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	runtimeOnly 'com.mysql:mysql-connector-j'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
	useJUnitPlatform() // JUnit5가 제공하는 JUnit 플랫폼으로 테스트하도록 설정
}

 

프로젝트의 이름은 settings.gradle 폴더에서 다음과 같이 확인할 수 있습니다

rootProject.name = 'catalog'

 

애플리케이션 부트스트래핑

 

JAR로 패킹징된 자바 애플리케이션은 실행할 public static void main(String[] args) 메서드가 있어야하고 시작할 때 실행됩니다

catalog-service에는 프로젝트 생성 시 자동으로 만들어진 CatalogServiceApplication 클래스가 있고 이 안에 main()메서드를 정의해 스프링 부트 애플리케이션을 실행합니다

 

package com.bookstore.catalog;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CatalogApplication {

	public static void main(String[] args) {
		SpringApplication.run(CatalogApplication.class, args);
	}

}

 

@SpringBootApplication 애너테이션은 세 가지 애너테이션의 기능을 포함합니다

  • @Configuration : 해당 클래스는 빈을 정의하는 클래스
  • @ComponentScan : 컴포넌트 검색을 통해 빈을 찾아 스프링 콘텍스트에 자동으로 등록
  • @EnableAutoConfiguration : 스프링 부트에서 제공하는 자동 설정 기능 활성화 

애플리케이션 테스트

package com.bookstore.catalog;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class CatalogApplicationTests {

	@Test
	void contextLoads() {
	}

}

 

@SpringBootTest는 스프링 부트 애플리케이션 전체를 통합적으로 테스트하기 위해 설정을 자동으로 구성해주는 애너테이션으로 세 가지 기능을 포함합니다

  • 실제 애플리케이션을 실행할 때와 동일하게 ApplicationContext 로드
  • 테스트용 내장 웹 환경 구성
  • @SpringBootApplication이 선언된 클래스 기준 전체 컴포넌트 스캔

catalog(루트 폴더)로 이동한 다음 gradle 테스트 작업을 수행합니다

./gradlew test

 

테스트가 통과하는 것을 통해 스프링 콘텍스트가 올바르게 로드됨을 확인할 수 있습니다

 

간단한 API 구현

 

프로젝트 구조에 따라서 web 패키지를 만들고 그 안에 HomeController를 만듭니다

package com.bookstore.catalog.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {

    @GetMapping("/")
    public String getGreeting() {
        return "BookStore에 오신 것을 환영합니다!";
    }
}

 

 

@RestController 애너테이션은  두 가지 애너테이션의 기능을 포함하는 REST API 전용 컨트롤러 선언 역할을 합니다

  • @Controller : 해당 클래스가 컨트롤러임을 선언
  • @ResponseBody : 클래스 내 모든 메서드가 자동으로 JSON 또는 XML 등 HTTP 응답 바디로 반환

@GetMapping은 GET 요청이 특정 URL로 들어왔을 때 해당 메서드를 실행합니다

 

이제 구현한 API가 정상적으로 작동되는지 확인해봅시다

catalog(루트 폴더)로 이동한 다음 애플리케이션을 실행하고 http://localhost:8080/에 접속하여 환영 메세지를 확인해 봅시다

./gradlew bootRun

 

 

Git, Github 설정

 

로컬 Git 초기화

루트 폴더에서 git을 초기화 합니다 .git 폴더가 생성됐으면 Git 이력 추적이 시작되었음을 의미합니다

git init

 

.gitignore 설정

루트 폴더에서 .gitignore 파일을 생성합니다

touch .gitignore

 

비밀번호, 키 등 노출되면 안되는 내용이 커밋되지 않도록 예외 처리를 합니다

gitignore.io 사이트에 운영체제, 사용 언어 등을 입력하면 그에 맞는 gitignore 내용을 편하게 작성할 수 있습니다

Windows, Java, Intellij, Gradle을 입력 후 생성된 내용을 작성해 줍시다

추가적으로 환경파일인 .env, application-*.yml도 작성해 줍니다

https://www.toptal.com/developers/gitignore

 

gitignore.io

Create useful .gitignore files for your project

www.toptal.com

 

### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn.  Uncomment if using
# auto-import.
.idea/artifacts
.idea/compiler.xml
.idea/jarRepositories.xml
.idea/modules.xml
.idea/*.iml
.idea/modules
*.iml
*.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# SonarLint plugin
.idea/sonarlint/

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

*.iml
modules.xml
.idea/misc.xml
*.ipr

# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/

# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml

# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/

# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$

# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml

# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
.idea/**/azureSettings.xml

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

### Gradle ###
.gradle
**/build/
!src/**/build/

# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties

# Cache of project
.gradletasknamecache

# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath

### Gradle Patch ###
# Java heap dump
*.hprof

# 환경파일
.env
application-*.yml

 

커밋 컨벤션

첫 커밋을 하기 전에 커밋 컨벤션을 먼저 정해줍니다

태그: 제목(본문, 꼬릿말 생략) => ex) feat: 도서 목록 조회 API 구현

태그 의미
feat 기능 추가
fix 버그 수정
docs 문서 관련
test 테스트 관련
refactor 리팩토링
chore 설정 파일, 빌드 등 부수적 변경

 

이제 첫 커밋을 해줍니다 첫 커밋 태그만 예외적으로 init을 사용하겠습니다

git add .
git commit -m "init: 프로젝트 구조 및 기본 설정 완료"

 

GitHub 저장소 생성 및 연결

Github에 bookstore 저장소를 생성한 후 로컬 프로젝트와 연결하고 push해 줍니다

git remote add origin https://github.com/사용자명/bookstore.git //원격 저장소와 로컬을 연결
git branch -M main // 기본 브랜치 이름 main으로 변경
git pull origin main --rebase // 원격 저장소 내용 로컬에 반영
git push -u origin main // 원격 저장소에 로컬 내용 푸시

 

브랜치 전략 수립

대표적인 브랜치 전략으로는 Git Flow와 Github Flow가 있습니다

현재 프로젝트는 다양한 버전, 테스트 서버 등을 사용하지 않으므로 단순하고 지속적인 배포에 강점이 있는 Github Flow를 사용하겠습니다

  • main : 배포용
  • feature : 기능 개발
트러블 슈팅

 

Gradle 프로젝트로 인식하지 못하는 문제

build.gradle 파일 -> 마우스 우클릭 -> Link Gradle Project를 클릭하여 gradle 프로젝트로 인식하게 하여 해결