인프런 워밍업 0기 3주차 배포

인프런 워밍업 0기 3주차 배포

인프런 워밍업 0기 3주차 배포

강의 수강

목차

1. JPA와 연관관계

2. 배포를 위한 준비

3. AWS와 EC2 배포

4. 스프링 부트 설정과 버전 이해하기

5. 기타

요약

JPA와 연관관계

JPA는 객체와 테이블을 매핑해주는 ORM으로 테이블끼리 가진 관계를 애노테이션으로 매핑할 수 있습니다.

다대일, 일대일, 일대다와 사용하지 않은 다대다까지 지원하고 있습니다.

연관관계라는건 테이블의 FK키를 어디서 관리하는 지에 따라 옵션 값이 달라집니다.

FK 키를 가지고 있는 객체를 연관관계 주인이라고 합니다.

배포를 위한 준비

우리가 만든 애플리케이션을 다른 사람들이 사용할 수 있도록 하려면

1. 다른 사람을 내 컴퓨터를 사용하도록 한다.

2. 공용 컴퓨터를 만들고 다른 사람들이 접속할 수 있도록 한다.

1번은 많은 사람들이 사용할 수 없고 24시간 동안 동작할 수 없습니다.

2번처럼 다른 사람들이 접속할 수 있도록 개발된 컴퓨터에 우리가 만든 애플리케이션을 설치하고 다른 사용자가 사용할 수 있도록 설정하는 방식을 사용합니다.

리눅스 운영체제는 여러 사용자가 동시에 접속해서 사용할 수 있도록 발전했기 때문에 해당 운영체제를 컴퓨터에 설치합니다.

현재 우리가 사용하는 MySQL, Spring, Java를 리눅스 컴퓨터에 설치해야합니다.

그러면 컴퓨터를 구매하고, 방화벽을 설정하고, ssh 인증에 대한 고민도 해야합니다.

이 과정을 클라우드 컴퓨팅 기술로 물리적인 컴퓨터를 구매하지 않고 서버 컴퓨터를 사용할 수 있습니다.

서버 컴퓨터를 구매한 뒤, 리눅스를 설치하고, MySQL을 설치하고, Java를 설치하여 내부에서 스프링 부트가 동작할 수 있도록합니다.

AWS와 EC2 배포

저는 AWS가 정책이 변할 때마다 혹시 모르는 돈을 지불할 수 있는 경험을 했기 때문에

GCP(구글 클라우드 플랫폼)을 사용했습니다.

GCP에서 VM Instance를 구매하고, 포트를 열고 , ssh키를 GUI로 등록하여 접속하는 방식을 선택했습니다.

SpringBoot 설정,버전 업 이해하기

스프링 부트 설정은 build.gradle 파일에 작성된 스크립트를 통해서 필요한 설정을 작성할 수 있습니다.

작성되는 언어는 JVM기반의 스크립트 언어인 groovyKotlin을 사용할 수 있는데 현재는 Kotlin도 공식 언어로 채택되었다는 걸 본적이 있습니다.

스크립트에 사용할 플러그인, 의존성, 그리고 작성되는 순서에 따라 실행될 로직을 작성할 수 있습니다.

스프링 부트 버전이 2.x --> 3.x로 올라가면서 JDK 17이 최소 사양으로 변경되었고, 자세한건 공식 스프링 부트 릴리스 항목에서 확인할 수 있습니다.

버전업을 할 경우 build.gradle에서 플러그인 버전을 변경하고, 컴파일 버전도 변경합니다. 그리고 인텔리제이를 사용할 경우

인텔리제이의 컴파일 버전,모듈버전 등 SDK의 버전도 변경해야합니다.

이때 마이그레이션을 할 때 미리 변경된 내용을 찾아주는 라이브러리를 사용할 수 있습니다.

runtimeOnly "org.springframework.boot:spring-boot-properties-migrator" 

를 추가하여 확인할 수 있습니다.

회고

이번 3주차는 스프링 부트에 서비스를 제공하기 위한 준비 단계에 대해 이해를 할 수 있던 한주 였습니다.

동료 직원들과 배포를 위해서 jenkinsdocker등을 스터디하면서 배포를 하는 다양한 기술을 학습을 했지만,

원초적인 배포를 왜 해야하는지를 궁금해하지 않고, 무작정 배포를 해야하는데 어떤 기술이 있고, 요즘 기술은 이걸 사용한다니까

스터디를 해서 배워보자라는 생각이 강했습니다.

강사님께서 말씀하신 내용중에 기억나는 건, 우리 컴퓨터를 다른 사람들에게 보여줄수 없고 24시간 동안 제공할 수 없으니

다른 컴퓨터에 우리가 만든걸 설치해서 제공하는 과정을 배포라고 한다.

이 말이 기억납니다.

추상적으로 배포라는게 뭔지는 알고 있지만, 구체적으로 배포에 대해서 정리를 하니 명확하게 어떤 의미인지 와닿았습니다.

이번 주에 배운 배포에 대해서 생각을 하고 배포를 하면서 지난번에 스터디를 통해 학습한 jenkkinsAnskble,`Docker`등을 실제로 사용해보면서

킅라우드 서버에 배포하는걸 천천히 해보려고 합니다.

미션

3주차는 미션이 없었기 때문에 미션에 대한 해결 과정을 작성해보려고 합니다.

2단계 미션인 출근 퇴근을 저장하는 방식을 처음에는 직원의 ID가 출근 API를 통해서 들어올 경우

데이터를 삽입하고, 퇴근 API를 통해서 들어올 경우 퇴근 데이터 데이터를 삽입하는 방식으로

코드를 작성했습니다.

테이블 데이터 구조는 자동 id,`직원 고유번호`,`찍은시간`,`현재 상태(출근,퇴근)` 필드를 가지고 있습니다.

이렇게 작성한 이유는 출근 퇴근만 기록하면 된다는 생각이였습니다.

로직은 간단하게 출근할 경우

 

1. 해당 아이디로 등록된 직원이 있는지 조회

- 없는 경우 예외 발생

2. 등록된 직원 정보로 출퇴근 기록지 테이블에 INSERT(직원아이디,LocalDateTime.now(),'ATTEND')

퇴근할 경우

 

1. 해당 아이디로 출퇴근 기록지에 직원아이디 조회

- 없는 경우 예외 발생

2. 있는 경우 출퇴근 기록지에 테이블에 INSERT(직원아이디,LocalDateTime.now(),'LEAVE') 실행

 

이렇게 작성하다보니 문제가 발생했습니다.

1. 출퇴근 기록을 통해서 일한 시간을 가져올 때

2. 휴일에 일한 경우, 추가 근무한 경우에는 어떻게 처리할 것인지

3. 출근을 동시에 2번 찍었을 경우

4. 퇴근을 안찍고 다음날에 출근을 찍은 경우 등

이렇게 테이블을 구조화하니 데이터를 읽어올 때, 저장할 때, 동시성이 발생할 때, 기타 요구사항이 발생할 때 모든 걸 대처할 수 없는

데이터 구조가 되었습니다.

해결 과정

한달간 모든 직원의 근무일 마다 근무 시간을 조회해야한다고 한다면

{

  "직원 id": {

   "detail": [

     {

       "date": "2024-01-01",

       "workingMinutes": 480

     },

     {

       "date": "2024-01-02",

       "workingMinutes": 490

     }

   ],

  "sum": 10560

  }

}

이런 구조로 응답값을 줘야한다고 할때 2가지 고민이 생겼습니다.

1. workingMinutes를 필드로 저장하는게 아니라 출근 시간,퇴근 시간을 조회후 애플리케이션에서 계산을 한다.

2. workingMinutes를 퇴근할 때 출근과 퇴근시간을 계산해서 필드를 추가해서 저장한다.

저는 2번을 선택했습니다.

그 이유는

첫번째는 매번 변경되는 값인 경우 (예: 장바구니 총 금액) 에는 매번 달라지기 때문에 필드에 굳이 저장할 필요가 없지만,

출퇴근 기록은 직원이 임의로 수정할 수 없도록 설계가 되어야하고, 수정을 원할 경우 출퇴근 담당자에게 별도로 요청을 해야 수정이 가능해야하기 때문에

workingMinutes필드는 한번 데이터가 입력되면 매번 수정되는 값이 아닙니다.

두번째는 만약 이 애플리케이션이 몇십몇이 아니라 몇백명 몇천명의 몇년치 데이터를 가져와야하는 경우, 설치된 서버가 사양이 낮아서 소화를 못하는 경우도 있을 거라 생각했습니다.

그래서 미리 테이블에 저장해놓는다면 이런 연산 과정이 생략이 될 수 있기 때문에 필드로 추가하는게 맞다고 생각합니다.

출근,퇴근을 별도의 ROW로 관리하지 않고 하나의 ROW로 관리하기로 변경했습니다.

1. 출근은 오늘하고, 퇴근을 새벽에 할 경우 조회하려면 조건이 까다로워집니다.

2. 출퇴근 기록지에서 하루에 대한 정보를 읽어온다면 퇴근(새벽),출근(아침),퇴근(저녁)으로 조회가 될테고 연산이 복잡해집니다.

그래서 데이터 구조를 다음과 같이 변경했습니다.

출퇴근 기록지:

id,`직원 id`,`오늘 날짜`,`출근 시간`,`퇴근 시간`,`등록일`,`수정일`,`등록한 위치`,`등록한 사람`,`수정한 사람`

 

회고

처음에 시간이 없다보니, 빠르게 구현을 해야한다는 생각에 추가 요구사항이나 엣지 케이스에 대한 염두를 하지 않고

데이터 구조를 설계했습니다.

테스트 코드를 작성하다가 이렇게 구조를 작성하면 테스트 하기도 어렵고, 수정하기도 어렵다는 걸 느꼈습니다.

결국은 요구사항은 데이터를 저장하는게 목적이 아니라 급여를 주기 위해서 데이터를 저장하는 게 목적인 기능이였습니다.

정규화도 좋고, 객체지향적인 것도 좋지만, 결국은 유지보수와 기능을 제공하기 위해 어떻게 데이터를 구조화하여 저장할지 고민을 하게 하는

문제였던거 같고 덕분에 데이터 구조를 처음에 잘못짜면 답이 없다는걸 느꼈습니다.

오히려 처음 작성하는게 더 빠르더라구요

국비교육을 받을때 강사님이 했던 말도 기억납니다. 테이블 설계는 정말 오래 고민하고 설계해야한다는 말씀이 기억납니다.

몸소 깨달은 한주가 되었습니다..

댓글을 작성해보세요.