[항해 99] 6주차 WIL(Weekly, I Learned)

gimseonjin616·2022년 7월 31일
0

프로젝트 후기

목록 보기
9/9

주차 : 6주차

기간 : 2022.07.23 ~ 2022.07.29

활동 내용 : 미니프로젝트 - Front와의 첫 협업


Chapter 1. 미니프로젝트 가즈아!!!

드디어 미니프로젝트 날이 밝았다.

내가 항해99를 신청한 이유 중 하나는 졸업하고 나서 취준 중에도 프로젝트 감을 잃고 싶지 않은 것이다.

약 1년 만에 협업 프로젝트였고 진짜 기대됐다.


Chapter 2. 나의 프로젝트 목표

이번 주차의 내 목표는 아래와 같다.

1. 어떻게 하면 프로젝트를 잘 관리할 수 있을까?
2. 어떻게 하면 내 프로젝트를 잘 보여줄 수 있을까?

언뜻보면 팀장의 고민인 거 같지만 난 팀장이 아니였다.

하지만 지금이 않으면 차후의 클론 프로젝트, 실전 프로젝트 전에 정리할 시간이 없을 듯 했다.

그래서 팀장님 및 팀원 분들께 양해를 구하고 노션 관리와 github 관리를 했다.


Chapter 3. 노션으로 프로젝트 관리하기!!

우선 프로젝트 전체 일정 및 테스크를 정리해야 했다.

최근 가장 각광받는 프로젝트 관리 기법이 에자일이다.

애자일은 짧은주기의 개발단위를 반복하여 하나의 큰 프로젝트를 완성해 나가는 방식으로 짧은 미니프로젝트에 도입하기 좋다고 판단했다.

그래서 일정을 관리할 수 있는 달력과 애자일 방식으로 태스크를 처리할 수 있는 보드를 만들었다.

일정표

Task Board

그리고 각 기술 파트별로 컨벤션, 또는 자료를 공유할 수 있는 프로그래밍 탭을 만들어서 사용하였다.
뿐만 아니라 결과물이나 트러블 슈팅, 관련 자료를 관리할 수 있는 탭도 만들어서 사용했다.

프로그래밍 탭

프로젝트 관리 탭

그리고 팀원 소개 탭을 만들어서 소속된 팀원의 정보를 공유하여 비상 연락망을 구축하였다.


Chapter 4. github readme로 우리 프로젝트 소개하기!!

git에는 readme라는 파일이 존재한다.

이 readme는 md라는 언어를 사용하여 repository를 사용하기 위해서 필요한 것, 방법, 또 기타 등등을 기술한 문서다.

Github에서는 이 readme file을 통해 repository를 이쁘게 꾸미고 설명할 수 있다.

따라서 나는 readme.md 파일을 통해 우리 프로젝트를 이쁘게 소개하고 싶었다.

Project Main Page

프로젝트 메인 소개 페이지에선 프로젝트 시연 영상, Skill Set, Project Structure, 그리고 어떻게 실행하는 지에 대해 기술하였다.


🌟 항해99 6주차 1조 프로젝트 - JMT 🌟

Introduce

Video Label

Skil Set

FrontBackDatabaseInfra
ReactSpring bootMySQLAWS

Project Structure

Untitled

How to use

1. Backend Repository의 readme에 따라 서버를 실행합니다.

2. Frontend Repository의 readme에 따라 서버 url을 입력하고 실행합니다.

3. Happy Enjoy!!    

Backend Page

Frontend Page는 프론트엔드 분들꺼라서 생략하고 Backend readme를 아래와 같이 꾸몄다.

ERD, Table design & create SQL, Folder Structure, Dependency & How To Run에 대해 설명하였다.


JMT backend

Data Structure

ERD Diagram

sql


테이블

image
CREATE TABLE IF NOT EXISTS `user` (
  `user_id` BIGINT NOT NULL AUTO_INCREMENT,
  `authority_list` TINYBLOB NULL DEFAULT NULL,
  `email` VARCHAR(255) NULL DEFAULT NULL,
  `enabled` BIT(1) NOT NULL,
  `name` VARCHAR(255) NULL DEFAULT NULL,
  `password` VARCHAR(255) NULL DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE INDEX `UK_ob8kqyqqgmefl0aco34akdtpe` (`email` ASC) VISIBLE)
ENGINE = InnoDB
image
CREATE TABLE IF NOT EXISTS `restaurant` (
  `restaurant_id` VARCHAR(255) NOT NULL,
  `address` VARCHAR(255) NULL DEFAULT NULL,
  `category` VARCHAR(255) NULL DEFAULT NULL,
  `description` VARCHAR(255) NULL DEFAULT NULL,
  `like_count` BIGINT NULL DEFAULT NULL,
  `map_x` VARCHAR(255) NULL DEFAULT NULL,
  `map_y` VARCHAR(255) NULL DEFAULT NULL,
  `name` VARCHAR(255) NULL DEFAULT NULL,
  `phone` VARCHAR(255) NULL DEFAULT NULL,
  `thumbnail` VARCHAR(255) NULL DEFAULT NULL,
  `url` VARCHAR(255) NULL DEFAULT NULL,
  PRIMARY KEY (`restaurant_id`))
ENGINE = InnoDB
image
CREATE TABLE IF NOT EXISTS `review` (
  `review_id` BIGINT NOT NULL AUTO_INCREMENT,
  `text` VARCHAR(255) NULL DEFAULT NULL,
  `restaurant_id` VARCHAR(255) NOT NULL,
  `user_id` BIGINT NOT NULL,
  PRIMARY KEY (`review_id`),
  INDEX `FK70ry7cuti298yxet366rynxch` (`restaurant_id` ASC) VISIBLE,
  INDEX `FKiyf57dy48lyiftdrf7y87rnxi` (`user_id` ASC) VISIBLE,
  CONSTRAINT `FK70ry7cuti298yxet366rynxch`
    FOREIGN KEY (`restaurant_id`)
    REFERENCES `test2`.`restaurant` (`restaurant_id`),
  CONSTRAINT `FKiyf57dy48lyiftdrf7y87rnxi`
    FOREIGN KEY (`user_id`)
    REFERENCES `test2`.`user` (`user_id`))
ENGINE = InnoDB
image
CREATE TABLE IF NOT EXISTS `likes` (
  `like_id` BIGINT NOT NULL AUTO_INCREMENT,
  `restaurant_id` VARCHAR(255) NOT NULL,
  `user_id` BIGINT NOT NULL,
  PRIMARY KEY (`like_id`),
  UNIQUE INDEX `UniqueRestaurantUser` (`restaurant_id` ASC, `user_id` ASC) VISIBLE,
  INDEX `FKi2wo4dyk4rok7v4kak8sgkwx0` (`user_id` ASC) VISIBLE,
  CONSTRAINT `FKi2wo4dyk4rok7v4kak8sgkwx0`
    FOREIGN KEY (`user_id`)
    REFERENCES `test2`.`user` (`user_id`),
  CONSTRAINT `FKmamcxnitc6oyoxjdr7dwbac8x`
    FOREIGN KEY (`restaurant_id`)
    REFERENCES `test2`.`restaurant` (`restaurant_id`))
ENGINE = InnoDB

Folder Structure

.
├── V1Application.java
├── config
│   ├── exception
│   │   ├── ErrorResponse.java
│   │   ├── MethodArgumentNotValidExceptionHandler.java
│   │   └── RuntimeExceptionHandler.java
│   ├── logging
│   │   ├── LogAspect.java
│   │   ├── LoggingFilter.java
│   │   ├── LoggingInterceptor.java
│   │   └── annotation
│   │       └── LogExecutionTime.java
│   ├── security
│   │   ├── JWTCheckFilter.java
│   │   ├── JWTLoginFilter.java
│   │   ├── JWTUtil.java
│   │   ├── PasswordEncoder.java
│   │   └── SecurityConfig.java
│   └── web
│       └── WebConfig.java
├── layer
│   ├── like
│   │   ├── controller
│   │   │   └── LikeController.java
│   │   ├── domain
│   │   │   ├── Likes.java
│   │   │   └── dto
│   │   │       ├── request
│   │   │       │   └── LikeAddRequestDto.java
│   │   │       └── response
│   │   │           ├── LikeAddResponseDto.java
│   │   │           └── LikeResponseDto.java
│   │   ├── infra
│   │   │   └── LikeRepository.java
│   │   └── service
│   │       └── LikeService.java
│   ├── restaurant
│   │   ├── controller
│   │   │   └── RestaurantController.java
│   │   ├── domain
│   │   │   ├── Restaurant.java
│   │   │   └── dto
│   │   │       └── response
│   │   │           ├── RestaurantRankingResponseDto.java
│   │   │           └── RestaurantSearchResponseDto.java
│   │   ├── infra
│   │   │   └── RestaurantRepository.java
│   │   └── service
│   │       └── RestaurantService.java
│   ├── review
│   │   ├── controller
│   │   │   └── ReviewController.java
│   │   ├── domain
│   │   │   ├── Review.java
│   │   │   └── dto
│   │   │       ├── request
│   │   │       │   └── ReviewRequestDto.java
│   │   │       └── response
│   │   │           ├── MyReviewResponseDto.java
│   │   │           └── ReviewResponseDto.java
│   │   ├── infra
│   │   │   └── ReviewRepository.java
│   │   └── service
│   │       └── ReviewService.java
│   └── user
│       ├── controller
│       │   └── UserController.java
│       ├── domain
│       │   ├── User.java
│       │   └── dto
│       │       ├── request
│       │       │   ├── SigninRequestDto.java
│       │       │   └── SignupRequestDto.java
│       │       └── response
│       │           ├── GetUserDataResponseDto.java
│       │           └── SigninResponseDto.java
│       ├── infra
│       │   └── UserRepository.java
│       └── service
│           └── UserService.java
└── util
    ├── SearchLocal
    │   ├── SearchLocalClient.java
    │   └── domain
    │       └── dto
    │           ├── SearchLocalRequestDto.java
    │           └── SearchLocalResponseDto.java
    └── naver
        ├── NaverClient.java
        └── domain
            └── dto
                ├── SearchImageRequestDto.java
                ├── SearchImageResponseDto.java
                ├── SearchLocalRequestDto.java
                └── SearchLocalResponseDto.java

https://elderly-gruyere-ed2.notion.site/85abe3c68b49444f9e432a086fd30b13?v=98d2bb286be943418e7a46467b0e4f0a

How to run

Properties

# MYSQL 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://mysql-link/serverTimezone=UTC&characterEncoding=UTF-8
spring.datasource.username= root
spring.datasource.password= password
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update

# 네이버 API 설정
naver.url.search.local=https://openapi.naver.com/v1/search/local.json
naver.url.search.image=https://openapi.naver.com/v1/search/image
naver.client.id= id
naver.client.secret= key

# 카카오 API 설정
kakao.url.search.local=https://dapi.kakao.com/v2/local/search/keyword.json
kakao.restapi.key= key

# Spring Security 설정
spring.security.filter.order=10

# Spring Admin 설정
server.port=8080
spring.boot.admin.url= admin url
spring.boot.admin.client.url= admin url
spring.boot.admin.client.username=admin
spring.boot.admin.client.password=admin
spring.boot.admin.client.instance.metadata.user.name=admin
spring.boot.admin.client.instance.metadata.user.password=admin
spring.boot.admin.client.instance.service-url= client url
spring.security.user.name=admin
spring.security.user.password=admin
management.endpoints.web.exposure.include=*
management.endpoints.health.show-details=always

# Sentry 설정
sentry.dsn=https://c110b598b1f042f19e0fc6c027d0e4b5@o1336019.ingest.sentry.io/6604408
# Set traces-sample-rate to 1.0 to capture 100% of transactions for performance monitoring.
# We recommend adjusting this value in production.
sentry.traces-sample-rate=1.0

Requirement

Spring boot : 2.6.1
Java JDK : 11

Build & Run

$ ./gradlew bootjar
$ java -jar 프로젝트명.jar

자세한 내용은 아래 깃허브 링크를 통해 확인할 수 있다.

https://github.com/hanghae99-JMT


Chapter 5. 첫 협업을 하며 느낀 점

졸업하고 나서 첫 협업 프로젝트였고 제한 시간 내에 우리가 목표로 한 기능을 모두 구현했다. 그리고 발표자료도 만들었고 성공적인 발표도 했다. 이번 주차 시작하기 전에 세운 목표를 달성한 거 같다.

하지만 조금은 아쉬운 점이 남았다. 우선 배포 자동화를 구축하지 못한 것이다. 물론 1주일 프로젝트고 상용 서비스가 아니지만 할 수 있고, 하면 좋은 것인데 안한 건 조금 아쉽다.

그리고 모니터링 환경을 구축했는데 제대로 활용하지 못했다. 이번 배포 환경은 Sentry & Spring boot admin을 사용했다. Sentry는 이전에 한번 사용해봤고 Spring boot admin은 처음 사용해봤다. Spring boot admin은 내부 메모리 사용량과 Thread 상태를 직접 볼 수 있어서 매우 만족했으나 Sentry는 별로 만족스럽지 못했다. 따라서 다음에는 ELk Stack으로 로그 모니터링 서버를 따로 구축해볼 것이다.

마지막으로 부하 분산을 구축하지 못했다. 최종 시연 직전에 로직을 잘못 핸들링해서 서버에 초당 100회의 요청이 갔다. 그러니 서버가 터졌다. 즉 서버가 초당 100 thoughtput을 견디지 못한 것이다. 이는 매우 약한 것이다. 아무래도 Spring boot admin에서 상태를 가져가기 위해 요청하는 것과 동시에 처리하기엔 무리였던 거 같다. 따라서 다음에는 Load balancing을 해야겠다.

profile
to be data engineer

0개의 댓글