Projects/OpenRoadmaps

[OpenRoadmaps] 2. 프로젝트 구조 설계 및 환경 설정

DevJaewoo 2022. 11. 28. 10:12
반응형

Backend

Spring Boot

다른 프레임워크들도 있지만 그동안 Spring을 공부해왔고, 시간이 별로 없기 때문에 가장 익숙한 프레임워크로 선택했다.

프로젝트는 Intellij에서 제공해주는 제너레이터를 통해 생성했다.

Gradle 설정은 다음과 같다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // Spring Data JPA
    implementation 'org.springframework.boot:spring-boot-starter-data-redis' // Redis
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' // OAuth2
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation' // Request DTO Validation
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.session:spring-session-data-redis' // Redis Session
    implementation 'com.h2database:h2' // Test Memory DB
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'org.postgresql:postgresql' // PostgreSQL Driver
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'io.rest-assured:rest-assured' // Acceptance Test
    testImplementation 'org.mockito:mockito-core' // Service Unit Test

    //querydsl
    implementation "com.querydsl:querydsl-jpa:5.0.0"
    annotationProcessor "com.querydsl:querydsl-apt:5.0.0"
}
  • spring-boot-starter-data-jpa: Spring Data JPA 사용
  • spring-boot-starter-data-redis / spring-session-data-redis: 세션을 Redis에서 관리하기 위해 사용
  • spring-boot-starter-oauth-client: 
  • spring-boot-starter-validation: @Size, @Notnull 등 Request를 검증하기 위해 사용
  • postgresql: PostgreSQL DB와 연결하기 위해 사용 / H2: 테스트용 In-Memory DB를 위해 사용
  • mockito: @Mock Object를 통해 의존성이 있는 컴포넌트를 단위테스트 하기 위해 사용
  • rest-assured: GET / POST / PUT 등 실제 Request와 그에 따른 Response를 검증하기 위해 사용

Database

오픈소스라 라이센스 문제가 전혀 없고, 많은 기능을 지원하는 PostgreSQL을 사용하기로 결정했다.

OS에 직접 설치하지 않고 Docker 컨테이너로 띄워서 사용했다.

docker run --name postgres -itd -e POSTGRES_PASSWORD=비밀번호 -p 5432:5432 postgres

Redis

PostgreSQL과 마찬가지로 Docker 컨테이너로 띄워서 사용했다.

docker run --name redis -itd -p 6379:6379 redis

 

 

[Spring Boot] Spring Data Redis 사용해보기

Spring Data Redis 사용해보기 Github나 다른 블로그를 돌아다니며 남들이 진행한 프로젝트를 보다 보면 백엔드 구조에 Redis란 것을 자주 볼 수 있다. 주로 캐시 데이터나 세션을 저장하는 용도로 사용

devjaewoo.tistory.com


폴더 구조

여태껏 해온 프로젝트들은 계층형으로 작성했지만, 프로젝트가 진행될 수록 한 패키지에 클래스가 너무 많아지고, 관리도 힘들어져서 도메인형 구조로 작성했다.

도메인이 1~3개정도로 적고, 추가될 일이 없다면 계층형이 좋겠지만 앞으로 계속 추가될 가능성이 있는 경우 도메인형이 관리하기 쉬울 것 같았다.

 

DTO 구조

DTO는 Class가 아닌 Record로 만들었다. 그 이유는 아래 글에 따로 정리해놨다.

 

[비교] DTO Class vs Record

DTO Class vs Record 기존에 Java 11만 쓰다가 이번 프로젝트에서 Java 17을 처음 써보는데, 클래스 생성 중 Record라는 메뉴가 생겨서 찾아보니 DTO로 쓰기 딱이라는 생각이 들었다. Record는 Java 16에서 정식

devjaewoo.tistory.com

 

또한 각 DTO는 파일로 분리하지 않고, 관련있는 DTO 클래스의 inner 클래스로 만들었다.

한 클래스의 코드 길이가 훨씬 많아지지만, 결국 비슷한 역할을 하는 DTO끼리 묶이는 것이기 때문에 오히려 관리하는 것이 쉬울 것이라 생각했다.


Frontend

React

아직 익숙하진 않지만, 사용해본게 React밖에 없어서 선택했다.

Typescript와 함께 create-react-app으로 프로젝트를 만들어 사용했다.

npx create-react-app frontend --template typescript

 

Typescript

처음 사용해보지만 기존 자바스크립트에 Type을 명시하는 것과 interface가 추가된것 말고는 딱히 어려운게 없어서 새로운 문법을 배우는 것에 대한 시간 소모보다 Type 명시로 인한 안정성이 높아지는게 더 가치있다고 판단하여 사용했다.

 

eslint

코드 작성 시 좋지 않은 패턴들을 피하기 위해 사용했다.

기본 설정이 아닌 다른 분이 공유해준 설정으로 사용했다.

{
  "extends": [
    "airbnb",
    "airbnb/hooks",
    "react-app",
    "plugin:react/recommended",
    "plugin:prettier/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "env": {
    "browser": true,
    "jasmine": true,
    "jest": true
  },
  "settings": {
    "import/extensions": [".js", ".jsx", ".ts", ".tsx"],
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      },
      "typescript": {
        "project": "."
      }
    }
  },
  "rules": {
    "arrow-body-style": "off",
    "semi": ["warn", "always"],
    "react/display-name": "off",
    "react/jsx-one-expression-per-line": "off",
    "react/jsx-filename-extension": [
      "error",
      { "extensions": [".js", ".jsx", ".ts", ".tsx"] }
    ],
    "react/jsx-props-no-spreading": "off",
    "react/require-default-props": "off",
    "react/jsx-wrap-multilines": "off",
    "react/react-in-jsx-scope": "off",
    "react/destructuring-assignment": "error",
    "react/prop-types": "off",
    "react/function-component-definition": [
      2,
      { "namedComponents": "arrow-function" }
    ],
    "import/prefer-default-export": "off",
    "import/no-anonymous-default-export": "off",
    "import/no-extraneous-dependencies": [
      "error",
      {
        "devDependencies": ["**/*.stories.*", "**/.storybook/**/*.*"],
        "peerDependencies": true
      }
    ],
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "js": "never",
        "jsx": "never",
        "ts": "never",
        "tsx": "never"
      }
    ],
    "no-param-reassign": ["error", { "props": false }],
    "no-unused-expressions": ["warn"],
    "no-shadow": "off",
    "@typescript-eslint/no-shadow": ["error"],
    "@typescript-eslint/camelcase": "off",
    "@typescript-eslint/no-unused-vars": [
      "warn",
      { "argsIgnorePattern": "^_" }
    ],
    "prefer-destructuring": ["error", { "object": false, "array": false }],
    "lines-between-class-members": "off",
    "jsx-a11y/click-events-have-key-events": "off",
    "jsx-a11y/label-has-associated-control": [
      "error",
      {
        "labelComponents": ["label"],
        "labelAttributes": ["htmlFor"],
        "controlComponents": ["input"]
      }
    ]
  },
  "parserOptions": {
    "project": "./tsconfig.json"
  }
}

 

TailwindCSS

StyledComponent, Emotion 등 다양한 CSS-in-JS 모듈이 있지만, 사용하기 간편하고 별도의 변수나 클래스 선언 없이 Component의 className만으로 스타일을 지정하는 것이 편리하다 생각하여 사용했다.

 

프로젝트 설정은 아래의 사이트를 참고했다.

 

Install Tailwind CSS with Create React App - Tailwind CSS

Setting up Tailwind CSS in a Create React App project.

tailwindcss.com

Mantine

UI 라이브러리로 Mantine을 사용했다.

React 기반 컴포넌트 라이브러리고, Tailwind를 적용하기 쉽다.

또한 다양한 Hook도 지원해줘서 Mantine을 사용했다.

 

Proxy

개발 환경에선 Spring 서버 (localhost:8080) 와 React 로컬 서버 (localhost:3000) 의 주소가 다르다.

때문에 3000번 포트로 접속한 사용자는 8080포트로 API 요청을 보내야 하는데, 이 때 둘의 URI가 다르기 때문에 CORS 오류가 발생한다.

 

사용자가 직접 Spring 서버로 요청하는 것이 아닌 3000번 포트를 경유해 요청할 수 있도록 Proxy를 설정해야 한다.

npm install http-proxy-middleware

 

setupProxy.js

Typescript를 사용하지만 proxy는 js로 해줘야 인식된다.

const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = (app) => {
  app.use(
    "/api",
    createProxyMiddleware({
      target: "http://localhost:8080",
      changeOrigin: true,
    })
  );
};

Github

프로젝트는 여러 환경에서 개발하고, Github Actions를 통한 CI/CD가 가능하도록 Github에 업로드했다.

https://github.com/DevJaewoo/OpenRoadmaps

 

GitHub - DevJaewoo/OpenRoadmaps

Contribute to DevJaewoo/OpenRoadmaps development by creating an account on GitHub.

github.com

 

반응형