블로그

이용수

[인프런 워밍업 클럽 1기] BE 3주차 발자국

[인프런 워밍업 클럽 1기] BE 3주차 발자국서론벌써 강의를 들은지 3주차가 지나간다. 강의와 스터디를 하면서 배운 내용을 잊지 않도록 주마다 블로그에 정리하려고 한다.섹션 5 : 책 요구사항 구현하기조금 더 객체지향적으로 개발할 수 없을까?BookService에서 User와 UserLoanHistory를 연결시켜 대출 기능과 반납 기능을 개선할 수 있다.User와 UserLoanHistory가 서로를 알도록 코드를 수정한다.연관 관계 설정@ManyToOne : (대출 기록) N : (대출 기록 소유자) 1 일 때 사용한다.@OneToMany : (대출 기록 소유자) 1 : (대출 기록) N 일 때 사용한다.연관 관계의 주인 설정하기 mappedBy = 주인 필드 이름 : 연관 관계의 주인의 값이 설정되어야만 진정한 데이터가 저장된다.JPA 연관관계에 대한 추가적인 기능들Person과 Address에서 1:1 관게 일시 @OneToOne을 사용한다.연관 관계의 주인이 아닌 쪽에 mappedBy를 사용하여 주인을 설정한다.연관 관계의 주인 효과 : 객체가 연결되는 기준이 된다.상대 테이블을 참고하고 있으면 연관관계의 주인연관관계의 주인이 아니면 mappedBy를 사용연관관계의 주인의 setter가 사용되어야만 테이블 연결연관관계 사용시 주의해야 할 점@Transactionnal public void savePerson(){ Person person = personRepository.save(new Person()); Address address = addressRepository.save(new Address()); person.setAddress(address); System.out.println(address.getPerson()); // null이 됨. } 위 코드에서 아직 트랜잭션이 끝나지 않아, 객체 끼리는 한쪽만 연결된 상태, 반대 쪽을 알 수 없어 null 반환하게 된다.setter를 한 번에 둘을 같이 이어주도록 처리하면 된다.즉, 양쪽 모두 연관관계를 가지고 있을 때는 양쪽 모두 한번에 맺어주는게 좋다.@Transactionnal public void savePerson(){ Person person = personRepository.save(new Person()); Address address = addressRepository.save(new Address()); person.setAddress(address); address.getPerson(); } ... public void setAddress(Address address){ this.address = address; this.address.setPerson(this); } ... public Person getPerson(){ return this.person; } User와 UserLoanHistory 관계에선 @ManyToOne, @OneToMany를 사용한다.@ManyToOne은 단방향으로만 사용할 수도 있다.@JoinColumn : 연관관계의 주인이 활용할 수 있는 어노테이션으로 필드의 이름이나 null 여부, 유일성 여부, 업데이트 여부 등을 지정한다.@ManyToMany는 구조가 복잡하고, 테이블이 직관적으로 매핑되지 않아 사용을 추천하지 않는다.cascade 옵션 : 저장이나 삭제를 할 때 연관관계에 놓인 테이블까지 함께 저장 또는 삭제해준다.orphanRemoval 옵션 : 연관관계가 끊어진 데이터를 자동으로 제거해준다.책 대출/반납 기능 리팩토링과 지연 로딩대출 기능 리팩토링 public void loanBook(String bookName){ this.userLoanHistories.add(new UserLoanHistory(this, bookName)); } 반납 기능 리팩토링 public void returnBook(String bookName){ UserLoanHistory targetHistory = this.userLoanHistories.stream() .filter(history -> history.getBookName().equals(bookName)) .findFirst() .orElseThrow(IllegalArgumentException::new); targetHistory.doReturn(); } User를 가져오는 부분과, 도메인 로직 실행 중간에 출력문을 넣어보면, @Transactional public void returnBook(BookReturnRequest request){ // 유저 정보를 가져온다 User user = userRepository.findByName(request.getUserName()) .orElseThrow(IllegalArgumentException::new); System.out.println("Hello"); user.returnBook(request.getBookName()); } User를 가져오고, Hello 가 출력되고, UserLoanHistory를 가져온다.즉, 영속성 컨텍스트는 지연 로딩이 가능하며, 지연 로딩을 사용하게 되면, 연결되어 있는 객체를 꼭 필요한 순간에만 가져올 수 있다.연관관계 사용의 장점각자의 역할에 집중하게 된다.새로운 개발자가 코드를 읽을 때 이해하기 쉬워진다.테스트 코드 작성이 쉬워진다.연관관계 사용의 단점지나친 사용시, 성능상의 문제가 발생할 수 있다.도메인 간의 복잡한 연결로 인해 시스템 파악이 어려워질 수 있다.복잡한 연결로, 하나의 수정이 연관된 다른 요소에 영향을 미칠 수 있다.즉, 비즈니스 요구사항, 기술적인 요구사항, 도메인 아키텍처 등 여러 부분을 고민해서 연관관계 사용을 선택해야 한다.Section 5 정리.책 생성, 대출 반납 API를 온전히 개발하며 지금까지 다루었던 모든 개념을 실습해 봤다.객체지향적으로 설계하기 위한 연관관계를 이해하고, 연관관계의 다양한 옵션에 대해 이해했다.JPA에서 연관관계를 매핑하기 위한 방법을 이해하고, 연관관계를 사용해 개발할 때와 사용하지 않고 개발할 때의 차이점을 이해했다.섹션 6 : 생애 최초 배포 준비하기배포란 무엇인가?배포 : 최종 사용자에게 SW를 전달하는 과정. 즉, 전용 컴퓨터에 우리의 서버를 옮겨 실행시키는 것profile과 H2 DBprofile : 똑같은 서버 코드를 실행시키지만, 실행될 때 설정을 다르게 하고 싶을 때 사용한다.profile 적용, profile로 local을 입력시, H2 DB를 사용하게 하고, dev를 입력시, MySQL DB를 사용하도록 설정하기.H2 DB : 경량 Database, 개발 단계에서 많이 사용하며 디스크가 아닌 메모리에 데이터를 저장할 수 있다. (휘발성이라 개발 단계에서만 사용한다.)H2 DB 사용시 ddl-auto 옵션을 create로 사용하면 테이블을 신경쓰지 않고 코드에만 집중할 수 있다.application.ymlspring: config: activate: on-profile: local datasource: url: "jdbc:h2:mem:library;MODE=MYSQL;NON_KEYWORDS=USER" username: "sa" password: //패스워드 driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create properties: hibernate: show_sql: true format_sql: true dialect: org.hibernate.dialect.H2Dialect h2: console: enabled: true path: /h2-console --- spring: config: activate: on-profile: dev datasource: url: "jdbc:mysql://localhost/library" username: "root" password: //패스 워드 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: none properties: hibernate: show_sql: true format_sql: true dialect: org.hibernate.dialect.MySQL8Dialect H2-Console로 로컬에서 링크에 접속하면로컬에서 데이터베이스를 확인할 수 있다.git과 github이란 무엇인가?git : 코드를 쉽게 관리할 수 있도록 해주는 버전 관리 프로그램github : git으로 관리되는 프로젝트의 코드가 저장되는 저장소github에 코드를 저장하는 이유.코드 소실 방지을 위해배포 할 떄 활용 가능 하다.git 기초 사용법git repository 주소 :강의 초반부터 intellij에서 git을 연결하여 사용 중이였다.git add.git commit -m "커밋 메시지"git pushAWS의 EC2 사용하기Section 6 정리.배포가 무엇인지 이해하고, 배포를 하기 위해 어떤 준비를 해야하는지 알아 봤다.스프링 서버를 실행할 때 DB와 같은 설정들을 코드 변경 없이 제어할 수 있는 방법을 알아봤다.git과 github의 차이를 이해하고 git에 대한 기초적인 사용법을 알아봤다.AWS의 EC2가 무엇인지 이해하고, AWS를 통해 클라우드 컴퓨터를 빌려봤다.섹션 7 : 생애 최초 배포하기EC2에 접속해 리눅스 명령어 다뤄보기다운로드 받은 키 페어를 이용하는 방법접속하려는 EC2의 IP주소다운로드 받았던 키 페어접속하기 위한 프로그램 (git CLI)ssh -i 경로/키페어이름.pem ec2-user@IPEC2컴퓨터가 많아 졌을 경우 간편하게 접근 가능하다.AWS 콘솔을 활용하는 방법AWS 화면에서 인스턴스에 연결에서 연결하면 된다.복잡한 명령어를 작성할 필요가 없다.가장 기본적인 리눅스 명령어mkdir folder1 : folder1 폴더 생성cd folder1 : folder1 폴더로 이동pwd : 현재 경로 출력cd.. : 상위 폴더로 이동ls 또는 ls -l : 현재 위치의 폴더 및 파일 목록 출력rmdir folder1 : folder1 폴더 제거배포를 위한 프로그램 설치하기설치해야 할 프로그램 목록git : 코드를 가져오기 위함java : 서버를 구동mysql : 데이터베이스 역할설치 과정sudo yum update sudo yum install git -y ALTER user'root'@'localhost' IDENTIFIED WITH mysql_native_password BY "패스워드"; 설정 후 profile에서도 변경해주어야 한다.git으로 원격 저장소를 최신화 해주면 완료.빌드와 실행, 그리고 접속종료되지 않는 실행가비아를 이용한 도메인 구입, DNS 적용Section 7 정리.EC2에 접속하는 방법을 알아보고, EC2에 접속해 리눅스 명령어를 다뤄봤다.개발한 서버의 배포를 위해 환경 설정을 리눅스에서 진행하고, 실제 배포를 진행해봤다.foreground와 background의 차이를 이해하고 background 서버를 제어해봤다.도메인 이름을 사용해 사용자가 IP대신 이름으로 접속할 수 있도록 했다.섹션 8 : Spring Boot의 이모저모build.gradle 이해하기build.gradle : 빌드 스크립트라고도 불리며, gradle을 이용해 프로젝트를 빌드하고 의존성을 관리하기 위해 작성되었으며, groovy언어를 사용해 작성되었고, kotlin언어를 사용할 수도 있다.plugins 블락 : 다양한 플러그인을 적용하도록 작성할 수 있다.org.springframework.boot 플러그인 역할스프링을 빌드했을때 실행가능한 jar파일이 나오도록 도와준다.스프링 애플리케이션을 실행할 수 있게 도와준다.다른 플러그인들이 잘 적용되도록 도와준다.io.spring.dependency-management외부 라이브러리, 프레임워크의 버전관리에 도움을 주고 서로 얽혀 있는 의존성을 처리하는데 도와준다.javajava 프로젝트를 개발하는데 필요한 기능들을 추가해주고, 다른 JVM언어 Gradle 플러그인을 사용할 수 있는 기반을 마련한다.group : 프로젝트의 그룹version : 프로젝트의 버전sourceCompatibility : 프로젝트가 사용하고 있는 JDK 버전repositories 블락 : 외부 라이브러리/프레임워크를 가져오는 장소 결정dependencies 블락 : 사용하는 라이브러리/프레임워크를 표시하는 곳tests : 테스트 수행시 사용하는 버전 명시.Spring과 Spring BootSpring과 Spring Boot의 차이점간편한 설정간단한 의존성 관리강력한 확장성MSA에 적합한 모니터링application.yml과 application.properties, lomboklombok : getter, setter, 생성자와 같은 반복되는 보일러 플레이트 코드를 제거할 수 있다.lombok 의존성 추가IntelliJ lombok 플러그인 추가IntelliJ Annotation Processor 설정Spring Boot 2.7.x에서 3.0.x로 업데이트하기Java 최소 버전이 17로 업그레이드 됨.많은 스프링 프로젝트, Thrid-party Library가 버전업 됨.AOT 기초 작업이 이루어짐.javax대신 jakarta 패키지를 사용하게 됨.모니터링 기능들이 강화 됨. 3주차 과제과제 6번 : https://www.inflearn.com/blogs/79934번 과제의 API를 Controller - Service - Repository로 분리하기.FruitRepository를 FruitMemoryRepository와 FruitMySqlRepository로 분리하고, @Primary 어노테이션을 사용해 두 Repository를 교차하며 동작해보기.과제 7번 : https://www.inflearn.com/blogs/80176번 과제의 기능들을 JPA를 이용하여 동작하도록 변경하기.과일 Entity Class를 이용해 특정 과을을 기준으로 과일 개수를 카운트하는 API 만들기판매되지 않은 특정 금액 이상 또는 특정 금액 이하의 과일 목록을 반환하는 API 만들기3주차 후기지난주 2주차 회고록에 이어서 인프런 워밍업 클럽 과정의 3주차가 마무리됬다. 이번 주차에서는 섹션 5의 일부분 부터 섹션 8까지 강의를 수강할 수 있었다. 간단하게 각 섹션 별로 강의의 주제를 다시 한번 상기하고 어떤걸 배우고 느꼈는지 확인해보려고 한다.섹션 5의 주제 : 책 요구사항 구현하기객체지향적으로 설계하기 위한 연관관계를 이해하고, 연관관계의 다양한 옵션에 대해 이해했다. 또한 JPA에서 연관관계를 매핑하기 위한 방법을 이해하고, 연관관계를 사용해 개발할 때와 사용하지 않고 개발할 때의 차이점을 이해했다.섹션 6의 주제 : 생애 최초 배포 준비하기배포가 무엇인지 이해하고, 배포를 하기 위해 어떤 준비를 해야하는지 알아 봤으며 스프링 서버를 실행할 때 DB와 같은 설정들을 코드 변경 없이 제어할 수 있는 방법을 알아볼 수 있었다. 또한 git과 github의 차이를 이해하고 git에 대한 기초적인 사용법을 알아보고, AWS의 EC2가 무엇인지 이해하고, AWS를 통해 클라우드 컴퓨터를 빌려볼 수 있었다.섹션 7의 주제 : 생애 최초 배포하기EC2에 접속하는 방법을 알아보고, EC2에 접속해 리눅스 명령어를 다뤄봤다. 개발한 서버의 배포를 위해 환경 설정을 리눅스에서 진행하고, 실제 배포를 진행해볼 수 있었다. foreground와 background의 차이를 이해하고 background 서버를 제어해보고, 도메인 이름을 사용해 사용자가 IP대신 이름으로 접속할 수 있도록 했다.섹션 8의 주제 : Spring Boot의 이모저모그동안 진행해온 Spring Boot의 build.gradle과 application.yml 등 다양한 설정 파일의 내부를 확인해볼 수 있었다.2차 중간 점검2차 중간 점검은 질의 응답보단 코드 리뷰를 진행하는 형식으로 진행됬다. 본인은 아직 미니 프로젝트 1번까지 수행하지 못해 직접 피드백을 받지는 못했지만, 고맙게도 올려주신 분들의 코드의 매커니즘 대체로 깔끔해서 작성한 내 코드와 비교해보며 간접적으로 좋은 피드백을 받을 수 있었다.마무리이번 주차는 대체적으로 개발한 코드를 리팩토링 하고 배포하는 부분이 많았다. 특히, 배포하는 부분을 주요 깊게 봤다.처음으로 AWS 계정을 생성해서 배포하는 과정까지 천천히 진행해봤는데, 확실히 금전적으로 사고가 일어날 수 있는 부분이다 보니 강의 자료 외에도 더 알아보고 신중하게 진행했다.이제 미니 프로젝트만 마무리 지으면 벌써 워밍업 클럽의 수료가 눈앞에 다가온다.다음 주차엔 남은 강의도 얼마 없어서 미니 프로젝트에 신경을 많이 쓰게 될것 같다.

백엔드백엔드인프런워밍업

최강현

[인프런 워밍업 스터디 클럽 1기] 백엔드 3주차 발자국

11일차 객체지향과 JPA 연관관계원래 우리가 작성한 코드는 User 와 UserLoanHistory가 서로 관계 없이 BookService를 통해 작동하였는데이제 UserLoanHistroy를 User를 통해 가져오게 변경해서 좀 더 객체지향적으로 변경하였다. 또 연관관계에 대해 학습하였다, 연관관계는 SQL에서 참조하는 관계인 테이블들을 자바에서 연관관계라고 말한다.참조키가 테이블에 있는 테이블이 주인이다.  12일차 기본적인 배포를 위한 준비 기본적인 배포를 위해 AWS 가입과 EC2 인스턴스를 준비했다.그리고 github에 가입 후 여태까지 만든 소스 파일들을 github에 푸쉬하였다. 이를 통해 배포를 위한 기본적인 준비를 끝마쳤다. 13일차 AWS와 EC2 배포 X14일차 Spring Boot 설정, 버전업 이해하기 X 과제6일차https://devnter.tistory.com/entry/%EC%9D%B8%ED%94%84%EB%9F%B0-%EC%9B%8C%EB%B0%8D%EC%97%85-%ED%81%B4%EB%9F%BD-1%EA%B8%B0BE-6%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C 7일차https://devnter.tistory.com/entry/%EC%9D%B8%ED%94%84%EB%9F%B0-%EC%9B%8C%EB%B0%8D%EC%97%85-%ED%81%B4%EB%9F%BD-1%EA%B8%B0BE-7%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C 7일차 과제가 좀 어려웠다 단순히 JPA로 리팩토링하는데도 시간을 많이 투자했고 2번 문제 또한 많은 고민 후 시도했는데 에러가 발생했다.3번 문제는 풀어보지도 못했다. 회고너무 놀기만 했다 마지막 미니 프로젝트는 잘 마무리 해서 제출해보자 제발~ 출처https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%84%9C%EB%B2%84%EA%B0%9C%EB%B0%9C-%EC%98%AC%EC%9D%B8%EC%9B%90/dashboard   

백엔드인프런워밍업클럽

전다윤

[인프런 워밍업 스터디 클럽 1기 BE] 세번째 발자국

Section - 6 생애 최초 배포 준비하기 배포란? 배포최종 사용자에게 SW를 전달하는 과정전용 컴퓨터에 Spring과 MySql 등이 설치되고 코드가 작성된 우리의 서버를 옮겨 실행시키는 것이다.AWS(Amazon Web Service)같은 클라우드 서비스에서 서버를 빌릴 수 있다. Profile똑같은 서버 코드를 실행시키지만 실행 환경에 따라 설정을 다르게 한다. 데이터베이스 설정, 외부 API 키 등...똑같은 서버 코드를 실행시키지만, local 이라는 profile을 입력하면, H2 DB를 사용하고, dev 라는 profile을 입력하면 MySQL DB를 사용하게 한다. H2 DB경량 Database로 개발 단계에서 많이 사용하며 디스크가 아닌 메모리에 데이터를 저장할 수 있다. 데이터가 휘발될 수 있다. 개발 단계에서는 변경이 잦기 때문에 오히려 휘발 되는 것이 장점일 수도 있다.application.yml 수정spring: config: activate: on-profile: local datasource: url: "jdbc:h2:mem:library;MODE=MYSQL;NON_KEYWORDS=USER" username: "sa" password: "" driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create properties: hibernate: show_sql: true format_sql: true dialect: org.hibernate.dialect.H2Dialect h2: console: enabled: true path: /h2-console --- spring: config: activate: on-profile: dev datasource: url: "jdbc:mysql://localhost/library" username: "root" password: 1234 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: none properties: hibernate: show_sql: true format_sql: true dialect: org.hibernate.dialect.MySQL8Dialect git과 github란? git코드를 쉽게 관리할 수 있도록 해주는 버전 관리 프로그램다양한 버전으로 개발된 프로그램들을 손쉽게 합치고 관리해 준다.GitHubgit으로 관리되는 프로젝트의 코드가 저장되는 저장소GitHub에 저장하는 이유내 컴퓨터에 있는 코드는 모종의 이유로 소실 될 수 있다.배포 과정에서 소스 코드를 옮길 때 활용할 수 있다. git 기초 명령어작성한 코드 원격 저장소에 올리기# 해당 프로젝트를 git이 관리하도록 함 git init # github 저장소와 git 프로젝트를 연결 git remote add origin [repository 주소] # 모든 파일을 추가 git add . # 특정 파일/폴더만 추가 git add [파일/폴더 이름] # 현재 add한 상태를 확인 git status # 현재 add된 파일들을 다 제거 git resest # add한 파일을 메시지와 함께 묶는 커밋 git commit -m “메시지” # 커밋한 파일을 github 저장소로 보냄 git push # git push 하는 경우 최초 1회는 반드시 실행해주어야 함 git push --set-upstream origin master.gitignore이 파일 안에 작성된 폴더나 다른 파일들이 git에 의해 추적되거나 관리되는 것을 방지함build/ .gradle/ .idea/ AWS EC2Elastic Compute Cloud탄력적으로 사용할 수 있는 원격 컴퓨터언제든지 필요할 때 빌리고 반납할 수 있다.Section - 7 생애 최초 배포하기 EC2 접속방법다운로드 받은 키 페어(pem key)를 이용하는 방법접속하려는 EC2의 IP 주소다운로드 받은 키 페어 접속하기 위한 프로그램(git CLI or Mac Terminal) 키 페어의 권한을 닫아준다. (보안 처리)chmod 400 경로/키페어명.pem보안 처리가 되어야만 접속이 가능하다. 만약, 처리가 되지 않고 접속을 시도하면 unprotected private key file을 사용하고 있다며 접근 자체가 거부 된다.접근 명령어ssh -i 경로/키페어명.pem ec2-user@IPAWS 콘솔을 활용하는 방법AWS ec2 웹사이트에 접속해서 연결 버튼을 통해 연결한다.기본적인 리눅스 명령어# 폴더를 만드는 명령어 mkdir folder1 # 현재 위치에서 폴더나 파일을 확인하는 명령어 ls # 조금 더 자세한 정보를 확인 ls -l drwxrwxr-x 2 ec2-user ec2-user 6 # d : folder1은 폴더이다. # r : 읽는 권한, w : 쓸 수 있는 권한, x : 실행 권한 # rwx/rwx/r-x # 폴더 소유자의 권한 / 폴더 소유 그룹의 권한/ 아무나 접근했을 때의 권 # 2 : 폴더에 걸려 있는 바로가기 개수 # ec2-user : 폴더 소유주의 이름 # ec2-user : 폴더 소유 그룹의 이름 # 6 : 폴더(파일의 크기) 단위 : byte필요한 프로그램 설치하기코드를 가져오기 위한 git 설치서버를 구동하기 위한 java 설치데이터베이스 역할을 하는 MySQL 설치GitHub에서 코드 가져오기git clone [레포지토리 주소]EC2 Swap 설정Swap 설정 : RAM이 부족할 경우 일부 DISK를 사용하게 해준다.# swqp 메모리 할당 sudo dd if=/dev/zero of=/swapfile bs=128M count=16 # swqp 파일에 대한 권한 업데이트 sudo chmod 600 /swapfile # swap 영역 설정 sudo mkswap /swapfile # swap 파일 사용 설정 sudo swapon /swapfile # swap 성공 확인 sudo swapon -s 빌드하기# gradlew를 사용할 수 있도록 쓰기 권한 설정 chmod +x ./gradlew # gradle을 이용해 테스트를 돌리지 않고 프로젝트 빌드 ./gradlew build -x test서버 실행하기java -jar build/libs/[빌드한 파일명.jar] --spring.profiles.active=dev foreground vs backgroundforeground우리가 보고 있는 프로그램ex) PDF 프로그램이 foreground 프로그램background우리가 보고 있지 않은데 실행 중인 프로그램ex) 컴퓨터에서의 백신 프로그램c2 접속을 종료해도 서버가 종료되지 않도록 하려면 서버를 background로 동작하게 해야 함nohup [명령어] &background 서버 다운ps aux : 현재 실행중인 프로그램 목록을 확인ps aux | grep java : java가 들어가는 프로그램을 확인(각 프로그램의 고유 번호 확인)kill -9 프로그램번호 : 해당 프로그램을 종료 DNS 적용가비아에서 도메인 구매DNS 레코드 수정타입 : A호스트 : www값/위치 : EC2에서 빌린 인스턴스의 퍼블릭 IP 주소 Section - 8 Spring Boot의 이모저모build.gradle빌드 스크립트gradle을 이용해 프로젝트를 빌드하고 의존성을 관리하기 위해 작성plugins : 프로젝트에 적용하고 싶은 플러그인 추가group : 프로젝트의 그룹version : 프로젝트의 버전sourceCompatibility : 프로젝트가 사용하고 있는 JDK 버전repositories : 외부 라이브러리나 프레임워크를 가져오는 장소 설정dependencies : 우리가 사용하는 라이브러리/프레임워크 표시tasks.named('test') : 테스트를 수행할 때 사용할 프레임 워크 Spring Boot의 특징간편한 설정xml 대신 어노테이션 기반의 설정 가능기본적으로 필요한 것을 모두 자동 설정간단한 의존성 관리의존성을 필요한 것끼리 묶어 starter로 관리필요한 라이브러리나 프레임워크 하나 하나 적을 필요 없음강력한 확장성starter 추가만으로 필요한 기술을 도입할 수 있음  application.ymlYAML 문법 사용.yaml 또는 .yml : YAML의 확장자기본적으로 key : value 형식으로 데이터 정의각 계층은 들여쓰기를 통해 구분 (이를 통해 중복 제거)value로 들어갈 수 있는 타입 : 참/거짓, 숫자, 문자열(큰 따옴표 사용)배열은 - 사용#로 주석 표현application.propertiesapplicatoin.yml 대신 사용 가능key : value 형식으로 데이터 기록들여 쓰기를 통해 중복을 제거할 수는 없음application-프로파일 이름.properties 파일을 새로 만들어 profile 설정가독성 떨어짐lombok생성자, getter, setter, equals, toString 등 반복되는 보일러 플레이트 코드(boiler palte code)를 자동으로 생성해줌(반복되는 코드 제거)lombok 도입을 위한 설정lombok 의존성 추가IntelliJ lombok 플러그인 추가intelliJ Annotation Processor 설정과제[과제 #6] API 분리[과제 #7] JPA 적용블로그를 찾아보며 겨우 혼자 배포한 경험이 있었는데 이렇게 다시 배포의 과정을 차근차근 배워볼 수 있어서 좋았다. 완강을 해서 뿌듯했고 앞으로 남은 미니 프로젝트도 잘 마무리할 수 있으면 좋겠다.

백엔드인프런워밍업클럽1기BE

변지섭

[인프런 워밍업 클럽 1기 BE] 세번째 발자국

이번 주도 강의를 많이 듣지는 못했지만, 미니프로젝트 1단계를 개발하고, 중간점검에 참여하면서 많은 것을 느낄 수 있었습니다.강의는 26강부터 30강까지 들었습니다. 학습 내용 요약:26강: Spring Data JPA를 이용해 다양한 쿼리 작성하기25강에서 Spring Data JPA가 무엇인지에 대해 배웠습니다. 복잡한 JPA코드를 스프링과 쉽게 사용할 수 있도록 도와주는 라이브러리였는데요. 26강에서는 실제로 Spring Data JPA를 활용해 다양한 쿼리를 작성해보았습니다.Spring Data JPA의 가장 편리한 점은, 메서드 이름만 작성하면 필요한 SQL을 자동으로 조립해 준다는 점이었습니다.따라서, 메서드 이름을 어떻게 짓는지 규칙을 정확하게 알아야 합니다.find: 1개의 데이터만 가져옵니다.By 뒤에 오는 필드 이름을 기준으로 Where문을 작성합니다.By 앞에 올 수 있는 구절find: 해당 조건을 만족하는 객체 하나를 가져옵니다. 반환 타입은 객체가 될 수도 있고, Optional<타입>이 될 수도 있습니다.Optional 객체는 Java8 이후로 등장한, null을 감싸는 Wrapper 객체로, 값이 없을 수 있는 경우를 표현하기 위해 사용합니다. null로부터 안전성을 보장받을 수 있어 좋지만, 결국 Unboxing하고, Boxing 하는 과정이 오버헤드로 작용할 수 있습니다.따라서 null이 아님이 확실하다면 굳이 사용할 필요가 없습니다.제한된 경우에 null 대신 반환형으로서 사용하도록 설계되었다고 합니다.orElseThrow() 메서드를 사용해, 값이 없는 경우 예외처리를 할 수 있습니다.ex.orElseThrow(IllegalArgumentException::new)reference: https://mangkyu.tistory.com/70조회 연산에서는 값이 없는 경우가 자주 발생할 수 있기 때문에, null을 리턴하도록 하면 에러가 너무 많이 발생할 것입니다. 따라서 Optional<타입> 형태로 값을 리턴하는 것 같습니다. findAll: 쿼리의 결과물이 N개인 경우 사용합니다. List<타입>을 반환합니다.exists: 쿼리 결과가 존재하는지 확인합니다. 반환 타입은 boolean입니다.count: SQL의 결과 개수를 셉니다. 반환 타입은 long입니다.각 구절은 And나 Or로 조합할 수도 있습니다.ex. findAllByPriceLessThanEqualAndSoldBy 뒤에 들어갈 수 있는 구절:GreaterThan: 초과GreaterThanEqual: 이상LessThan: 미만LessThanEqual: 이하Between: 사이에StartsWith: ~로 시작하는EndsWith: ~로 끝나는 SQL을 자동으로 생성해주므로, 매우 편리하지만, 조건이 복잡해질수록 메서드 이름이 길고 복잡해져 조건을 간략하게 쓰는 것이 필요해 보였습니다.27강: 트랜잭션 이론편트랜잭션: 쪼갤 수 없는 업무의 최소 단위(All or Nothing)ex. 쇼핑몰에서 결제 실패가 발생하면, 주문 전체가 취소되는데 이는 트랜잭션으로 묶여있기 때문이다.start transaction(트랜잭션 시작) / commit(반영) / rollback(미반영) 28강: 트랜잭션 적용과 영속성 컨텍스트@Transactional 어노테이션으로 트랜잭션을 적용할 수 있습니다.이때, 조회(SELECT) 쿼리만 사용한다면, readOnly 옵션을 통해 성능을 향상시킬 수 있습니다.readOnly 옵션을 사용하면 dirty-read(트랜잭션 중에, 나중에 시작한 다른 트랜잭션이 먼저 완료되어, 결과가 다르게 보이는 것) 처리를 해줄 필요가 없으므로 성능이 향상되고, 영속성 컨텍스트도 readOnly 객체의 변경을 저장해줄 필요가 없으므로, 부담이 줄어듭니다.태현님께서도, readOnly 옵션을 true로 설정하는 경우, CRUD를 모두 제공하는 DB가 아니라 Read만 가능한 DB에 바로 접근하므로, 성능 향상이 있다고 말씀하셨습니다.하지만, 서비스 레이어에서 무분별하게 readOnly를 사용할 경우 성능이 저하될 수 있다는 실험도 있었습니다.reference: https://medium.com/@jkha7371/is-transactional-readonly-true-a-silver-bullet-1dbf130c97f8위 글에서 다른 흥미로운 내용도 많았는데, readOnly = true 처리를 해주더라도 이는 힌트일 뿐이며, 일부 트랜잭션 매니저는 힌트를 받지 못해 write 작업이 가능하고, 예외도 발생하지 않는다고 합니다. 영속성 컨텍스트의 능력 4가지1. 변경 감지(Dirty Check)영속성 컨텍스트 안에서 불러온 Entity는 명시적으로 save하지 않더라도, 변경을 감지해 자동으로 저장됩니다.ex. 강의에서 update() 메서드의 경우 save() 메서드를 호출하지 않아도 영속성 컨텍스트를 통해 자동으로 저장되었습니다.2. 쓰기 지연INSERT, UPDATE, DELETE를 바로 날리는 것이 아니라, commit될 때 모아서 한 번에 날림 -> DB와 통신 횟수가 줄어듦   DB야 미안해... 상황이 덜 발생할 수 있습니다! 3. 1차 캐싱ID를 기준으로 Entity를 기억하기 때문에, 캐싱된 객체는 완전히 동일합니다.(인스턴스의 주소도 동일)4. 지연 로딩일종의 Lazy Evaluation인 것 같습니다.연관관계가 있는 엔티티를 조회 시 한 번에 가져오는 것이 아니고, 필요 시 가져옴!reference: https://devoong2.tistory.com/entry/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8Persistence-Context%EC%9D%98-5%EA%B0%80%EC%A7%80-%ED%8A%B9%EC%A7%9530강 책 생성 API 개발하기기존에 배운 내용을 바탕으로 Book 객체를 생성하고, 테이블 설계 -> 도메인, 리포지토리 -> 서비스 -> 컨트롤러, DTO를 작성해보았습니다.혼자 작성하는 과정에 테이블 필드 이름과 DTO의 필드 이름이 달라서, Spring Data JPA가 필드를 인식하지 못하는 문제가 있었습니다.왜 책 이름을 255자나 할당하는지 궁금했는데, 문자열을 타이트하게 잡았을 때, 나중에 조건에 변화가 생기면 테이블을 수정해야 하는데, 그게 쉽지가 않다고 하셨습니다.또, @Column의 length가 기본 255자기 때문에, 255로 설정하면, 옵션에서 length 조건을 지울 수 있습니다. ## 스터디에 임하는 자세:다른 일로 바쁠때는 스프링 공부에 소홀해지기도 하는데, 스터디 과제 마감이 있기 때문에 다시 스프링 공부를 하게 됩니다. 또, Domain / Repository / Service / Controller / DTO 로 구분하여 개발하는 과정이 번거로울 때도 있지만, 과제를 해나갈수록 익숙해지고 있습니다. 중간 점검 시간에 태현님께서 코드 리뷰를 해주셨는데, 코드를 그 자리에서 보시면서 어떤 선택지가 있고, 각 선택지의 장단점은 무엇이며, 본인은 어떤 선택지를 선호하고, 그 이유가 무엇인지에 대해 설명해주셨습니다. 사실 너무 잘하셔서 충격이었고, 저게 현직자구나... 저런 사항들을 고려하면서 코드를 작성한다면, AI에 쉽게 대체되지 않겠다는 생각도 함께 들었습니다. 코드 리뷰에 참여하신 찬영님도 정말 열심히 고민해서 코드를 작성해주셨고, 덕분에 깊이 있는 코드리뷰가 되었던 것 같습니다. 요즘 테스트에 관심이 많이 생겼는데, 중간점검 때 알려주신 테스팅 방법을 좀 더 찾아보고, 미니 프로젝트에도 녹여봐야겠습니다.

노은빈

[인프런 워밍업 클럽 스터디]BE 1기 세번째 발자국

어째 계속 변명 회고가 되어가고 있는데 호기롭게 다짐한 것과 달리 공부를 많이 못했다. 지금 이후부터 담주까지 열심히 강의를 들어 완주하는 것에 만족하려고 한다. ㅜㅜ 아직도 10일차에 머물러 있지만 금방 완주할 수 있을거다!! Section4섹션4에서는 JPA를 다루는 방법에 대해 배운다. 문자열 SQL을 직접 사용하는 것의 한계문자열을 작성하기 때문에 실수할 수 있고, 실수를 인지하는 시점이 느림 // 유저 조회 public List<UserResponse> getUsers() { String sql = "SELECT * FROM user"; return jdbcTemplate.query(sql, (rs, rowNum) -> { long id = rs.getLong("id"); String name = rs.getString("name"); int age = rs.getInt("age"); return new UserResponse(id, name, age); }); } String sql = "SELECT * FROM user"; 이 부분에 실행이 되지 않아도 빨간줄이 안 뜸⇒ 오류가 컴파일 시점에 발견되 지 않고, 런타임 시점에 발견됨 ( 컴파일 : 서버를 실행할때 자바 코드를 .class 코드로 변화시켜서 jvm에서 동작시켜야하는 과정) ( 런타임 : 실제 서버가 가동된 이후)특정 데이터베이스에 종석적이게 됨다른 db로 바꾸려면 전체를 바꿔야 하는 어려움반복 작업이 많아짐, 테이블을 하나 만들 때마다 CRUD 쿼리가 항상 필요데이터베이스의 테이블과 객체는 패러다임이 다름부모 클래스와 하위 클래스들을 구분짓기 어려움JPA란?Java Persistence API ( 자바 영속성 API ) ⇒ 자바 진영의 ORM(Object - Relational Mapping)Java Persistence API ( 자바 영속성 API )영속성 : 서버가 재시작되어도 데이터는 영구적으로 저장되는 속성API : 정해진 규칙⇒ 데이터를 영구적으로 보관하기 위해 자바 진영에서 정해진 규칙 ORM(Object - Relational Mapping)Object : 객체Relational : 관계형 db⇒ 관계형 db의 테이블Mapping : 객체랑 테이블을 연결 즉, JPA란 ?객체와 관계형 db의 테이블을 짝지어 데이터를 영구적으로 보관하기 위해 Java 진영에서 정해진 규칙말로 되어있는 규칙을 코드로 표현 → HibernateHibernate(구현체) → 구현(implement) → JPA ⇒ 즉, JPA는 interface(규칙)이고, Hibernate는 그것을 구현하는 구현체며 JDBC를 사용한다. 다음 강의에서는 User 객체에 엔티티를 넣는 방법을 배운다.사실 객체에 @Entity 를 적어주면 된다.@Entity public class User { @Id // id라는 걸 알리기 위해 => primary @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; @Column(nullable = false, length = 20) // name(varchar) = 20 private String name; private Integer age; }@Entity : 스프링이 User객체와 user 테이블을 같은 것으로 바라봄entity의 의미 ⇒ 데이터베이스에서 저장되고, 관리되어야 하는 데이터 id에 auto_increment 가 있으므로@GeneratedValue(strategy = GenerationType.*IDENTITY*) 로 자동 생성되는 값임을 명시@id : 이 필드를 primary key로 간주함@GeneratedValue : primary key는 자동 생성되는 값임 @Column : 객체의 필드와 Table의 필드를 매핑함null이 들어갈 수 있는지의 여부, 길이 제한, db에서의 column 이름 등등이 들어감 매핑은 끝 → JPA를 사용하니 추가적인 설정을 해주어야 함application.yml jpa: # hibernate: ddl-auto: none # 우리 프로젝트는 테이블과 객체가 잘 연결되었기 때문에 필요 X properties: hibernate: show_sql: true # JPA를 사용해 db에 Sql을 날릴 때 Sql을 보여줄지에 관한 것 format_sql: true # sql을 보여줄 때 예쁘게 포맷할 것인지 dialect: org.hibernate.dialect.MySQL8Dialect # 이 옵션으로 db를 특정하면 조금씩 다른 Sql을 수정 Spring에 jpa-hobernate-ddl-auto라는 옵션이 있는데 이 옵션은 스프링이 시작할때 디비에 있는 테이블을 어떻게 처리할지에 관함→ 테이블이랑 객체랑 다름(매핑을 잘못함)일 때 어떻게 할지에 대한 옵션ddl-auto: create : 기존 테이블이 있다면 삭제 후 다시 생성ddl-auto: create-drop : 스프링이 종료될 때 매핑됐던 테이블 모두 제거ddl-auto: update : 객체와 테이블이 다른 부분만 변경ddl-auto:validate : 객체와 테이블이 동일한지 확인ddl-auto: none : 별다른 조치 X Spring Data JPA를 이용해 자동으로 쿼리 날리는 방법에 대해 배운다.⇒ sql을 작성하지 않고 유저 생성/ 조회/ 업데이트 기능 리팩토링 유저 생성 기능UserServiceV2@Service public class UserServiceV2 { private final UserRepository userRepository; public UserServiceV2(UserRepository userRepository) { this.userRepository = userRepository; } // 이미 UserRepository에서 JPA를 상속받기 때문에 그냥 불러와서 public void saveUser(UserCreateRequest request){ userRepository.save(new User(request.getName(), request.getAge())); } // save 함수만 써주면 저장됨 => 이미 있는 문법(sql문이 필요없다) // User -> JPA로 되어있는 객체 } save 메소드에 객체를 넣어주면 INSERT SQL이 자동으로 날라감save되고 난 후 유저는 id를 갖게 됨 유저 조회 기능유저 조회 기능UserServiceV2// 유저 조회 public List<UserResponse> getUsers(){ return userRepository.findAll().stream() // 모든 테이블을 가져옴 .map(user -> new UserResponse(user.getId(), user.getName(), user.getAge())) .collect(Collectors.toList()); } 자바 문법을 이용해 더 간단하게 변경 가능(자바 8버전을 이용한 stream)stream 으로 만들어서 mapping 후 유저리스트로 다시 만듦 .collect(Collectors.toList());⇒ 즉 유저 객체를 가져와서 객체 간의 변환하게 됨findAll() : 모든 데이터를 가져옴(select * from user;) 유저 업데이트 기능id를 이용해 User을 가져와 User가 있는지 없는지 확인하고User가 있다면 update 쿼리를 날려 데이터 수정(없으면 예외 던짐)UserServiceV2// 유저 업데이트 public void updateUser(UserUpdateRequest request){ // 원하는 sql : select * from where id = ?; // 반환값 : Optional<User> => 매핑했던 user 객체 User user = userRepository.findById(request.getId()) .orElseThrow(IllegalArgumentException::new); // 유저가 없다면 예외, 유저가 있다면 결과값 들어옴 user.updateName(request.getName()); // 유저의 객체를 가져와 업데이트 // request.getName() -> 변경되어야 하는 api의 이름 userRepository.save(user); // 자동으로 user의 이름이 바뀌어있는걸 확인하고 바뀐걸 기준으로 업데이트 쿼리가 날아감 } findById : id를 기준으로 조회 지금까지 사용한 기능save : 주어지는 객체를 저장하거나 업데이트 시켜줌findAll : 주어지는 객체가 매핑된 테이블의 모든데이터 가져옴findById : id를 기준으로 특정한 1개의 데이터 가져옴어떻게 Sql을 작성하지 않아도 동작하는걸까?!JPA가 자동으로 처리하는겅가? 반은 맞고 반은 틀림⇒ Spring Data JPA 가 하는 것임 ( Spring Data JPA ≠ JPA)Spring Data JPA : 복잡한 JPA 코드를 스프링과 함께 쉽게 사용할 수 있도록 도와주는 라이브러리 유저 삭제 기능⇒ spring JPA로 바꾸기삭제는 이름 기준인데 이름 기준 조회는 없음💡 어떻게 select * from user where name = ? 을 어떻게 만들 수 있을까?⇒ UserRepository interface에 들어가서 유저 반환 함수 만들기User entity 객체에 있음UserRepositorypublic interface UserRepository extends JpaRepository<User, Long> { User findByname(String name); // -> select * from user where name = ?; } 반환 타입은 User, 유저가 없다면 null 반환함수 이름을 작성하면, 알아서 sql 조회되는 방식임 ⇒ 함수 이름을 기본 함수처럼 만들어야 함find 라고 작성하면, 1개의 데이터만 조회By 뒤에 붙는 필드 이름으로 SELECT 쿼리의 where 문이 작성됨UserServiceV2// 유저 삭제 public void deleteUser(String name){ User user = userRepository.findByname(name); if (user == null) { throw new IllegalArgumentException("User not found"); } userRepository.delete(user); // 무조건 유저가 존재함을 의미(없으면 예외처리가 되니깐) } delete : 주어지는 데이터를 db에서 제거함 다양한 Spring Data JPA 쿼리에는 무엇이 있을까? By 앞에 들어갈 수 있는 기능find : 1건을 가져옴. 반환 타입은 객체가 될 수도 있고, Optional<type>이 될 수도 있음findAll : 쿼리의 결과물이 N개인 경우 사용. List<타입> 반환exist : 쿼리 결과가 존재하는지 확인. 반환 타입은 boolean (존재하면 true, 존재 X false)count : sql의 결과 개수를 셈. 반환 타입은 long (ex. long countByAge) By 뒤에 들어갈 수 있는 기능 ( findByName )각 구절은 And 나 Or 로 조합할 수 있음List<User> findAllByNameAndAge(string name, int age); => SELECT * FROM user WHERE name =? AND age = ?; GreaterThan : 초과 ( 필드명 뒤에)GreaterThanEqual : 이상LessThan : 미만LessThanEqual : 이하Between : 사이에 트랜잭션트랜잭션 : 쪼갤 수 없는 업무의 최소 단위 만약 쇼핑몰 사이트에서 물건을 주문하면주문 기록 저장포인트 저장결제 기록 저장public class OrderService { public void completePayment() { orderRepository.save(new Order(..)); pointRepository.save(new Point(..)); billingHistoryRepository.save(new BillingHistory(..)); } } billingHistoryRepository.save(new BillingHistory(..)); 에서 만약 에러가 난다면?⇒ 주문 정보 데이터가 있고 포인트 저장 데이터가 있는데 결제 기록에는 안 뜨게 된다pointRepository.save(new Point(..)); 에서 만약 에러가 난다면?⇒ 주문 기록은 있는데 포인트와 결제 기록이 없다모든 sql을 성공시키거나, 하나라도 실패하면 모두 실패시키자!⇒ 쪼갤 수 없고 한 몸이다 ⇒ 트랜잭션 트랜잭션 명령어start transaction; // 트랜잭션 시작 commit; // 정상 종료 rollback; // 실패 처리성공 처리시키면 보이고(commit) 실패 처리 시키면 안 보임(rollback)우리의 코드에 어떻게 적용할 수 있을까?public class OrderService { public void completePayment() { orderRepository.save(new Order(..)); pointRepository.save(new Point(..)); billingHistoryRepository.save(new BillingHistory(..)); } } completePayment() 함수가 시작되기 전에 트랜잭션을 시작하고모두 성공하면 commit 하나라도 실패하면 rollback을 시키자우리 프로젝트에서 트랜잭션을 사용하려면@Transactional 사용해 적용시키면 된다. UserServiceV2@Service public class UserServiceV2 { private final UserRepository userRepository; public UserServiceV2(UserRepository userRepository) { this.userRepository = userRepository; } // 유저 생성 @Transactional public void saveUser(UserCreateRequest request){ userRepository.save(new User(request.getName(), request.getAge())); } // 유저 조회 @Transactional public List<UserResponse> getUsers(){ return userRepository.findAll().stream() .map(UserResponse::new) .collect(Collectors.toList()); } // 유저 업데이트 @Transactional public void updateUser(UserUpdateRequest request){ // 원하는 sql : select * from where id = ?; // 반환값 : Optional<User> User user = userRepository.findById(request.getId()) .orElseThrow(IllegalArgumentException::new); // 유저가 없다면 예외, 유저가 있다면 결과값 들어오고 user.updateName(request.getName()); // 들어온 이름 userRepository.save(user); // 자동으로 user의 이름이 바뀌어있는걸 확인하고 바뀐걸 기준으로 업데이트 쿼리가 날아감 } // 유저 삭제 @Transactional public void deleteUser(String name){ User user = userRepository.findByname(name).orElseThrow(IllegalArgumentException::new); userRepository.delete(user); // 무조건 유저가 존재함을 의미 } } SELECT 쿼리만 사용한다면, readOnly 옵션을 쓸 수 있음트랜잭션을 사용했을 때 데이터 변경을 할 수 없음 ⇒ 보통 조회에 사용 영속성 컨텍스트 : 테이블과 매핑된 Entity 객체를 관리/보관하는 역할User.java@Entity // 엔티티 public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; @Column(nullable = false, length = 20) // name(varchar) = 20 private String name; private Integer age; // id, name, age => 테이블관 매핑된 객체 스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생겨나고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료됨. ⇒ 즉 트랜잭션과 함께 생겨나고 트랜잭션과 함께 종료됨 영속성 컨텍스트의 특수 능력 4가지변경 감지(Dirty Check) : 영속성 컨텍스트 안에서 불러와진 Entity는 명시적으로 save 하지 않더라도, 변경을 감지해 자동으로 저장됨쓰기 지연DB의 insert / update / delete sql을 바로 날리는 것이 아니라 트랜잭션이 commit될 때 모아서 한 번에 날림 쓰기 지연이 없다면? ⇒ A, B, C를 각자 저장 → spring과 db 사이의 통신이 3번 일어남(시간이 오래 걸림)쓰기 지연이 있다면? ⇒ 3번 통신했지만 한 번에 저장하기(시간이 빠름)1차 캐싱영속성 컨텍스트가 없다면 3번 통신이 일어남첫번째 코드가 실행되면 조회 (영속성 컨텍스트가 id가 1인 유저 기억) → 두번째 코드가 실행되면 id가 1인 유저를 이미 알고 있어서 가지고 있는 정보를 내보냄과제 6. Layered Architecturehttps://velog.io/@dmsqls19/인프런-워밍업-클럽-1기-BE-과제6.-기능-분리 회고이 이후 섹션부터는 지금 공부 중에 있다. 아무래도 내 다짐과는 다르게 너무 공부를 덜 한 느낌이라 시간이 된다면 완주한 후에 발자국을 남겨보도록 하겠다. 사실 강의 정리는 계속 강의를 들으면서 따로 정리하고 있기 때문에 나중에 다 완강하고 한 번 더 들으면서 제대로 공부해 볼 생각이다. 이번주는 과제도 한 개 밖에 제출하지 못 했다. 여러모로 아쉬운 한 주다ㅠㅜ https://quartz-mastodon-ac1.notion.site/6ae20b419ca9400c94b4df9ab8f2f3da?pvs=74

백엔드

dev_traveler

[인프런 워밍업 스터디 1기 디자인] 3주차 - 컴포넌트 만들기 2

지난 주에 이어 컴포넌트 만들기를 계속 진행했습니다. 다양한 컴포넌트들을 만들어 보니 자신감도 생기고 Figma 툴도 점점 능숙해져 갑니다. 과제가 다 끝나고 빨리 사이드 프로젝트를 시작해보고 싶습니다. Card 컴포넌트컨텐트를 표현하기 좋은 Card 컴포넌트 입니다. 단순한 형태로 만들어서 현재는 이미지, 제목, 부제목, 설명, 버튼만 넣고 뺄 수 있습니다. 그러나 좀 더 확장성 좋은 구조로 개선할 수 있어 보입니다. 나중에 연습해볼 Modal 컴포넌트에서 Slot 을 활용해 확장성이 좋은 컴포넌트를 만들었는데 참고하면 좋을 것 같습니다. Modal 컴포넌트Slot 을 활용해서 해당 Slot 에 다른 컴포넌트를 넣을 수 있도록 확장성 있게 설계했습니다.이 모달 컴포넌트를 사용해서 다양한 모달을 구현했습니다.그러나 확장성을 위해서 너무 자유도 높은 컴포넌트를 설계하면 사용할 때 오히려 불편합니다. 그래서 변하는 부분과 변하지 않는 부분을 구분하는게 중요합니다. 이 Modal 컴포넌트는 인스턴스를 만드는데 바로 사용되기 보다 다양한 모달 컴포넌트를 만들기 위한 재료로 사용되면 좋을 것 같습니다.  Toast와 Alert 컴포넌트Toast 와 Alert 은 쓰임새가 비슷해서 좀 헷갈립니다. uiguideline.com 에서 제공하는 정의를 통해 구분지어 봅시다. Toasts are shown as a floating box typically in the top right of the page. They can optionally be displayed on other edges of the screen (top-left, top-center, bottom-left, bottom-center, or bottom-right). Toasts provide limited space for content, and therefore the content must be short and concise, providing immediate feedback in response to a user action or informing users of a process that the app has performed or will perform. Disappear automatically or can be dismissed by the user.Generally, an alert displays a prominent message at the top of the screen. It could be used to promote a new feature or provide action-based feedback messages. They’re persistent and nonmodal, allowing the user to either ignore them or interact with them at any timeToast 는 주로 화면의 오른쪽 상단에서 떠오르고 짧고 간결한 메세지를 담고 있습니다. 사용자 행동에 즉각적인 피드백이나 애플리케이션이 잘 동작하고 있음을 알려주는 정보를 담습니다. 자동으로 사라지거나 사용자에 의해 없앨 수 있습니다. Alert 은 화면 상단에 눈에 띄는 메세지를 보여줍니다. 새로운 기능이나 사용자 행동을 수반하는 피드백 메세지를 담을 수 있습니다. alert은 영구적이고 모달처럼 동작하지 않기 때문에 사용자가 언제든지 무시하거나 반응할 수 있습니다. 핵심은 Alert 은 자동으로 닫히지 않고 화면 상단에 위치하지만 Toast 는 화면 가장자리에서 즉각적으로 튀어나와서 자동으로 사라질 수 있다는 것입니다. 이제 두 컴포넌트를 구분해서 사용할 수 있을 것 같습니다.  Table 컴포넌트테이블 컴포넌트는 복잡할 줄 알았는데 생각보다 쉬웠습니다. 테이블을 구성할 요소들을 나누어 part 컴포넌트로 나누고 조합하면 금방 테이블이 만들어집니다. 3주동안 과제를 진행해보며평균적으로 하루동안 봐야할 강의는 1시간 정도이고 이를 연습해보고 미션까지 수행하는 것은 저에겐 3시간은 필요한 것 같습니다. 매일 4시간씩 과제를 한다는게 정말 쉽지 않은 일인데 스스로 대견하다는 생각도 듭니다. (물론 저는 지금 이틀정도 밀려있습니다.) 밀리지 않고 진도에 맞춰서 진행하는 다른 인프러너분들 정말 존경합니다. 이제 진짜 일주일도 안남았는데 끝까지 완주해서 오마카세 먹으러 갈랍니다. (OT 때 스스로 정하신 자기 보상 기억하시죠? 저도 방금 문득 생각났습니다ㅎㅎㅎ) 그럼 모두 화이팅 🔥

UX/UIFigmaUXUIComponentDesignProduct

S.M KIM

[인프런 워밍업 클럽 Study] 백엔드 3주차 발자국

학습 내용 요약 <SQL을 직접 작성하는 것에 대한 문제점>실수할 여지가 많으며, 실수 시 인지하는 시점이 느리다SQL 작성 시 오타가 발생할 경우 IDE에서 자체적으로 확인해주는 것이 아니라면 보통은 런타임 에러로 처리가 되어서 실제로 서버가 가동될 때 에러가 발생하여 문제가 더 커질 가능성이 있음.특정 데이터베이스에 종속적이게 된다.데이터베이스마다 SQL 문법이 조금씩 다르기 때문에 데이터베이스를 바꾸게 되면 이미 작성한 SQL문도 잘못된 부분이 있으면 하나하나 다 바꿔줘야 함.반복작업이 많아진다.테이블을 하나 만들 때마다 기본적인 INSERT / SELECT / UPDATE / DELETE 쿼리는 필요하며, SELECT 쿼리를 할 때마다 필드 하나하나를 매핑해주는 것이 번거롭다.데이터베이스와 객체는 패러다임이 다르다.대표적으로 연관관계와 상속에서 이러한 차이점이 두드러진다. <JPA의 정의>ORM (Object-Relational Mapping) : 관계형 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 자동으로 매핑(연결)해주는 프로그래밍 기법JPA : 객체와 관계형 데이터베이스의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙Hibernate : JPA를 구현한 구현체. <JPA 어노테이션>@Entity : 특정 객체에 붙여, 해당 객체를 DB 테이블로 인식하게 해주는 어노테이션.@Id : 객체 필드에 붙여 그 객체 필드를 primary key로 간주하게 하는 어노테이션.@GeneratedValue : 기본키의 생성 전략을 정의하기 위한 어노테이션.생성 전략으로는 Table, Sequence, Identity, Auto가 있으며, 기본값은 Auto임.@Column : 객체 필드를 테이블 컬럼에 매핑하는 어노테이션.nullable : null 값의 허용 여부를 설정unique : 유일성 조건 여부를 설정length : 문자 길이 제약조건을 설정 <application.yml>spring.jpa.hibernate.ddl-auto스프링이 시작할 때 DB에 있는 테이블을 어떻게 처리할지에 대한 옵션create : 기존 테이블이 있다면 삭제 후 다시 생성create-drop : 스프링이 종료될 때 테이블을 삭제update : 객체와 테이블이 다른 부분만 변경validate : 객체와 테이블이 동일한지 확인none : 별다른 조치를 하지 않음spring.jpa.properties.hibernate.show_sqlJPA를 사용해 DB에 SQL을 날릴 때 SQL 쿼리문을 보여주는 것에 대한 설정spring.jpa.properties.hibernate.format_sqlJPA를 사용해 DB에 SQL을 날릴 때 SQL을 예쁘게 포맷팅하는 것에 대한 설정spring.jpa.properties.hibernate.dialect데이터베이스의 종류를 설정해주기 위한 방언 설정 <자동으로 쿼리문 날리기>Repositorypublic interface UserRepository extends JpaRepository<User, Long> { } Repository에서 JpaRepository를 상속받도록 설정하고, 테이블의 매핑 객체인 User 와 유저 테이블의 id인 Long 타입을 각각 적어주어야 한다. 간단하게 사용할 수 있는 JPA 명령어userRepository.XXX()save : 주어진 객체를 저장하거나 업데이트 한다.findAll : 주어지는 객체가 매핑된 테이블의 모든 데이터를 가져온다.__By__ : id를 기준으로 특정한 1개의 데이터를 가져온다. By 앞과 뒤에 어떤 단어가 들어가는지에 따라 쿼리를 마음껏 만들어낼 수 있다By 앞에는 find, findAll, exists, count 등이 들어갈 수 있다.By 뒤에는 필드 이름이 들어가며, and나 or 로 조합될 수 있다.ex) findAllByNameAndAge = select * from user name = ? and age = ?ex) findAllByNameOrAge = select * from user name = ? or age = ?동등 조건 외에 다양한 조건을 활용할 수도 있다.GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, Between, StartsWith , EndsWith 등… <트랜잭션과 영속성 컨텍스트>트랜잭션 : 쪼갤 수 없는 업무의 최소 단위commit : 트랜잭션 시작 후 실행된 SQL 명령을 DB에 반영rollback : 트랜잭션 시작 후 실행된 SQL 명령을 반영하지 않고 취소대상 메소드에 @Transactional 어노테이션을 붙여 트랜잭션을 적용할 수 있다.트랜잭션 실행 로직은 다음과 같다.서비스 메소드가 시작할 때 트랜잭션과 영속성 컨텍스트가 시작돈다.서비스 메소드 로직이 모두 정상적으로 성공하면 commit 된다.서비스 메소드 로직 실행 도중 문제가 생기면 rollback 된다.트랜잭션이 종료될 때 영속성 컨텍스트도 종료된다.영속성 컨텍스트의 특징변경 감지 (Dirty Check) : 영속성 컨텍스트 안에서 불러온 Entity는 명시적으로 save 를 해주지 않더라도 알아서 변경을 감지하여 저장된다.쓰기 지연 : 여러 SQL 문을 실행시켜도 이 쿼리문들을 모아 commit 되는 시점에 한번에 DB에 적용시켜준다.1차 캐싱 : ID를 기준으로 Entity를 기억하는 기능으로, SELECT 문을 사용하여 특정 엔티티를 불러올 경우 쿼리문이 한 번만 발생하며, 이후 같은 엔티티를 불러올 경우 영속성 컨텍스에 저장된 엔티티를 불러오게 된다. 회고저번 주에 클린 코드에 대한 강의를 듣고 이번 주에 과제를 진행하면서 클린 코드를 적용해보기로 했지만 생각보다 쉽지 않아 아쉬웠던 것 같습니다. 이번 주 금요일에 진행했었던 QNA 코드리뷰 시간에서는 throw new를 적용할 때 발생하는 동시성 이슈, N+1 문제, @Transactional 어노테이션의 readonly 옵션, enum 클래스의 활용, ApiUrlConstants로 API 주소를 관리하는 기법 등이 기억에 남았습니다. 이제 마지막으로 최종 과제만 남았는데, 남은 시간동안 테스트 코드를 이용하여 최종 과제를 해결하는 것은 어려워도 지금까지 배운 클린 코드에 대한 지식으로 최대한 깔끔한 코드를 작성해보도록 노력할 것입니다. 

백엔드워밍업

김체토

[인프런 워밍업 클럽 스터디 1기 디자인] 3주차 발자국

3주 차 - 학습했던 내용 요약인풋 컴포넌트인 버튼, 체크박스, 라디오, 스위치, 라벨, 컨트롤 그룹, 텍스트 필드, 텍스트 상자, 셀렉트를 만들었습니다.디스플레이 컴포넌트인 아바타, 아코디언, 뱃지, 툴팁, 디바이더, 칩, 스테이터스 칩, 카드 폼, 테이블 요소들을 만들었습니다.제작한 컴포넌트의 대비를 체크하여 접근성에 부합하는지 체크해 주었습니다.라이브로 타이포그래피 베리어블에 대하여 공부했습니다.  3주 차 - 회고만들어진 컴포넌트를 볼 때는 금방 만들 수 있을 것 같았는데 실제로 하나씩 따라 만들어보니 시간이 생각보다 많이 걸립니다. 이번 주에 내비게이션 컴포넌트까지 만드는 게 목표였는데 디스플레이까지밖에 하지 못했습니다.테이블은 각 잡고 만들면 상당히 복잡해질 것 같네요.특히 만들어진 컴포넌트를 활용하여 또 다른 컴포넌트를 만들 때는 고려해야 할 점들도 많아지는데, 어떻게 더 효율적으로 프로퍼티를 구성하면 될지 고민을 거듭하면서 더 좋은 컴포넌트를 디자인할 수 있게 되는 것 같습니다.타이포그래피 베리어블도 많이 복잡하다고 느껴졌는데 볼드님 라이브를 듣고 쉽게 이해할 수 있었습니다. type face, font, font family도 잘 구분할 수 있게 되었습니다 :)타이포그래피 베리어블은 복잡하지만 잘 적용해 본다면 반응형 작업 시 타이포까지 대응할 수 있어 엄청 좋을 것 같습니다!  4주 차 - 다짐 및 계획다음 주에는 나머지 컴포넌트들을 만들고 예시 페이지들까지 완성하여 커리큘럼을 완주해 보도록 하겠습니다!!  

UX/UI인프런워밍업클럽스터디figmauiux

희희

[인프런 워밍업 클럽 스터디 1기] BE 3주차 회고

 세번째 발자국 인프런 워밍업 클럽 스터디에 참여하여 일주일을 보낸 후 쓰는 세번째 회고록.  학습 내용 Section 5 - 책 요구사항 구현하기연관관계두 개 이상의 테이블 또는 객체 간의 관계를 정의하는 방법엔티티 간 객체지향적 모델링 가능 연관관계의 주인 효과상대 테이블을 참조하고 있으면 연관관계의 주인연관관계의 주인이 아니면 MappedBy를 사용연관관계의 주인의 setter가 사용되어야만 테이블 연결 JPA 연관관계1:1 관계@OneToOne한 엔티티가 하나의 엔티티와만 연관된 경우두 엔티티 모두 @OneToOne 설정주인이 아닌 곳에 mappedBy 붙여야 함N:1 관계@ManyToOne여러 엔티티가 한 개의 엔티티와 연관된 경우연관관계의 주인은 무조건 N (숫자가 많은 쪽)N쪽(Many)에 @ManyToOne을 설정하고 1쪽(One)에 @OneToMany를 설정@ManytoOne은 단방향으로 사용 가능@JoinColumn연관관계의 주인이 활용할 수 있는 어노테이션필드의 이름이나 null 여부, 유일성 여부, 업데이트 여부 등을 지정N:M 관계@ManyToMany여러 엔티티가 여러 개의 엔티티와 연관된 경우구조가 복잡하고 테이블이 직관적으로 매핑되지 않아 사용하지 않는 것이 좋음casade 옵션한 객체가 저장되거나 삭제될 때, 그 변경이 폭포처럼 흘러 연결되어 있는 객체도 함께 저장되거나 삭제되는 기능orphanRemoval 옵션객체 간의 관계가 끊어진 데이터를 자동으로 제거하는 옵션  Section 6 - 생애 최초 배포 준비하기배포최종 사용자에게 SW를 전달하는 과정전용 컴퓨터에 우리의 서버를 옮겨 실행시키는 것 전용 컴퓨터에 코드를 옮기고 필요한 프로그램을 설치해 최종 사용자가 접속할 수 있도록 하는 것 profile같은 서버 코드를 실행시키지만, 실행 설정을 다르게 하고 싶을 때 사용DB 설정, 외부 API 키 등의 환경 구성을 다르게 할 수 있음local -> H2 DB, dev -> MySQL DBapplication.yml에서 ---로 옵션 구분 H2 DB경량 데이터베이스로, 개발 단계에서 많이 사용함디스크가 아닌 메모리에 데이터를 저장 가능개발단계에서는 수정사항이 많아 데이터가 휘발되는 것이 장점으로 작용ddl-auto 옵션을 create로 설정하면 테이블이 자동 생성/삭제가 되어 편리함 git코드를 쉽게 관리할 수 있도록 해주는 버전 관리 프로그램githubgit으로 관리되는 프로젝트의 코드가 저장되는 저장소코드는 어떠한 이유로든 소실될 가능성이 있기 때문에 백업용으로 사용프로젝트 공유, 협업, 배포 등에 활용 가능git 명령어git initgit 초기화해당 프로젝트를 git이 관리하겠다는 의미git remote add orign [각자의 주소]현재 프로젝트의 git 저장소를 주어진 주소로 설정git add . 작업 디렉토리의 모든 (변경된) 파일을 스테이징 영역(commit의 대상)으로 추가 (택배 상자에 파일 담기). 대신 [파일 이름]을 넣으면 특정 파일만 추가 가능git statusgit 상태 확인 (택배 상자 안에 담긴 내용 확인)git commit -m "메시지"스테이징 영역의 상태를 버전으로 기록 (택배를 포장하고 송장 붙이기)commit을 해주면 commit한 곳으로 언제든지 돌아올 수 있어 코드의 추가, 삭제가 자유로움commit 메시지에는 적고 싶은 내용(어떤 코드인지, 업데이트 내용 등)git push 원격 저장소(github)에 코드 변경분을 업로드 (택배 상자 github에 보내기)git pull원격 저장소의 코드를 다운로드.gitignoregit을 통해 관리하고 싶지 않거나 원격 저장소에 올리고 싶지 않은 파일을 관리하기 위한 파일파일의 경로나 파일 이름을 적어둠 AWS(Amazon Web Service)가입하면 우리가 배포할 전용 컴퓨터를 대여 가능지역을 한국으로 변경EC2 (Elastic Compute Cloud)탄력적으로 사용할 수 있는 원격 컴퓨터탄력적 : 원격으로 언제든 생성/제거 가능인스턴스 = 우리가 빌린 컴퓨터인스턴스 시작을 누른 후 설정이름 및 태그 : 우리가 빌릴 컴퓨터의 이름 지정애플리케이션 및 OS 이미지 : 기본적으로 Amazon Linux 2 AMI(아마존에서 관리하는 리눅스 운영체제)인스턴스 유형 : 우리가 빌릴 컴퓨터 사양키 페어(로그인) : 빌린 컴퓨터에 접속할 때 필요한 보안 파일네트워크 설정 : 빌린 컴퓨터에 접속할 때 접근을 허용할 IP, 포트 등을 설정하는 보안 그룹 생성스토리지 구성 : 빌릴 컴퓨터의 디스크 용량 결정 Section 7 - 생애 최초 배포하기EC2 접속키 페어를 이용하는 방법다운로드 받은 키 페어(pem key)키 페어 파일의 보안을 설정 : chmod 400 경로/키페어명 .pemchmod : 접근 권한 변경 (400)ssh 접속 : ssh -i 경로/키페어명.pem ec2-user@IPAWS 콘솔을 활용하는 방법AWS EC2 웹사이트에 접속해 연결 버튼 누르기 리눅스 명령어mkdir: 폴더를 만드는 명령어ls: 현재 위치에서 폴더나 파일을 확인하는 명령어ls -l : 더 자세한 정보 확인drwxrwxr-xd: 폴더(디렉토리)r: 읽는 권한, w: 쓰는 권한, x: 실행 권한rwx / rwx / r-x : 소유자 권한 / 소유 그룹 권한 / 아무나 접근할 때의 권한2 : 폴더에 걸려 있는 바로가기 개수ec2-user : 폴더 소유자의 이름ec2-user : 폴더 소유 그룹의 이름6 : 파일의 크기(byte)Dec 5 06:00 : 파일의 최종 변경 시각folder1 : 파일 이름cd(change directory): 폴더 안으로 들어가는 명령어cd .. : 상위 폴더로 이동pwd(print working directory): 현재 위치를 확인하는 명령어rmdir: 특정 폴더(디렉토리)를 제거하는 명령어 서버 설정 및 배포Git, Java, MySQL 설치코드를 가져오기 위한 Git서버를 구동할 Java사용할 데이터베이스 MySQL리눅스에서 스프링 배포 프로그램 설치Github에서 코드 가져오기git clone [저장소 주소]Swap 설정메모리가 부족할 경우 일부 디스크를 사용하도록 하는 설정 무료로 사용하는 EC2는 메모리가 적기 때문sudo dd if=/dev/zero of=/swapfile bs=128M count=16 : swap 메모리 할당sudo chmod 600 /swapfile : swap 파일에 대한 권한 업데이트sudo mkswap /swapfile : swap 영역 설정sudo swapon /swapfile : swap 파일 사용 설정sudo swapon -s : swap 성공 확인빌드chmod +x ./gradlew : gradLew를 사용할 수 있도록 쓰기 권한 설정./gradlew build -x test : gradle을 이용해 프로젝트 빌드 (테스트 코드 실행 X)서버 실행java -jar build/libs/[빌드한 파일명.jar] --spring.profiles.active=devJar 파일을 실행만 했는데 서버가 동작하는 이유 : Spring Boot에 톰캣이 내장되어 있기 때문톰캣 : 웹 애플리케이션 서버의 한 종류. 들어온 요청을 형식에 맞추어 스프링에 전달ctrl+c : 무언가를 중단하는 신호(실행중인 서버 중단)./gradlew clean : 현재 빌드되어 있는 결과물 제거 foreground vs backgroundforeground우리가 보고 있는 프로그램(현재 보이는 화면의 프로그램)background 우리가 보고 있지 않은데 실행 중인 프로그램ec2 접속을 종료해도 서버가 종료되지 않도록 하려면 서버를 background로 동작하게 해야 함nohup [명령어] &background 서버 다운ps aux : 현재 실행중인 프로그램 목록을 확인ps aux | grep java : java가 들어가는 프로그램을 확인(각 프로그램의 고유 번호 확인)kill -9 프로그램번호 : 해당 프로그램을 종료 DNS 적용가비아 회원가입 후 도메인 구매도메인 네임 등록 : 구매한 도메인과 빌린 EC2 서버 연결타입 : A호스트 : www값/위치 : EC2에서 빌린 인스턴스의 IP방화벽 설정접근 가능한 IP 혹 포트 설정 Section 8 - Spring Boot의 이모저모build.gradle빌드 스크립트gradle을 이용해 프로젝트를 빌드하고 의존성을 관리하기 위해 작성plugins : 프로젝트에 적용하고 싶은 플러그인 추가group : 프로젝트의 그룹version : 프로젝트의 버전sourceCompatibility : 프로젝트가 사용하고 있는 JDK 버전repositories : 외부 라이브러리나 프레임워크를 가져오는 장소 설정dependencies : 우리가 사용하는 라이브러리/프레임워크 표시tasks.named('test') : 테스트를 수행할 때 사용할 프레임 워크 Spring Boot의 특징(Spring과의 차이점)간편한 설정xml 대신 어노테이션 기반의 설정 가능기본적으로 필요한 것을 모두 자동 설정간단한 의존성 관리의존성을 필요한 것끼리 묶어 starter로 관리필요한 라이브러리나 프레임워크 하나 하나 적을 필요 없음강력한 확장성starter 추가만으로 필요한 기술을 도입할 수 있음 application.ymlYAML 문법 사용.yaml 또는 .yml : YAML의 확장자기본적으로 key : value 형식으로 데이터 정의각 계층은 들여쓰기를 통해 구분 (이를 통해 중복 제거)value로 들어갈 수 있는 타입 : 참/거짓, 숫자, 문자열(큰 따옴표 사용)배열은 - 사용#로 주석 표현application.propertiesapplicatoin.yml 대신 사용 가능key : value 형식으로 데이터 기록들여 쓰기를 통해 중복을 제거할 수는 없음application-프로파일 이름.properties 파일을 새로 만들어 profile 설정가독성 떨어짐lombok생성자, getter, setter, equals, toString 등 반복되는 보일러 플레이트 코드(boiler palte code)를 자동으로 생성해줌(반복되는 코드 제거)lombok 도입을 위한 설정lombok 의존성 추가IntelliJ lombok 플러그인 추가intelliJ Annotation Processor 설정  과제 6일차 과제 - Controller 3단 분리하기 https://shimmer-exoplanet-946.notion.site/6-18433147fcf443ad8597ac6b4fac8c43?pvs=4 문제 1번은 과제 4에서 만들었던 코드를 Controller - Service - Repository로 분리하는 과제였다. 수업 때 배운대로 API와 HTTP를 담당하는 부분만 Controller에 남겨두고 분기 처리나 로직을 담당하는 부분은 Service로, SQL을 이용해 DB와 통신을 담당하는 부분은 Repository로 분리해 주었다.문제 2번은 Repository를 DB에 데이터를 저장하는 MysqlRepository와 메모리에 데이터를 저장하는 MemoryRepository로 분리하는 과제였다. 기존 코드가 SQL을 이용해 DB에 데이터를 저장하는 방식이었으므로 그대로 MysqlRepository로 옮겨주고, MemoryRepository의 경우 List<Fruit>을 만들어 메모리에 과일에 대한 정보들을 저장했다. 기존 함수에서 id가 필요한 부분이 있었는데, mysql에서 id는 자동으로 생성되기 때문에 MemoryRepository에만 변수 num을 0으로 초기화해두고 createFruit가 호출될 때마다 1씩 증가하게 하여 id 대신 사용했다.문제 2개 모두 수업 시간에 했던 방식에서 크게 달라지지 않아 무난하게 해결했다. 확실히 코드를 계층별로 분리해두니 각 계층의 역할이 명확하게 보이고 코드가 간결해져 보기 편했다. 7일차 과제 - JPA 적용하기https://shimmer-exoplanet-946.notion.site/7-9e89cd27e6284807b1f448d6934b30fe?pvs=4문제 1은 과제 #6에서 만들었던 기능들을 JPA를 이용하도록 변경하는 것이었다. 수업에서 배운대로 Fruit 객체에 @Entity 어노테이션을 붙이고 각 필드를 테이블의 속성과 매핑되도록 적절한 어노테이션을 붙여주었다. 그후 FruitService에서 SQL을 문자열로 하나하나 타이핑하는 것이 아니라 JPA 함수를 이용해 DB와 통신하도록 수정하고, 추가적으로 필요한 함수는 FruitRepository 인터페이스에 선언해주었다.문제 2는 과일의 이름을 받아 지금까지 가계를 거쳐간 해당 과일의 개수를 세는 기능을 만드는 것이었다. 테이블에서 특정 이름을 가진 레코드의 개수를 세면 되는 것이라 countByName을 이용하여 원하는 값을 구했다. postman으로 테스트할 때 406 Not Acceptable 에러가 발생했는데, FruitCountResponse에 getter를 추가해주니 정상 작동했다.문제 3은 아직 판매되지 않은 과일 중 특정 금액 이상 혹은 특정 금액 이하의 과일 목록을 받아오는 기능을 만드는 것이었다. findAllByPriceGreaterThanEqual / findAllByPriceLessThanEqual을 이용해 특정 가격 이상/이하의 과일들을 가져온 후, Fruit의 isPurchase 함수를 이용해 팔린 과일인지 확인하여 팔리지 않은 과일들만 넣은 리스트를 반환해주었다.세 문제 모두 수업에서 배운 내용을 그대로 사용하거나 간단한 응용만 하는 방식이라 할 만 했다. 다만 stream과 같은 기능이 익숙하지 않아 해당 부분에서 발생한 에러를 해결하거나 특정 기능을 사용하는 방법을 찾기 위해 구글링을 해야 했다. 수업을 들으면서도 느꼈지만 자바 공부를 좀 더 해야겠다.   회고 다른 일들이 많이 겹쳐 공휴일이 끼어 있는데도 바쁜 한 주를 보냈다. 덕분에 저번주에 배운 내용을 다시 한번 복습하고 정리하겠다는 다짐은 지켰지만, 후반부 강의도 조금 밀려 늦게 들었고 따로 공부해보려던 것은 못한 점이 아쉽다. 이번주 강의는 새로운 개념을 익히기 보다는 배포 과정을 체험해보는 것에 가까웠던 점이 다행이었다. 강의를 따라하는 게 다지만 강사님의 화면과 다른 부분이 조금씩 있어 따로 찾아봐야 했는데, 그래도 진도를 마치고 배포까지 해내고 나니 굉장히 뿌듯하고 자신감이 붙었다. 처음에는 잘 사용하지 않는 리눅스나 AWS 부분에 대한 막연한 두려움이 있었는데 강의에서 세세히 설명해주니 어렵게만 느껴졌던 것들이 이해가 돼서 좋았다. 이번주로 스터디는 마무리되고 남은 것은 미니 프로젝트와 마무리 강의들 뿐이다. 다음주는 미니 프로젝트를 할 수 있는 부분까지만이라도 수행해보고, 시간이 된다면 강의에서 배운 것들을 전체적으로 복습하려 한다. 또한 스터디가 끝나더라도 한 주의 회고를 작성하는 것은 계속하는 습관을 들여보려 한다. 발자국을 작성하는 것은 이번 스터디를 통해서 처음 해봤는데, 한주동안 배운 내용을 한번씩 정리하는 것이 많은 도움이 되었다. 작성을 하는 동안 지난 한주를 돌아보며 아쉬운 점을 개선할 방법을 찾아보고, 다음주에 대한 계획을 세우게 되는 것도 좋았다. 이 마음가짐을 쭉 유지해서 스터디가 끝난 이후에도 계속해서 체계적으로 공부를 할 수 있도록 노력해야겠다.

백엔드인프런워밍업클럽스터디

lar

[인프런 워밍업 클럽 스터디 1기] 세번째 발자국

1. 3주차 학습한 내용 [10일차 - 객체지향과 JPA 연관관계]1. JPA 연관관계에 대한 추가적인 기능들1:1 관계 - @OneToOne예) 한 사람은 한 개의 실거주 주소만을 갖고 있다.@OneToOne 어노테이션을 사용한다.연관관계 주인이 아닌 쪽에 mappedBy 옵션을 사용한다.연관관계의 주인 효과객체가 연결 기준이 된다.상대 테이블을 참조하고 있으면 연관관계의 주인이다.연관관계 주인이 아니면 mappedBy를 사용한다.연관관계의 주인의 setter가 사용되어야만 테이블을 연결한다.연관관계의 사용 시 주의해야 할 점트랜잭션이 끝나지 않았을 때, 한 쪽만 연결해두면 반대 쪽은 알 수 없다. > setter 한번에 둘이 같이 이어주면 된다.N:1 관계 - @ManyToOne과 @OneToMany@ManyToOne을 단방향으로만 사용할 수도 있다.cascade 옵션 : 한 객체가 저장되거나 삭제될 때, 연결되어 있는 객체도 함께 저장되거나 삭제되는 옵션이다.orphanRemoval 옵션 : 객체간의 관계가 끊어진 데이터를 자동으로 삭제하는 옵션이다.실제 DB에서 데이터를 삭제하고 싶을 때 사용한다.@JoinColumn연관관계의 주인이 활용할 수 있는 어노테이션을 의미한다.필드의 이름, null여부, 유일성 여부, 업데이트 여부 등을 지정한다.N:M 관계 - @ManyToMany구조가 복잡하고, 테이블이 직관적으로 매핑되지 않아 사용하지 않는 것을 권장한다.도메인 계층에 비즈니스 로직이 들어갔다?BookService는 UserLoanHistory 객체를 직접 사용하지 않도록 변경하였다.User와 UserLoanHistory, 2개의 객체가 서로 협력하도록 변경하였다. 이를 도메인 계층에 비즈니스 로직이 들어갔다라고 표현한다.2. 영속성 컨텍스트의 4번째 특징지연 로딩(Lazy Loading) : 연결되어 있는 객체를 꼭 필요한 순간에만 가져온다.@OneToMAny의 fetch 옵션이다.(기본적으로 Lazy로 설정되어 있다.)연관관계를 사용하면 무엇이 좋을까?각자의 역할에 집중하게 된다. (=응집성)새로운 개발자가 코드를 읽을 때 이해하기 쉬워진다.테스트 코드 작성이 쉬워진다.연관관계를 사용하는 것이 항상 좋을까?지나치게 사용하면 성능 상의 문제가 생길 수도 있고, 도메인 간의 복잡한 연결로 인해 시스템을 파악하기 어려워질 수 있다.비즈니스 요구사항, 기술적인 요구사항, 도메인 아키텍쳐 등 여러 부분을 고민해서 연관관계 사용을 선택해야 한다.[11일차 - 기본적인 배포를 위한 준비]1. 배포란?최종 사용자에게 SW를 전달하는 과정을 의미한다.전용 컴퓨터(AWS)에 우리의 서버를 옮겨 실행시키는 것이다.최종 사용자가 우리의 서버를 쓸 수 있는 방법전용 컴퓨터에 코드를 옮기고 스프링, MYSQL 등을 설치해 사용자가 접속하게 한다.AWS에서 컴퓨터를 빌릴 때 알아둬야 할 점컴퓨터를 살 때 운영체제도 같이 선택한다.윈도우, 리눅스, 맥OS2. profile과 H2 DBprofile 적용스프링 서버를 실행할 때 db와 같은 설정들을 코드 변경 없이 제어할 수 있는 방법spring: config: activate: on-profile: local datasource: url: "jdbc:h2:mem:library;MODE=MYSQL;NON_KEYWORDS=USER" username: "sa" password: "" driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create properties: hibernate: show_sql: true format_sql: true dialect: org.hibernate.dialect.H2Dialect h2: console: enabled: true path: /h2-console --- spring: config: activate: on-profile: dev datasource: url: "jdbc:mysql://localhost/library" username: "root" password: "" driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: none properties: hibernate: show_sql: true format_sql: true dialect: org.hibernate.dialect.MySQL8Dialect 3. git과 githubgit이란?코드를 쉽게 관리할 수 있도록 해주는 버전 관리 프로그램을 의미한다.버전 A, 버전 B를 쉽게 만들 수 있게 해주고 여러 버전을 쉽게 취합이 가능하다.github이란?git으로 관리되는 프로젝트의 코드가 저장되는 원격 저장소를 의미한다.왜 github에 코드를 저장하는걸까?컴퓨터의 있는 소스코드가 소실될 수 있기 때문에 코드를 원격의 저장하는 것이다.배포할 때도 활용한다.4. git 기초 사용법git을 활용해서 github 프로젝트 업로드하기github 사이트 접속github 저장소 생성한다.(Create Repository)IntelliJ Terminal을 이용해 git 명령어 입력git 프로젝트 시작하기 / git init : 이 프로젝트를 이제 git이 관리하겠다는 의미git 프로젝트의 github 저장소 설정하기 / git remote add origin [각자의 주소]기초 셋팅 완료git 기초 명령어코드를 git에 추가할 때 명령어git add.git에 메세지 붙이는 명령어git commit-m "메세지"git을 github에 보내기git push현재 상황 확인하기git status파일들 빼주기git reset5. AWS의 EC2 사용하기회원가입AWS 계정 생성(회원가입) - 회원정보/결제정보/본인인증/Support 플랜 (무료) 선택로그인루트 사용자 선택 - 계정입력 후 로그인콘솔 홈지역(서버) 서울로 설정서비스에서 EC2 검색 및 클릭 - 리소스 : 인스턴스(빌린 컴퓨터) 클릭인스턴스 시작 클릭 - 이름 및 태그 : 이름 입력 - 아마존 리눅스 선택 - 인스턴스 유형(빌린 컴퓨터의 사양) CPU 및 메모리 t2.micro 선택 - 키 페어 : 새 키 페어 생성 - 키 페어 이름 입력 수 생성 - 네트워크 설정 : 보안 그룹 생성 선택 - 스토리지 구성(용량) 8gib - 설정 후 인스턴스 시작 클릭인스턴스 목록을 보면 실행 중인 서버가 확인된다. [12일차 - AWS와 EC2 배포]1. EC2에 접속해 리눅스 명령어 다뤄보기다운로드 받은 키 페어를 이용하는 방법우리가 접속하려는 EC2의 IP 주소 : 퍼블릭 IPv4 주소이전 시간에 다운로드 받았던 키 페어접속하기 위한 프로그램(git CLI 또는 Mac treminal)기본적인 리눅스 명령어mkdir : 폴더를 만드는 명령어ls : 현재 위치에서 폴더 또는 파일을 확인하는 명령어cd : 폴더 안으로 들어가는 명령어pwd : 현재 위치를 확인하는 명령어2. 과제여섯 번째 과제(6일차)일곱 번째 과제(7일차)3. 회고프로젝트 배포 하는 법을 알 수 있어서 좋았고, 배포를 하면서 오류가 발생해서 한번에 되지 않아 시간이 오래 걸렸다. 리눅스에 대한 공부도 해야겠다는 생각이 들었다. 아직 미니 프로젝트를 진행하진 못했지만 배운 것을 활용해서 잘 마무리해야겠다!

백엔드워밍업발자국회고3주차

cynh K

[인프런 워밍업 스터디 1기 디자인] 3주차 발자국 및 회고

피그마 베리어블을 활용한 디자인시스템 구축 3주차 회고3주차 회고 작성하러 왔습니다..! 가정의 달이라는 좋은 핑계로 공부가 아닌 다수의 외부일정으로 이번주는 정말 부진했어요 ㅠㅠ회고하며 부지런히 늦어진 진도 잡으러 왔습니다 가보자고..!.3주차 다짐과 느낀점  3주차를 맞이하며 배웠던 시스템을 조금씩 그리고 재밌게 실무에 적용하고 사용하기 시작했어요! 특히 라디오,스위치,텍스트 필드를 하나하나 만들다보니 시간은 걸렸지만 너무 재밌었습니다 ㅎ-ㅎ1-2주차때 빠진 강의를 듣고 이해가 안되던 강의를 재수강하다보니 자연스레 진도가 늦어진 상황에 이번주엔 지난 미션을 하기 바빴던 것 같아요 아주 스스로에게 실망,,그래도 토요일날 진행되었던 중간점검 라이브에서 멘토님의 정성어린 자료와 피드백을 들으면서 포기하지 말자는 마음이 들었어요.4주차 시작에 있어 다짐최대한 멘토님께서 세워주신 플랜을 따라가되, 이해의 측면에도 중요한 것 같아서스트레스 받지않고 정확히 재밌게 공부한다는 마음으로 할 수 있는 만큼 최선을 다하려고 합니다!볼드멘토님도 멘티님들도 스터디 하는 모든 분들 막주도 화이팅입니다!

UIUX인프런워밍업클럽

박지원

[인프런 워밍업 클럽 스터디] BE 1기 세번째 발자국

섹션 5. 책 요구사항 구현하기 JPA에서 연관관계를 매핑하기연관관계의 주인: "상대 테이블을 가리키는 테이블"Table을 바라보았을 때 누가 관계의 주도권을 가지고 있는지를 의미함.JPA에도 알려주는 법: 연관관계의 주인이 아닌 객체에서 @OneToMany와 같은 연관관계 어노테이션에 mappedBy 옵션을 표시한다.연관관계 주인의 효과: 연관관계의 주인을 기준으로 테이블이 연결된다.예를 들어, 연관관계의 주인인 person 은 setAddress 를 통해 테이블을 이어주지만, address로 같은 메서드를 실행하면 제대로 테이블이 연결되지 않는다.person.setAddress(address); // 정상 실행 address.setPerson(person);연관관계의 주인을 통해 객체를 이어줘도, 반대쪽도 이어지는 것은 아니므로 하나의 setter 안에서 객체끼리 완전히 연결시켜 주어야 한다.연관관계의 주인인 person 은 setAddress 내에서 address의 Person도 설정해 준다.public void setAddress(Address address) { this.address = address; this.address.setPerson(this); }연관관계를 나타내는 어노테이션 @OneToMany와 @ManyToOne: N : 1 관계@OneToOne: 1 : 1 관계@ManyToMany: N : M 관계 (*N : M 연관관계의 구조는 복잡하고, 테이블도 직관적으로 매핑되지 않기 때문에 사용하지 않는 게 좋음) JPA 연관관계의 다양한 옵션 mappedBy 옵션: 연관관계의 주인이 아닌 객체가 주인에게 매여 있음을 표시한다.@JoinColumn: 연관관계의 주인에게 활용할 수 있는 어노테이션. 연관관계의 주인이 가지고 있는 다른 테이블을 가리키는 필드의 이름이나 null 여부, 유일성 여부, 업데이트 가능 여부 등을 정해줄 수 있다.cascade 옵션: 한 객체가 저장되거나 삭제될 때, 연결되어 있는 객체도 함께 저장되거나 삭제되는 기능orphanRemoval 옵션: 연관관계가 끊어진 데이터를 자동으로 제거해 준다.fetch 옵션: 객체의지연 로딩 여부를 설정한다. 꼭 필요할 때 가져오는 LAZY 옵션(기본 옵션), 처음 데이터를 로딩할 때 바로 가져오는 EAGER 옵션이 있다.지연 로딩: 영속성 컨텍스트의 특징. 필요한 순간에 연결되어 있는 객체를 가져온다.연관관계를 사용하면?도메인 계층에서 두 클래스가 직접 협업할 수 있으므로 Service 계층의 코드가 더 간결해진다.하지만 연관관계를 너무 지나치게 사용하면 시스템 파악이 어려워지고 한 곳에서의 수정이 다른 곳까지 영향을 줄 수도 있으므로 여러 부분을 고민하며 연관관계 사용 여부를 결정해야 한다.섹션 6. 생애 최초 배포 준비하기 배포란 무엇인가 필요한 프로그램(ex. spring, MySql..)이 설치된 전용 컴퓨터에 코드를 옮기고 실행하는 과정profile 설정하기똑같은 서버 코드를 local profile에서는 H2 DB로, dev profile에서는 MySQL DB를 사용하도록 설정할 수 있다.application.yml의 설정 값도 함께 변경해 주어야 함.   git과 githubgit: 코드를 쉽게 관리할 수 있도록 해주는 버전 관리 프로그램github: git으로 관리되는 프로젝트의 코드가 저장되는 저장소코드를 github 저장소에 저장하는 과정git add .: 모든 코드를 담는다.git commit -m "메시지": 파일들을 포장하고 적고 싶은 문장을 적는다.git push: 송장을 붙인 파일들을 github에 보낸다.EC2: Elastic Compute Cloud의 약자로, 탄력적으로 원격 컴퓨터를 사용할 수 있다는 의미.섹션 7. 생애 최초 배포하기리눅스 명령어mikdir 폴더이름 - 폴더를 만든다ls - 현재 위치에서 폴더나 파일을 확인한다ls -l - 폴더의 자세한 정보를 확인한다 접근권한 명령어가 표시된다. 이를 변경하는 명령어가 chmod다. cd 폴더이름 - 폴더 안에 들어간다.cd .. - 현재 위치에서 상위 폴더로 간다.pwd - 현재 위치를 확인한다. rmdir 폴더이름 - 비어있는 디렉토리를 제거할 수 있도록 한다.foreground와 backgroundforeground: 우리가 보고 있는 프로그램background: 우리가 보고 있지 않은데 실행 중인 프로그램EC2 접속을 종료해도 서버가 동작하게 하려면 서버가 background에서 동작할 수 있도록 명령어를 추가해야 한다.jar 파일 실행 명령어의 앞뒤로 nohup [명령어] &를 붙여준다.ex. nohup java -jar build/libs/library-app-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev &rm nohup.out - nohup.out 파일을 제거한다.nohup.out 파일을 확인하는 방법리눅스 편집기 vim을 활용: vi nohup.out 입력접속한 터미널에서 확인: cat nohup.out or tail -f nohup.outbackground로 동작하고 있는 서버 종료하기리눅스 작업 관리자 명령어 ps aux를 사용해 실행 프로그램 목록을 볼 수 있다. (*java 관련 프로그램만 보고 싶다면 ps aux | grep java)프로그램마다 고유한 번호가 있으므로 kill -9 번호를 입력하면 서버 프로그램이 종료된다.섹션 8. Spring Boot의 이모저모 Spring Boot와 관련된 여러가지 사항build.gradle:gradle을 이용해 프로젝트를 빌드하고 의존성을 관리하기 위해 작성한 파일Spring과 Spring Boot Spring Boot는 Spring에서 제공하는 편리한 기능을 사용하기 위해 필요한 설정을 Java의 어노테이션 기반으로 가능하게 하고, 기본적인 설정들은 모두 자동으로 해준다.Spring Boot의 starter로 의존성 관리가 쉬워졌고, starter 추가만으로 원하는 기술을 쉽게 도입할 수 있게 되었다. application.yml과 application.properties:스프링 설정에 활용된다. YAML 방법이 가독성이 좋다.lombok : getter나 생성자, setter, equals, toString 등을 자동으로 만들어준다.어노테이션 @Getter, @NoArgsConstructor, @RequiredArgsConstructor(final이 붙어 있어 필수로 값 필요한 변수들을 가지고 있는 생성자를 만든다), @Setter, @EqualsAndHashCode, @ToString 등이 있다.<3주차 학습 내용 회고>완성한 서버를 배포해 보는 경험을 처음 경험해 본 일주일이었다. 강의에서 제공된 완벽한 코드를 실행시킨 것 뿐이지만, 지금까지 했던 코드의 터미널 실행과는 또 다른 느낌의 기쁨을 느낄 수 있었다. 깃 허브는 사실 아직도 잘 모르겠지만, 첫 시작을 했으니 다음에 사용할 때는 조금 더 여유롭게 사용할 수 있을 것 같다.연관관계를 따져보는 내용은 디비 수업에서 배웠던 것의 연장선에 있는 듯한데, 비슷하면서도 개념이 완전히 같지는 않아서 실제로 개발할 때 공부가 더 필요할 부분인 듯하다.본 강의 내용은 이번 주로 드디어 끝이 났다. 아직 남은 부분이 있긴 하지만, 이렇게 빠듯한 일정으로 강의를 다 수강해 본 게 얼마 만 인지 모르겠다. 남은 내용들도 잘 챙겨가서 다음 단계 공부에 잘 활용해 보고 싶다.  <미션>과제6API 3단 분리, Repository 분리하기API 분리는 전에 해두었던 것을 좀 더 간결하고 가독성 좋게 만드는 방식으로 만들었다.Repository의 경우 원래 만든 Repository의 볼륨이 상대적으로 컸기에 잘못 분리하면 에러 파티가 날 수도 있겠다 싶어서 살짝 부담스러웠지만 그래도 잘 분리할 수 있었다.과제7기존 코드를 JPA를 통해 동작하도록 변경하기왠지 모르겠지만 굉장히 오래 걸렸다. 첫 몇 시간은 아예 과제 주제를 착각해서 허송세월을 보내기도 했다. 차근차근 강의록을 다시 읽어보면서 내용을 과제에 적용하려고 했다.기존 코드는 쿼리를 직접 작성해야 했기에 문자열 " "안에 작성한다는 것이 매우 부담스러웠는데, 훨씬 간편해졌다. 다른 분들의 코드도 몇 개 참고했는데 JPA에서 제공하는 기능으로 쿼리를 원하는 대로 작성해서 데이터를 뽑아낸 경우도 있었다. 그런데 복잡해 보이기도 하고 나는 강의에서 다뤄진 내용으로 해보고 싶어서 기본 메소드를 사용했다. 나중에 필요할 때가 분명 있을 테니 그 때 활용해 보기로 했다.앞선 과제를 계속해서 더 간결하고 편리하게 사용할 수 있는 쪽으로 개선하는 과제가 많았는데, 이 과제들이 아니었다면 난 곧장 JPA만을 이용해 코드를 짰을 것이다.(아마도) 차근차근 순서대로 같은 기능을 하는 다른 코드들을 시간을 들여 작성해 보는 시간들이 매우 소중하다는 걸 느낀 과제였다.

인프런워밍업클럽스터디

[인프런 워밍업 클럽 스터디] BE 스터디 1기 2주차 발자국

색션 6깃 연결하기=> https://www.notion.so/Git-f90d207e88af4eb28dad3a799cb96713AWS 연결 방법  Git Bash로 연결chmod 400 <pem주소> => 사용할 수 있게 권한 부여ssh -i <pem주소> ec2-user@<빌린 AWS 주소> => 접속시도성공시AWS 콘솔로 연결섹션 7가장 기초적인 Linux 명력어mkdir => 폴더를 만드는 명령어ls => 현재 위치에서 폴더나 파일을 확인하는 명령어ls -l => 조금 더 자세한 정보를 확인하는 명령어cd => 폴더 안으로 들어가는 명령어cd.. => 상위 폴더로 올라가는 명령어pwd => 현재 위치를 확인하는 명령어rmdir => 비어 있는 폴더(디렉토리)를 제거하는 명령어 sudo yum update => 패키지 관리프로그램을 최신화sudo => 관리자의 권한으로 실행yum => 리눅스 패키지 관리 프로그램 sudo yum install git => yum을 이용해 깃 설치 => sudo yum install git -y => 중간에 물어보지 않고 바로설치하고 싶을 때sudo yum install java-11-amazon-corretto -y java -version => 버전 확인 및 설치 확인 mysql 설치 이후엔 4주차에 이어서 과제과제 6=> https://www.notion.so/6-930d8e02b85244a6aaa3126a708633d8 과제 7=> https://www.notion.so/7-62fb6239437b4677a1374bd529cabd73 회고이번 주차는 조금 강의를 많이 듣지 못하였고 다음 주에 이어서 완강을 목표로 달리겠습니다. AWS에 연결하고 mysql 설치에서 에러가 발생하였는데 그 부분을 좀 더 정리해서 다음 주에 올리면 좋을거 같아서 적다가 지웠습니다. 배보하는 작업이 실질적으로 금액이 있는 부분이 이기에 좀 더 신경쓰며 작업해야 겠고 생소한 리눅스환경에서 하려고 하니 더 알아가야겠고 저 꼼꼼히 배워야겠다는 생각이 들었습니다.

백엔드인프런워밍엄스터디

이혜리

[인프런 워밍업 클럽 1기/BE] 3번째 발자국

section531강. 대출 기능 개발하기32강. 책 반납 기능 개발하기33강. 조금 더 객체지향적으로 개발할 수 없을까?34강. JPA 연관관계에 대한 추가적인 기능들35강. 책 대출/반납 기능 리팩토링과 지연 로딩1. 대출기능 개발 - 새로운 테이블 생성현재 user, book 2개의 테이블이 존재한다. 하지만 이 2개의 테이블 만으로는 대출 기능을 만들 수 없다. 새로운 테이블 user_loan_history 이 필요하다.create table user_loan_history ( id bigint auto_increment, user_id bigint, book_name varchar(255), is_return tinyint(1), primary key (id) )user_id : 어떤 유저가 빌렸는지 알 수 있도록, 유저의 id를 가지고 있도록 한다.is_return : 타입은 tinyint 인데, entity 객체의 필드 중 boolean에 매핑하게 되면, true인 경우 1, false인 경우 0이 저장된다.2. 책 반납 기능 개발 - @ManyToOne 으로 리팩토링  위의 HTTP Body 는 반납 request 의 요청 형식이다. 그런데 '책 대출' 과 '책 반납'의 api body가 똑같다. 이때 똑같더라도 별개의 class로 작성하는 것이 좋다. 두 기능 중 한 기능에 변화가 생겼을때, 유연하고 다른 부가적인 문제없이 대처할 수 있기 때문이다.아래는 반납 관련 DTO와 Controller, service 내용이다.DTOpublic class BookReturnRequest { private String userName; private String bookName; public BookReturnRequest(String userName, String bookName) { this.userName = userName; this.bookName = bookName; } public String getUserName() { return userName; } public String getBookName() { return bookName; } }Controller @PutMapping("/book/return") public void returnBook(@RequestBody BookReturnRequest request){ bookService.returnBook(request); }Service@Transactional public void returnBook(BookReturnRequest request) { User user = userRepository.findByName(request.getUserName()) .orElseThrow(IllegalArgumentException::new); UserLoanHistory history = userLoanHistoryRepository.findByUserIdAndBookName(user.get Id(), request.getBookName()) .orElseThrow(IllegalArgumentException::new); history.doReturn(); }위의 코드를 조금 더 객체지향적으로 개발하기 위해서JPA 연관관계를 활용할 수 있다.  이렇게 바꾸기 위해서는 UserLoanHistory와 User 가 서로 직접 알고 있어야 한다.UserLoanHistory의 userId 를 user로 변경해보자. @Entity public class UserLoanHistory { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; @JoinColumn(nullable = false) @ManyToOne private User user; private String bookName; private boolean isReturn; public Long getId() { return id; } public String getBookName() { return bookName; } public boolean isReturn() { return isReturn; } public UserLoanHistory(User user, String bookName) { this.user = user; this.bookName = bookName; this.isReturn = false; } public void doReturn(){ this.isReturn = true; } public UserLoanHistory() { } }@ManyToOne 은 N(나) : 1(너) 관계로 위에서는 N이 UserLoanHistory가 되고, 1이 User가 된다.User 클래스에서 1명의 유저는 N개의 UserLoanHistroy를 가지고 있을 수 있기 때문에, UserLoanHistroy를 List 형태로 가지고 있어야 한다.@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; @Column(nullable = false, length = 20, name = "name") //name varchar(20) private String name; @Column(nullable = false) private Integer age; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) //주인이 가진 필드 이름 // fetch = FetchType.LAZY private List<UserLoanHistory> userLoanHistories = new ArrayList<>(); protected User() { } public Long getId() { return id; } public String getName() { return name; } public int getAge() { return age; } public void updateName(String name){ this.name = name; } public User(String name, int age) { if (name == null || name.isEmpty()) throw new IllegalArgumentException(String.format("잘못된 name(%s)이 들어왔습니다.", name)); this.name = name; this.age = age; } public void loanBook(String bookName){ this.userLoanHistories.add(new UserLoanHistory(this, bookName)); } public void returnBook(String bookName){ UserLoanHistory targetHistroy = this.userLoanHistories.stream() .filter(history -> history.getBookName().equals(bookName)) .findFirst() .orElseThrow(IllegalArgumentException::new); targetHistroy.doReturn(); } }요 List에는 @OneToMany 를 붙여준다.이때 연관관계의 주인을 정해주어야 한다.  현재 user 테이블과 user_loan_history 테이블을 보면, user_loan_history는 user를 알고 있다. 반면 user는 user_loan_history 를 알지 못한다. 즉, 관계의 주도권을 user_loan_history 가 가지고 있는 것이다.테이블에서는 이를 알 수 있지만,JPA 에서는 모르는 상태이니 mappedBy 옵션을 달아주어 이제 알려주자.user가 주인이 아니므로, @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) //주인이 가진 필드 이름 // fetch = FetchType.LAZY private List<UserLoanHistory> userLoanHistories = new ArrayList<>();이렇게 하여 user 와 userLoanHistory가 서로를 알 수 있도록 하였다. 하지만, 여전히 BookService는 User와 UserLoanHistory를 각자 다루고 있다. 온전히 협력하지 못하므로 이를 수정해보자.+ @JoinColumn 은 연관관계의 주인 클래스에서 사용할 수 있다. Service 코드에서 UserLoanHistory를 직접 사용하지 않고, User 를 통해 대출 기록을 저장하도록 변경해보자.일단 BookService는 아래와 같이 변경했다. @Transactional public void loanBook(BookLoanRequest request) { //1. 책 정보를 가져온다. Book book = bookRepository.findByName(request.getBookName()) .orElseThrow(IllegalArgumentException::new); //2. 대출기록 정보를 확인해서 대출중인지 확인합니다. //3. 먄약에 확인했는데 대출중이라면 예외를 발생시킨다. if (userLoanHistoryRepository.existsByBookNameAndIsReturn(book.getName(), false)) //대여중임 throw new IllegalArgumentException("이미 대출되어 있는 책입니다."); //4. 유저 정보를 가져온다. User user = userRepository.findByName(request.getUserName()) .orElseThrow(IllegalArgumentException::new); user.loanBook(book.getName()); }위에서 UserLoanHistory 객체를 직접적으로 사용하지 않고 있다. user 객체의 함수인 loanBook를 불러오고 있는데 여기 메소드를 살펴보면, public void loanBook(String bookName){ this.userLoanHistories.add(new UserLoanHistory(this, bookName));User 의 필드중 userLoanHistories 에 UserLoanHistory 객체를 집어넣는다.이렇게 바꾸어서 User 와 UserLoanHistory 2개 객체가 서로 협력하도록 변경했다.section 6배포를 하기 위해서는 aws 의 ec2를 사용한다.ec2는 계속 돌아가는 전용 컴퓨터와 비슷한 개념이다. ec2 인스턴스를 생성한 후, 이에 ssh 연결하여 필요한 것들을 설치한 후, 프로젝트 build 후 실행을 background에서 하면 된다.회고강의를 90% 들은 시점에서 들은 생각은 이 강의와 인프런 워밍업 클럽 스터디를 하기 잘했다는 것이다. 이제는 기본적으로 api를 보낼 수 있으니, 앞으로는 시큐리티 부분과 테스트 코드 위주로 공부를 더 해나가려 한다.

백엔드백엔드aws배포jpa연관관계

미플

[인프런 워밍업 스터디 클럽] 1기 - 세 번째 발자국

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]3주 차는 이전까지 만들었던 애플리케이션을 배포하는 과정을 다뤘다. 무엇을 배웠나?11일 차: 기본적인 배포를 위한 준비- 배포란 무엇인가, 어떤 준비가 필요한가 - 스프링 서버 실행 시 설정을 코드 변경 없이 제어하는 방법 - Git, GitHub 차이, 기초적인 사용법 - AWS EC2란 무엇인가? 어떻게 사용하는가? 12일 차: AWS와 EC2 배포- EC2에 접속하는 방법과 리눅스 명령어 다루기 - 개발환경 구축 및 배포 - foreground, background의 차이 및 background 제어하기 - 도메인 이름 사용하기 13일 차: Spring Boot 설정, 버전업 이해하기 14일 차: 마무리 및 추가 꿀팁 영상 과제스프링 컨테이너와 계층화 아키텍처과일가게 API 구현하기 마무리지난주에는 걱정이 많았는데 이번주는 재밌게 보냈다. 과제를 구현하고 부족한 내용을 다시 보충하며 알아가는 과정에 시간이 사라졌다. 걱정이 많았는데 마무리가 즐겁게 끝나서 다행이다. 공식적인 스터디 일정은 이제 수료식만 남았다. 미니프로젝트를 계속 구현할지 혹은 또 다른 일정을 시작할지 생각해 봐야겠다. 

백엔드인프런워밍업클럽

winnercold

인프런 워밍업 클럽 BE 1기 - 3주차 발자국

학습한 내용영속성 컨텍스트(Persistence Context)테이블과 매핑된 Entity 객체를 관리/보관하는 역할을 한다.스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생성되고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다.영속성 컨텍스트의 특성들을 통해, 데이터의 일관성을 유지하고, 데이터베이스와의 통신 효율을 높일 수 있다.  기능변경 감지(Dirty Check)영속성 컨텍스트 안에서 불러와진 Entity 객체는 명시적으로 save하지 않더라도, 변경을 감지를 통해 자동으로 저장된다.쓰기 지연DB의 INSERT/UPDATE/DELETE에 대한 SQL을 즉시 보내는 것이 아니라, 트랜잭션이 COMMIT될 때 모아서 한 번만 날린다. 이렇게 하면 네트워크 비용과 데이터베이스 리소스 사용을 최소화하여 성능을 개선할 수 있다. 1차 캐싱영속성 컨텍스트는 조회된 Entity를 내부 캐시에 저장한다.같은 트랜잭션 내에서 동일한 Entity를 다시 조회할 때는 데이터베이스에 추가적인 쿼리를 실행하지 않고, 1차 캐시에서 직접 객체를 반환한다.이렇게 되면 데이터베이스 접근 횟수를 줄여 성능을 향상된다.캐싱된 객체는 완전히 동일하다.  지연 로딩(Lazy Loading)연결되어 있는 객체를 꼭 필요한 순간에만 가져온다.  연관관계(Association)두 개 이상의 테이블 또는 객체 간의 연결을 의미한다. 1:1 관계@OnnToOne 한 테이블의 레코드가 다른 테이블의 단 하나의 레코드와만 관련@JoinColumn 연관관계의 주인이 활용할 수 있는 어노테이션필드의 이름이나 null 여부, 유일성 여부, 업데이트 여부 등을 지정N:1 관계@ManyToOne 한 테이블의 한 레코드가 다른 테이블의 여러 레코드와 관련N쪽(Many)에 @ManyToOne을 설정하고 1쪽(One)에 @OneToMany를 설정하여 양방향 매핑을 구성양방향이 아닌 단방향으로 사용할 수 있다.연관관계의 주인은 @ManyToOne을 사용한 쪽으로 설정N:M 관계@ManyToMany한 테이블의 여러 레코드가 다른 테이블의 여러 레코드와 관련구조가 복잡하고, 테이블이 직관적으로 매핑되지 않아 사용하지 않는 것을 추천중간 엔티티(Join Table)를 두고 @OneToMany, @ManyToOne으로 해결하는 방법을 권장 연관관계의 주인JPA에서는 연관관계의 주인을 정해 FK를 관리한다.연관관계의 주인이 외래 키를 관리(등록, 수정)하며, 주인이 아닌 쪽은 읽기만 가능하다.연관관계의 주인이 아닌 쪽에 mappedBy 옵션을 통해 소유자를 지정한다. 효과객체 간의 관계를 명확히 정의하여 응집성을 높일 수 있다.연관관계의 주인을 기준으로 객체 간의 연결이 이루어지며, 이를 통해 엔티티 간의 관계를 보다 명확하게 이해할 수 있다.mappedBy 옵션을 사용하여 양방향 연관관계를 설정하면, 객체 간의 관계가 더욱 명시적으로 표현할 수 있다.연관관계의 주인의 setter 메서드를 사용하여 테이블 간의 연결이 이루어지므로, 데이터의 일관성을 보장할 수 있다.새로운 개발자가 코드를 이해하기 쉽고, 테스트 코드 작성이 용이해진다. 주의사항양방향 연관관계를 설정할 때에는 양쪽 엔티티 모두에게 관계를 설정해 주는게 좋다.연관관계의 주인을 올바르게 설정하지 않으면 데이터 일관성 문제가 발생할 수 있다.데이터 직렬화 시, 엔티티 간의 순환 참조가 발생할 수 있다.연관관계를 지나치게 사용하면 성능 저하가 발생할 수 있다.도메인 간의 복잡한 연결로 인해 시스템을 이해하기 어렵고, 영향도 파악에 어려움이 생겨 시스템의 유지보수가 어려워질 수 있다. cascade 옵션한 객체가 저장되거나 삭제될 때, 그 변경이 폭포처럼 흘러 연결되어 있는 객체도 함께 저장되거나 삭제되는 기능데이터가 삭제될 때 연결된 데이터까지 한 번에 삭제 된다. orphanRemoval 옵션orphan(고아): 관계가 끊어진 데이터removal: 제거객체간의 관계가 끊어진 데이터를 자동으로 제거하는 옵션 배포(Deploy)최종 사용자에게 SW를 전달하는 과정소프트웨어를 서버 같은 전용 컴퓨터에 설치하고 실행시키는 것을 포함한다.AWS(Amazon Web Service)같은 클라우드 서비스를 사용하면, 다양한 사양의 서버를 빌려 사용할 수 있다.개발 환경에서는 개발자의 로컬 컴퓨터에서 MySQL과 같은 데이터베이스를 사용할 수 있고, 배포 환경에서는 서버에 설치된 MySQL을 사용할 수 있다.   Profile소프트웨어를 실행할 때 환경에 따라 다른 설정을 적용하고 싶을 때 사용한다. 데이터베이스 설정, 외부 API 키 등의 환경 구성을 다르게 할 수 있다.  똑같은 서버 코드를 실행시키지만, local 이라는 profile을 입력하면, H2 DB를 사용하고, dev 라는 profile을 입력하면 MySQL DB를 사용하도록 구성할 수 있다.  H2 Database - 경량 Database로, 개발 단계에서 많이 사용한다. - 디스크가 아닌 메모리에 데이터를 저장할 수 있다. - 메모리 모드에서 실행할 경우, 서버를 재시작할 때마다 데이터가 초기화되므로, ddl-auto 옵션을 create로 설정하면 테이블에 대해 신경쓰지 않고 코드에만 집중할 수 있다.  Git코드를 쉽게 관리할 수 있도록 해주는 버전 관리 프로그램 버전 관리파일 변경 이력을 저장하여, 특정 시점의 버전으로 쉽게 돌아갈 수 있다.브랜치동일한 소스 코드에서 여러 개발자가 동시에 다른 작업을 할 수 있도록 지원한다. 기능별로 코드를 분리하고, 완성된 기능을 병합할 수 있다.협업여러 개발자가 동일한 프로젝트에 동시에 참여할 수 있고, 작업을 병합하는 과정에서 발생할 수 있는 충돌을 관리하고 해결할 수 있다.   GithubGit 으로 관리되는 프로젝트의 코드가 저장되는 저장소  사용 이유로컬 시스템에 문제가 발생하더라도 온라인 저장소에 코드를 관리할 수 있다.인터넷이 연결된 어디서나 코드에 접근할 수 있다.배포 할 때 활용할 수 있다.코드 관리 뿐만 아니라 Github Actions 같은 툴을 사용하면 변경사항을 자동으로 테스트하고 배포할 수 있다. 명령어git add 파일 이름 지정된 파일을 스테이징 영역(staging area)에 추가하여 Git이 관리하도록 한다. 모든 변경된 파일을 추가하려면 git add . 명령을 사용할 수 있다.git status 현재 워킹 디렉토리의 상태를 표시한다.어떤 파일이 수정되었거나 스테이징 영역에 추가되었는지, 아직 추적되지 않고 있는 파일이 있는지 확인할 수 있다.수정된 파일은 빨간색으로, 스테이징 영역에 추가된 파일은 초록색으로 표시된다.git commit -m "메시지"스테이징 영역에 추가된 변경 사항들을 로컬 저장소에 저장한다.커밋 메시지는 변경 사항을 설명하는 데 사용된다.git push로컬 저장소의 커밋을 원격 저장소에 업로드한다. 리눅스 명령어 mkdir: 폴더를 만드는 명령어ls: 현재 위치에서 폴더나 파일을 확인하는 명령어더 자세한 정보를 확인하려면 ls -l 명령을 사용할 수 있다.cd(change directory): 폴더 안으로 들어가는 명령어상위 폴더로 이동하려면 cd .. 명령을 사용할 수 있다. pwd(print working directory): 현재 위치 확인하는 명령어 rmdir: 특정 폴더(디렉토리) 제거하는 명령어  회고이번 주에는 JPA의 영속성 컨텍스트와 연관관계, 배포, Git/Github, 리눅스에 대해 학습했다. Git과 Github 같은 경우에는 이전부터 계속 사용해왔기 때문에 개념을 되짚고 넘어가는 데 큰 어려움은 없었다. 그러나 배포는 항상 조금 두렵게 느껴졌는데, 그 이유는 결과만 생각했기 때문이라는 것을 알 수 있었다. 이번 강의를 통해서 결국 하나의 클라우드 서비스일 뿐이고, 정확한 개념과 동작 원리를 이해한다면, 이런 문제들을 해결할 수 있다는 것을 깨달았다. 처음에는 Git, Github도 어려웠지만, 계속 사용하면서 조금씩 익숙해졌던 것 처럼 아직까지 어색한 클라우드 서비스, 리눅스 등 기술들을 지속적으로 학습하고 사용해보면서 익숙해지려고 노력해야겠다. 이번 주에는 작성한 미니 프로젝트에 대해 코드 리뷰를 받을 수 있었다. 코드 리뷰를 통해 테스트 코드 작성 시 다양한 기법을 고려하고, 로직을 구현할 때 데이터 양과 쿼리 수 등을 고려하는 것이 중요하다는 것을 배울 수 있었다. 스터디를 통해 지금까지 알고 있던 내용을 되짚어보고, 이해도를 높일 수 있었다. 또한, 개발자로서 코드를 작성할 때 고려해야 할 부분에 대해 배울 수 있는 시간이었다. 스터디는 이제 마무리되었지만, 배운 내용을 복습하고, 피드백을 바탕으로 미션을 수정할 예정이다. 또한, 미니 프로젝트를 4단계까지 진행하여 배포까지 완료해 봐야겠다.

백엔드