블로그

hmkim199

[워밍업 클럽 0기 BE] 3주차 발자국

학습 내용출처: 자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지] 3주차에서는 배포와 AWS, Git, Github, Spring Boot에 대해 알게 되었습니다. 익숙한 내용이 많아 미션을 하며 학습한 내용 위주로 작성하려 합니다.  미션https://github.com/hmkim199/spring-commute-app미니 프로젝트를 하며 강의와 실습, 과제를 통해 배웠던 것들을 스스로 적용해보고 고민해볼 수 있어서 유의미했습니다. @ManyToOne과 @OneToMany를 좀 더 이해하게 되었고 둘 다 써주기 보다는 무한 참조가 걸리는 것을 방지하기 위해 @ManyToOne 을 많이 쓴다는 것을 찾아보며 알게 되었습니다. 또한 fetch 방식은 LAZY로 설정해주어 불필요한 부하를 방지하는 방법도 알게 되었습니다. 현업에서는 왜래키를 잘 쓰지 않는데, 왜래키를 쓰지 않고 테이블간 연관 관계를 표시해주고 동작하도록 로직을 구현했습니다.LocalDate 타입을 Postman을 통해 Json으로 넘겨주는 것에서 오류가 있었는데, JsonFormat이라는 애노테이션을 이용해서 오류를 수정할 수 있었습니다. 다만 패턴에 따라 오류 발생 유무의 차이가 있어 이 부분은 차후 좀 더 알아보아야 할 것 같습니다.@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "Asia/Seoul") // 이렇게 오류 해결 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd", timezone = "Asia/Seoul") // 이렇게는 오류가 발생 회고 및 목표회사와 스터디를 병행하다 보니 어려운 점도 많았지만 피곤해도 강의를 들으며 헷갈렸던 개념들이 이해가 되기 시작하니 뿌듯하고 개운한 느낌이 들기도 했습니다. 설명을 너무 잘 해주셔서 도움이 많이 되었고 스터디가 끝나더라도 다시 강의를 들으면서 하나하나 따라해보고 과제나 미션들도 다시 해보면서 복습하고 싶습니다. 부족했던 부분을 스스로 보완하는 시간을 가지려고 합니다. 누군가에게 보여주기 위한 공부가 아닌 스스로 만족하기 위한 학습을 해나갈 수 있어 좋았습니다. 

백엔드SpringBootBackend

hmkim199

[워밍업 클럽 0기 BE] 2주차 발자국

학습 내용출처: 자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]섹션 4. 생애 최초 JPA 사용하기문자열 SQL을 직접 작성하는 것의 단점문자열을 작성하기 때문에 실수할 수 있고, 실수를 인지하는 시점이 느리다.특정 데이터베이스에 종속적이게 된다. 반복작업이 많아진다.데이터베이스의 테이블과 객체는 패러다임이 다르다. => 그래서 JPA가 등장! JPA란? Java Persistence API의 약자로 자바 진영의ORM(Object-Relational Mapping) 기술 표준을 의미.데이터를 영구적으로 보관하기 위해 Java 진영에서 정해진 규칙Spring Data JPA4. 영속성 컨텍스트테이블과 매핑된 Entity 객체를 관리/보관하는 역할을 수행스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생겨나고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료변경 감지 (Dirty Check): 영속성 컨텍스트 안에서 불러와진 Entity는명시적으로 save 를 해주지 않더라도 알아서 변경을 감지하여 저장쓰기 지연 : 트랜잭션이 commit 되는 시점에 SQL을 모아서 한 번만 수행1차 캐싱 : ID를 기준으로 Entity를 기억하는 기능지연 로딩: 필요한 순간에 연결되어 있는 객체를 가져온다. (fetch 옵션 LAZY, EAGER 중 @OneToMany는 LAZY가 기본)섹션 5. 책 요구사항 구현하기상대 테이블을 가리키는 테이블이 연관관계의 주인이다. 연관관계의 주인이 아닌 객체는 mappedBy 를 통해 주인에게 매여 있음을 표시해 주어야 한다.양쪽 모두 연관관계를 갖고 있을 때는 양쪽 모두 한 번에 맺어주는 게 좋다.cascade 옵션을 활용하면, 저장이나 삭제를 할 때 연관관계에 놓인 테이블까지 함께 저장 또는 삭제가 이루어진다.orphanRemoval 옵션을 활용하면, 연관관계가 끊어진 데이터를 자동으로 제거해 준다. 미션6일차7일차의존성 주입을 어디에서 어떻게 하는지를 강의를 들으며, 미션을 하면서 자연스럽게 익히게 되어서 좋았습니다. sql을 직접 사용하는 것과 JPA를 통한 변화가 어떤 차이가 있는지 코드 상으로 확인할 수 있어서 기존에 헷갈리고 불명확한 부분들이 또렷이 보여서 좋았습니다. 회고 및 목표이전에는 @OneToMany와 같은 애노테이션을 어디에 사용하는지, 왜 사용하는 지를 모르고 그냥 동작하게 만들기 위해서 썼는데 2주차 강의를 수강하면서 각 테이블끼리 객체지향적으로 연결시키면서 자연스럽게 이해할 수 있었던 것 같아서 의미있고 재밌게 느껴졌습니다. 영속성 컨텍스트도 어렵게 생각하다가 강의를 들으니 이해가 잘 되어서 좋았고 전반적인 스프링 부트 기술들에 대해 필요성과 관계성 등을 알게 되어 좋았습니다.3주차에는 미니 프로젝트를 하면서 배웠던 것들을 스스로 적용해보고 다시 복습하는 시간을 가지고 싶습니다.

백엔드SpringBootJAVABackend

hmkim199

[워밍업 클럽 0기 BE] 1주차 발자국

학습 내용출처: 자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지] 섹션 1. 생애 최초 API 만들기1. (웹을 통한) 컴퓨터 간의 통신은 HTTP 라는 표준화된 방식이 있다.2. HTTP 요청은 HTTP Method (GET, POST)와 Path(/portion)가 핵심이다.3. 요청에서 데이터를 전달하기 위한 2가지 방법은 쿼리와 바디이다.4. HTTP 응답은 상태 코드가 핵심이다.5. 클라이언트와 서버는 HTTP를 주고 받으며 기능을 동작하는데 이때 정해진 규칙을 API라고 한다.@RestController주어진 Class를 Controller로 등록한다. (Controller : API의 진입 지점)@GetMapping("/add")아래 함수를 HTTP Method가 GET이고 HTTP path가 /add인 API로 지정한다.@RequestParam주어지는 쿼리를 함수 파라미터에 넣는다. @PostMapping(”/multiply”)아래 함수를 HTTP Method가 POST이고 Path가 /multiply인 API로 지정한다.@RequestBodyHTTP Body로 들어오는 JSON을 요청 DTO 로 바꿔준다!HTTP body를 객체로 바꾸는 @RequestBody 를 사용하는 경우는, 생성자를 만들지않아도 괜찮다. API의 응답 결과를 JSON으로 반환하는 방법: Controller에서 그냥 객체를 반환하면, JSON으로 응답되며 객체에는 getter가 있어야 함-> getter 없는 객체 반환하면? 에러났음. (Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]) 섹션 2. 생애 최초 Database 조작하기CPU : 연산담당RAM : 메모리, 단기기억DISK : 장기기록우리가 서버를 실행시켜 API를 동작시키기까지 이 3가지 장치는 다음과 같은 역할을 수행1. 우리가 개발하고 있는 스프링 부트 서버는 DISK에 파일로 잠들어 있다.2. 서버를 실행시키면 DISK에 있는 코드 정보가 RAM으로 복사된다.3. API가 실행되면 ‘연산'이 수행되며, CPU와 RAM을 왔다 갔다 한다.4. 즉 POST API를 통해 생긴 유저 정보는 RAM에 쓰여 있다.5. 만약 서버가 종료되면 RAM에 있는 모든 정보가 사라진다.6. 때문에 다시 서버를 시작하면, 유저 정보가 없는 것이다!-> 서버에서는 Java에 있는 File 클래스를 사용해 직접 DISK에 접근할 수도 있지만, 이럴 때 바로 Database를 사용할 수 있다. 섹션 3. 역할의 분리와 스프링 컨테이너함수 하나로 모든 기능을 구현한다면?1. 그 함수를 동시에 여러 명이 수정할 수 없다.2. 그 함수를 읽고, 이해하는 것이 너무 어렵다.3. 그 함수의 어느 부분을 수정하더라도 함수 전체에 영향을 미칠 수 있기 때문에 함부로건들 수 없게 된다.4. 너무 큰 기능이기 때문에 테스트도 힘들다.5. 종합적으로 유지 보수성이 매우 떨어진다. 기존 컨트롤러에서 모든 기능을 구현했을 때의 컨트롤러 역할1. API의 진입 지점으로써 HTTP Body를 객체로 변환하고 있다.2. 현재 유저가 있는지, 없는지 등을 확인하고 예외 처리를 해준다.3. SQL을 사용해 실제 DB와의 통신을 담당한다.-> 각각을 Controller, Service, Repository로 분리! 미션1일차2일차3일차4일차 1주차 미션을 수행하면서는 학습한 것을 스스로 적용할 수 있도록 하는 것에 가장 집중하였습니다. 2일차 과제를 해결하며 Json 배열 받는 방법(List를 요청 DTO에서 필드로 갖기), Getter나 생성자가 없는 경우 발생하는 에러 등을 겪으면서 새로운 문제를 마주하고 해결하는 방법을 알게 되었습니다. 회고 및 목표회사와 함께 스터디를 병행하니 4-5일차 과제는 수행하지 못해서 아쉬웠습니다. 하지만 2주차 학습을 진행하며 틈틈이 1주차에 미흡했던 부분을 보완하고자 합니다.4일차 추가: 2024-02-26 

백엔드SpringBootJAVABackend

Shallow copy vs Deep copy

자바스크립트에서 기존에 존재하는 객체를 복사해서 새로운 무언가를 만들고 싶을 때가 있다. 하지만 그냥 새로운 변수를 선언해서 기존의 객체를 대입하면.. 새로운 변수를 변형했을 때 기존의 값까지 영향을 받아 상황에 따라 골치아파질 수 있다.. 이건 후술할 shallow copy가 된다.   Shallow copy는 원본의 값을 '참조'하는 형태로 복사한다. 따라서 복사한 값의 형태가 바뀌면 그 원본의 값도 영향을 받는다. Deep copy는 원본의 값을 정말 그 값만 복사해오고, 원본과는 완전히 별개의 객체가 된다. 이를 수정하거나 해도 원본의 값은 영향을 전혀 받지 않는다. ex) //JavaScript 환경에서.. obj = {a: 1, b: 2}; new_obj = obj; new_obj.a = 3; console.log(obj.a);    //3   JavaScript에서는 객체를 deep copy하기 위해 lodash의 ._clone()이나 ._cloneDeep()을 많이 이용한다. clone()은 객체를 deep copy하지만, 내부 객체까지는 deep copy하지 못한다. ex) obj = {a: 1, b: 2,  c: {2, 4}}; clone_obj= ._clone(obj); clone_obj.c === obj.c;    //true   때문에 내부 객체가 포함되어있다면 ._cloneDeep()을 쓴다. obj = {a: 1, b: 2,  c: {2, 4}}; clone_obj= ._cloneDeep(obj); clone_obj.c === obj.c;   //false   추가로 shallow copy는 deep copy에 비해 상대적으로 속도가 빠르다.   Shallow copy와 Deep copy를 상황에 따라 적절히 섞어서 쓰도록 하자.

백엔드JavaScriptBackend