블로그

이삭토스트

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

강의 수강6일차 - 스프링 컨테이너의 의미와 사용 방법우리가 설정해줘야 하는 부분들이 설정을 안 해줬는데도 작동하는 신기한 현상을 볼 수 있다.물론 정답은 스프링 부트에서 제공해주는 매우 편리한 기능(스프링 빈, 컨테이너)에 의한거지만 (개발자는 반복을 싫어한다.)또한 기기 자체에서 모듈방식을 채택하는 경우가 많은데 그것과 유사하게 스프링 내에서는Repository를 어떤 전략을 취할 것인지 선택하여 많은 변경이 없이 구조를 효과적으로 바꾸게 된다.스프링 컨테이너가 이 역할을 해주고 컨테이너가 서비스를 대신 인스턴스화하고, 그때마다 레포지토리를 결정해주는데 이 방식 자체를 IoC라고 한다.@Configuration과 @Component등 스프링에서 자주 쓰이는 어노테이션에 대해서 배우게 되는 시간이었던 것 같다.7일차 - Spring Data JPA를 사용한 데이터베이스 조작SQL에서 벗어나 드디어 JPA를 본격적으로 사용하게 되는 부분이다.JPA를 사용하기 위한 사전 설정과 Entity 클래스, 그리고 JPA를 사용할 때 가장 중요한 ddl_auto 이 부분이 실무에서는 매우 중요하다고 생각한다. (실무 데이터에서 validate빼고 사용한다면 데이터가, 변형 또는 날라가버리니까)가끔 일반적인 SQL 명령어에서 정밀하게 다루고자 할 때 JPA를 확장시켜둔 Repository에JPA 쿼리를 이용하여 다양한 쿼리를 작성해줄 수 있다. (조금 더 정밀하게 작동시키려면 JPQL이 답)8일차 - 트랜잭션과 영속성 컨텍스트트랜잭션의 개념에 대해 알아가는 구간, 영속성 컨텍스트 특징 (변경 감지, 쓰기 지연, 1차 캐싱, 지연로딩, 동일성 보장) 9일차 - 조금 더 복잡한 기능을 API로 구성하기User에서 벗어나 대출과 반납이라는 개념을 들어간다. 새로운 테이블을 만들고 두 테이블을 연결해서 사용하는 방법을 알게 되었다.그리고 마지막으로 JPA에서 연관관계 매핑에 관한 떡밥을 남기시며 다음 주 월요일을 기대하게 된다.미션6일차 과제 - 4일차 과제 API 분리, Controller - Service - Repository 계층에 익숙해지기 기존코드를 JPA를 이용하여리팩토링을 해나가는 과정이다.문제1 에서는 컨트롤러가 너무 많은 역할을 하고 있어 Controller(HTTP 관련 역할) - Service(분기 처리, 로직) - Repository(DB와 접근 담당)로 나누는 과정이며,문제2는 Repository를 인터페이스화 해서 메모리에 저장하는 부분과 MySql 저장하는 것을 선택하게끔 하는 것이었다.문제1은 기존 코드를 Controller에서 Service로 우선 나누고 그 다음에 Service에서 DB와 접근에 관련된 부분을 분리하여 Repository에 나누는등 3개로 분리하였다. 이 과정에서 JdbcTemplate를 Repository만 접근하므로 코드의 가독성을 늘리기 위해Repository를 제외하고는 JdbcTemplate 관련 설정을 지워줬다.문제2는 DIP에 관련된 내용으로 스프링에서 클래스에 의존하는 것이 아니라 인터페이스에 의존하게끔 만들어 의존성 역전 원칙을 만들게 하기 위함이다. (+ IoC)7일차 과제 - JPA 연습 문제1은 6일차 과제에서 만든 과제를 JdbcTemplate에서 Spring Data JPA를 사용하는 환경으로 바꿔주는 과정이다.JPA를 처음 접할 때 이걸 왜 사용하고 어떻게 사용해야하는지 몰랐다. 오히려 SQL 내용을 배우고나서 JPA로 천천히 넘어오니 사용방법과 필요성을 뼈저리게 느꼈다. 부트캠프에서는 처음 접하는 내용을 바로 활용하는 입장에 있어서 이해를 하지 못하고 급하게 넘어왔던 부분이었는데 지금 JPA를 다시 공부하면 깊게 배우면서 조금 더 내 실력을 늘릴 수 있을 것 같다. 자연스럽게 테이블에 대한 개념도 배우면서 어떤 곳에서 어떤 코드를 짜고 그 의문점에 대해서 해소 할 수 있는 과제 였다.문제2는 JPA를 적용해 놨다면 이제 새로운 기능을 JPA를 이용하여 만드는 것이다.조금 의아한거라면 JPA를 깊게 배워갈 수록 SQL의 필요성을 느끼게 되는 것 같다.문제3은 2가지 쿼리를 받아서 2가지 갈래로 분기를 만들어 값을 리턴하는 기능을 만드는 것이었다.처음에 dto 설계를 잘 못해서 객체를 객체로 감싸서 List 자체만이 나오는 것이 아니라 dto에서 설정한 이름이 한번 더 포장되어서 결과가 반환되었다. API에서 디버그를 사용하면 요청이 보내졌을 때 변해지는 과정을 알 수 있으면 좋겠다. 아니면 내가 알지 못하는 사용법이 있는 것 같다.8일차 과제 - 미니프로젝트 도입아직은 특별하게 작업물을 만들지는 않았다. 5월 23일까지 제출해야하는 것이므로 프로젝트 전체적으로 크게 보고나서 설계하고 만들어가는 것도 늦지 않다고 생각을 하고, 강의를 들어가면서 구축해나가야 할 것 같다.본격적인 내용은 3주차 회고에서 나오게 될 것 같다.기존 구조에서 새로운 것을 추가하고 JPA를 다양하게 사용해보고 이제 연관관계 매핑이나 백엔드를 살짝 벗어나는 내용도 나오게 될 것 같다. 특히 배포 부분에 관련된 내용 같은데 이 부분은 아는게 많이 없어서 접해보는 걸로 만족하는 계기가 되지 않을까?

백엔드워밍업스터디BE1기회고록

eueun05

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

학습 내용1. 강의1일차: 스프링 컨테이너, 스프링 빈의 개념에 대해 학습하고, 왜 스프링 컨테이너가 좋은 코드와 관련이 있는지 알아봤다. 그리고 의존성 주입방법에 대해 학습했다.2일차: 기존의 문자열 SQL을 활용하는 방식의 한계점을 알아봤고, 이를 해결하기 위해 Spring Data JPA를 이용하는 방법에 대해 학습했다.3일차: 트랜잭션의 개념에 대해 배우고, @Transactional 어노테이션을 사용해 서비스 레이어의 메서드에서 트랜잭션이 보장될 수 있도록 적용해봤다. 그리고 영속성 컨텍스트에 대해 알아봤다.스프링에서 트랜잭션을 시작하면 영속성 컨텍스트가 생기고, 트랜잭션이 종료될 때 영속성 컨텍스트도 종료된다.영속성 컨텍스트 특징변경 감지(Dirty Check): 영속성 컨텍스트 안의 Entity는 변경을 감지해 자동으로 저장된다.쓰기 지연: SQL들을 트랜잭션이 commit될 때 한 번에 날린다.1차 캐싱: 영속성 컨텍스트 안의 Entity를 저장하여 같은 엔티티 조회 시 DB 대신 이미 저장되어 있는 내용에서 조회한다. 4일차: 이전까지 배운 내용들을 종합하여 책 생성, 대출, 반납 기능 API 개발 실습을 했다.5일차: JPA에서 연관관계를 매핑하는 방법에 대해 학습하고, 도메인 계층에 비즈니스 로직을 넣도록 기존의 대출, 반납 기능 코드를 리팩토링했다.2. 과제과제4: 과일정보관리 API 개발과제5: 코드 리팩토링 연습

이혜리

[인프런 워밍업 클럽 스터디1기] 백엔드 - 테스트코드(feat.4차과제)

과제4는 과일 가게에 입고된 과일에 대한 API 를 만드는 과제이다.이 과제로 테스트코드를 작성해보았다.새로운 과일을 등록하는 API (post) 를 테스트하는 부분과이미 등록된 과일을 팔아 saled 필드를 0으로 바꾸는 API (put) 을 테스트하는 부분으로 나누어 2개를 작성하였다.FruitControllerTest.javapackage com.group.libraryapp.controllerTest; import com.fasterxml.jackson.databind.ObjectMapper; import com.group.libraryapp.dto.fruit.FruitCreateRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import java.time.LocalDate; import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; @ExtendWith(SpringExtension.class) @SpringBootTest @AutoConfigureMockMvc public class FruitControllerTest { @Autowired MockMvc mockMvc; @Autowired ObjectMapper objectMapper; @Test @DisplayName("과일 새로 등록 테스트(성공)") public void saveFruitTest() throws Exception{ //given String name = "자두"; LocalDate date = LocalDate.parse("2024-05-12"); long price = 3000; FruitCreateRequest fruitCreateRequest = new FruitCreateRequest(name,date,price); String url = "http://localhost:8080" + "/api/v1/fruit"; //when final ResultActions resultActions = mockMvc.perform(post(url) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(fruitCreateRequest)) ).andDo(print()); //then resultActions .andExpect(status().isOk()); } @Test @DisplayName("과일 판매후 등록 테스트(성공)") public void saledFruit() throws Exception{ //given String url = "http://localhost:8080" + "/api/v1/fruit"; //when final ResultActions resultActions = mockMvc.perform(put(url) .queryParam("id","9") ).andDo(print()); //then resultActions .andExpect(status().isOk()); } }테스트코드에서는 실제 객체와 비슷하지만 테스트에 필요한 기능만 가지는 가짜 객체를 만들어서 애플리케이션 서버에 배포하지 않고도 스프링 MVC 동작을 재현할 수 있는 클래스를 사용한다.어지저찌 작성해서 테스트는 통과했다.테스트가 실패하는 경우와 나머지 api에 대해서도 추후 추가할 예정이다.아래 블로그들 내용을 참고해서 작성해보았는데아직 모르는게 너무 많은 것 같다.. https://shinsunyoung.tistory.com/52https://velog.io/@minseokangq/REST-API-CRUD 

백엔드테스트코드4차과제백엔드mock

김설하

인프런 워밍업 클럽 스터디 1기 FE | 2주차 발자국

일주일 동안의 학습 방식을 4L식으로 회고해본다.Liked (좋았던 점) + Learned (배운 점) : :중간 점검 : 여러가지 인사이트를 얻을 수 있었다. 능동적으로 생각하는 데에 방해가 될 것 같다는 우려를 하고 있어서 챗GPT의 사용을 어떻게 해야할 지 질문드렸는데 강사님께서 답변주신 내용이 도움이 되고 있다. 내용인즉 활용하는 데에 능숙해지는 것도 나의 능력이고 도움을 받아서 같이 만들 수도 있는 것이다. 다른 동료분들의 Q&A도 많은 도움이 된다. 프로젝트 Tip) 회원가입하고 로그인 후 메인 페이지로 접속 가능한 프로젝트들을 만드는 경우가 있는데, 최대한 게스트 로그인과 같은 접근 용이한 방법을 사용해서 프로젝트를 구성하는 것이 좋다. (회원가입-로그인이 필수면 유저가 메인 기능만 가볍게 열람하고 싶은 경우 많은 손이 들기 때문에...) 또한 기능 동작하는 영상을 짧고 굵게 잘 찍어둔다.과제 시간이 많이 걸린다면 시간이 많이 걸리는 이유를 분석하라 -> 나의 경우엔 CSS에서 은근 시간을 많이 쓰고 중간중간에 코드를 쪼개면서 리팩터링하거나 다른 방법이 없나 모색하는 데에 시간이 걸린다.코딩은 오픈북이라는 말씀강의 : React 시작 | React 파트에서 항상 들으면 까먹게 되고, 심지어 코드로 잘 활용하지 못하는 부분이 최적화라고 생각했다. 섹션3 최적화 파트를 집중해서 들었다.미션 : 아이콘 폰트나 CSS 작성에 도움이 되는 사이트 등 아는 방법들을 적극 활용해서 마음에 드는 UI로 과제를 만들고 있다. 또한 많은 과제들을 관리하기 위해서 Github Project, Milestones 를 활용하고 있다. 한 눈에 보이고 이슈와 연동이 되기도 하고 좋은 방법인 것 같다.  이런 느낌으로 열심히 CSS 구현.. ◠.◠ (근데이제 빠르게 하고싶다는 욕망이 스물스물 올라오는 것이다) Lacked (부족한 점) : 강의는 React 진도를 나가고 있지만. JS 과제인 Github Finder 과제를 수행하고 있다. 기능 위주로 구현해서 제출하면 된다는 걸 알고 있지만 UI도 욕심나고 ㅎㅎ,, 이것저것 챙기고 싶은 게 많아서 지연되는 경향이 있다. 욕심을 내면 한도 끝도 없다는 게 장점이자 단점인 것 같다. 또한해 놓은 미션이 있어도 바로 다음 미션에 착수하거나 다른 할 일들에 밀려서 발자국 작성이 느리다. 문서 작성이 장벽처럼 느껴지는데 문득 소스코드를 열람하는 수고를 들일 사람이 몇이나 있을까 하는 생각이 들었다. 정성들여 짜놓은 코드라면 README.md 작성을 통해 어필하는 것을 아끼지 말아야겠다. Longed For (바라는 점) : 스터디 끝까지 최대정진 오늘까지 JS 과제 완수한 후 발자국 작성, 다음주에는 강의 진도를 앞당겨 듣고 React 과제 선택과 집중하기React에서 상대적으로 취약한 TDD 파트 집중해서 듣기 / (개인적인 욕심) Docker로 실행하는 부분 깊게 이해하면서 듣기이번 주에는 시간을 많이 내지 못하였는데, 다음주는 유종의 미를 걷는 것에 집중하기 시간을 많이 할애하여 임하고 다음주가 지나면 '나의 작업 스타일은 어떤지' 파악이 된 상태였으면 좋겠다.      

프론트엔드인프런워밍업클럽

김 동현

인프런 워밍업 클럽 스터디 1기 FE - 2주차 발자국

2주차 후기사실은 복습이었던것 사실 예전에 6개월 국비지원수업으로 프론트과정을 들었던적이있었다. 그때 당시에는 나름 학원반에서 잘하는 편이었는데 이제 다시 해보니 이해도제대로 못하고 그냥 쓰고있었다. 지금은 자바도 공부하고 오니 코드 스타일에 대해서도 조금 더 명확해지고 객체나 메서드에 대한 개념도 더 쉽게 이해할수있게 된것같다 (역시 쓸모없는 공부는 없구나..)어쨋든 한번 경험해봤음에도 거의 반년이 넘게 리액트를 사용하지않다가 다시 공부하는것은 어려웠다. 기억나는 건 상태라는게 있고 이걸 잘 쓰고 관리하는게 리액트 성능에 아주 중요하다는것? 이번 주차를 하면서 간단한 투두리스트, 예산계산기, 넷플릭스 , 디즈니클론을 만들었는데 아직은 감이 잡힐듯 말듯한것같다. 다음 기술을 배우면서 이전기술이 보완되는 경험도있어서 다음 리덕스나 next를 공부하는 것도 기대가된다. 이번에 작성한 프로젝트 중에 괜찮았던건 뽑아서 백엔드를 따로 구성해서 포트폴리오로도 써볼까한다. 앞으로3주차는 리액트에서 중요한 기술들을 배우고 next.js도 배우게되는데 배우는게 많고 어려워진만큼 남은 시간동안 알차게써서 과제도 모두 완료할수있었으면 좋겠다. 리액트를 하고 스프링을 까먹는건아닐까 걱정이된다..ㅠ

프론트엔드

코파

인프런 워밍업 클럽 스터디 1기 FE | 2주차 발자국

목차React 세팅 Todo List 만들기 느낀점1. React 세팅Create-react-appnpm 또는 npx로 설치npm init react-app my-appnpx create-react-app my-appReact 애플리케이션을 만들기 위한 기본 파일 및 구조가 설정됨.npx 사용이 더 좋은 이유항상 최신 버전을 설치하므로 React를 설치한 후에도 다시 업데이트할 필요가 없음.프로젝트의 루트 디렉토리에 React를 설치하지 않고도 React 스크립트를 실행할 수 있음.프로젝트마다 React를 별도로 설치할 필요가 없음. 참고) 프로젝트 이름에 대문자 들어가면 오류 React 앱을 개발모드로 실행npm startsomething is already running on port 3000 에러Y를 누르면 다른 포트를 만들어서 동작하게 함. Vite 터미널에 해당 명령어를 입력해준다.npm create vite@latest프로젝트 이름을 지정해준다.Back-space 없이 그냥 입력하면 알아서 덮어 써진다.React를 선택한다.해당 명령어를 순서대로 입력하면 된다.SWC(Speedy Web Compiler)자바스크립트 프로젝트의 컴파일과 번들링 모두에 사용될 수 있는, Rust라는 언어로 제작된 빌드 툴말 그대로 매우 빠른 웹 컴파일러의 기능을 제공하는 툴  cd 입력하고 첫글자 누르고 tap 누르면 됨. 2. Todo List 만들기Todo List 만들 때 발생한 오류1) React에서 배열(리스트)를 렌더링할 때 각 항목에는 고유한 "key" prop이 있어야 함.해결 방법리스트로 렌더링되는 각 요소에 고유한 "key" prop을 추가하면 됨. 2) <input> 요소에 value prop을 썼지만 해당 요소에는 onChange 핸들러가 없음.이런 경우 사용자 입력에 대한 처리가 없는 상태로 값을 변경할 수 없다고 경고 문구를 띄움.해결 방법1) defaultValue prop 사용<input defaultValue={this.state.value} />2) onChange 핸들러 추가<input value={this.state.value} onChange={(e) => this.setState({ value: e.target.value })} /> 3) TypeScript에서 이벤트 핸들러의 매개변수 타입은 일반적으로 React.ChangeEvent를 사용함. import React, { ChangeEvent } from "react";  handleChange = (e: ChangeEvent<HTMLInputElement>) => { console.log(e); };3. 느낀점이번 한 주 동안 기록할 만한 일이 없었다.채용 공고를 깔짝이면서 둘러보는 데 쓸데없이 시간을 낭비하였고, 아무것도 하기 싫다는 생각으로 퍼질러서 정말 별 것도 하지 않았다. 하지만 이제는 강의를 열심히 듣고 과제를 완성해야겠다는 생각이 들었다. 현재의 상황에 집중하고 최선을 다해야하는 것이 맞는 것 같다.

웹 개발워밍업클럽발자국FE2주차

winnercold

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

학습한 내용 스프링 컨테이너서버가 시작될 때, 함께 시작되는 클래스들을 담는 거대한 공간스프링 빈을 등록하고 관리하는 역할을 한다.이를 통해 객체의 생성, 의존성 관리, 라이프사이클 관리 등을 처리한다.build.gradle 파일에 설정한 의존성들도 함께 스프링 빈으로 등록된다.스프링 빈을 등록하는 과정에서 필요한 의존성을 함께 설정해준다.  의존성(Dependency)하나의 요소가 다른 요소에게 영향을 받는 관계소프트웨어의 유연성과 유지보수성에 영향을 준다.  스프링 빈(Spring Bean)컨테이너 안에 다양한 클래스가 들어가게 된다.이때 다양한 정보도 함께 들어있고, 인스턴스화도 이루어진다.스프링 컨테이너 안으로 들어간 클래스를 스프링 빈이라고 한다.  등록 방법@Configuration: 클래스에 붙이는 어노테이션@Bean을 사용할 때 함께 사용해 주어야 한다.@Bean:메서드에 붙는 어노테이션메서드에서 반환되는 객체를 스프링 빈으로 등록한다.@Component: 주어진 클래스를 컴포넌트로 간주한다.컴포넌트로 간주된 클래스들은 스프링 서버가 뜰 때 자동으로 감지된다.@RestController, @Service, @Repository, @Configuration 어노테이션은 모두 @Component 어노테이션을 가지고 있다.  스프링 빈을 주입 받는 방법생성자를 이용해 주입받는 방식 가장 권장하는 방식이다. setter를 통해 주입받는 방식  필드에 직접 주입하는 방법기본적으로 권장되지 않는다.setter를 통해 다른 인스턴스로 교체해 동작에 문제가 생길 수 있다.필드에 바로 주입하게 되면 테스트가 어렵다. 제어의 역전(IoC, Inversion of Control)객체를 생성하는 과정에서 스프링 컨테이너가 필요한 의존성을 자동으로 선택해서 주입해준다.스프링 컨테이너가 필요한 의존성을 설정해주는 과정을 의존성 주입(DI, Dependency Injection) 이라고 한다.이렇게 하면 코드의 수정 없이 의존성을 변경할 수 있고, 애플리케이션의 유연성을 높인다.JPA(Java Persistence API)데이터를 영구적으로 보관하기 위해 Java 진영에서 정해진 규칙자바 진영에서 제공하는 ORM(Object-Relational Mapping) 기술의 표준 API영속성(Persistence): 서버가 재시작 되어도 **데이터는 영구적으로 저장**되는 속성API: 정해진 규칙 ORM(Object-Relational Mapping) - Object: 자바에서의 객체를 의미한다. - Relational: 관계형 데이터베이스의 테이블을 의미한다. - Mapping: 객체와 데이터를 매핑하는 작업을 의미한다.JPA는 단순히 API일 뿐이므로, 실제 동작을 위해서는 JPA 구현체가 필요하다.대표적으로 Hibernate가 있고, Hibernate는 내부적으로 JDBC를 사용하여 데이터베이스와 통신한다.영속성 컨텍스트(Persistence Context)테이블과 매핑된 Entity 객체를 관리/보관하는 역할을 한다.스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생성되고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다.영속성 컨텍스트의 특성들을 통해, 데이터의 일관성을 유지하고, 데이터베이스와의 통신 효율을 높일 수 있다. 기능변경 감지(Dirty Check)영속성 컨텍스트 안에서 불러와진 Entity 객체는 명시적으로 save하지 않더라도, 변경을 감지를 통해 자동으로 저장된다.쓰기 지연DB의 INSERT/UPDATE/DELETE에 대한 SQL을 즉시 보내는 것이 아니라, 트랜잭션이 COMMIT될 때 모아서 한 번만 날린다.이렇게 하면 네트워크 비용과 데이터베이스 리소스 사용을 최소화하여 성능을 개선할 수 있다.1차 캐싱영속성 컨텍스트는 조회된 Entity를 내부 캐시에 저장한다.같은 트랜잭션 내에서 동일한 Entity를 다시 조회할 때는 데이터베이스에 추가적인 쿼리를 실행하지 않고, 1차 캐시에서 직접 객체를 반환한다.이렇게 되면 데이터베이스 접근 횟수를 줄여 성능을 향상된다.캐싱된 객체는 완전히 동일하다.Spring Data JPA복잡한 JPA 코드를 쉽게 사용할 수 있도록 도와주는 스프링 프레임워크의 모듈스프링은 JpaRepository<Entity, ID>를 구현 받는 Repository에 대해 자동으로 SimpleJpaRepository 기능을 사용할 수 있게도 해 준다.save: 주어지는 객체를 저장하거나 업데이트 시켜준다.findAll: 주어지는 객체가 매핑된 테이블의 모든 데이터를 가져온다.findById: id를 기준으로 특정한 1개의 데이터를 가져온다.delete: 주어진 객체를 삭제한다.함수 이름만 작성하면, 알아서 SQL을 만들어 준다. 구절By 앞에 사용되는 구절find반환 타입은 객체가 될 수도 있고,Optional<타입>이 될 수도 있다.findAll쿼리의 결과물이 N개인 경우 사용한다.반환 타입 List<타입>exist쿼리 결과가 존재하는지 확인한다.반환 타입 booleancountSQL의 결과 개수를 센다.반환 타입 longBy 뒤에 사용되는 구절필드 이름이 들어간다.필드들은 And 또는 Or로 조합될 수 있다.필드 이름만 작성하면 동등 조건(=)으로 쿼리가 생성된다.외에 다양한 조건을 활용할 수 있다.GreaterThan : 초과GreaterThanEqual : 이상LessThan : 미만LessThanEqual : 이하Between : 사이에StartsWith : ~로 시작하는EndsWith : ~로 끝나는  회고이번주에는 스프링 컨테이너와 빈, 그리고 JPA에 대해 학습했다. 스프링은 기능을 쉽게 구현할 수 있도록 IoC와 DI 같이 기능을 제공한다. 그동안은 사용하는데 그쳤다면 이번에는 스프링 빈은 무엇이며 어떻게 등록하고, 어떻게 스프링에서 의존성 주입을 해 주는지 알 수 있었다. 이를 통해 스프링의 핵심 개념을 이해할 수 있었다.  또한, JDBC를 사용하면서 오타로 인해 런타임시에 예외가 발생한 적이 종종 있었지만 이번 JPA를 사용하면서 이런 예외를 줄일 수 있었다. Java 진영에서 어떤 목적을 가지고, JPA가 만들어 진건지, 어떻게 사용하고 실제 구현체는 무엇이면 어떻게 동작할 수 있는지 배울 수 있던 한 주였다.강의 내용처럼 앞으로도 공부하는데 있어서 기술의 사용법에 그치지 않고 기술의 등장 배경과 원리를 함께 이해한다면 한단계 더 성장 할 수 있을 것 같다. 

백엔드

이슬

인프런 워밍업 클럽 스터디 1기 FE - 2주차 발자국

The four Ls 🍀좋았던 것(Liked)성공적으로 진행된 부분이나 긍정적인 경험스터디 과제로 책 리스트 나열, 깃헙 파인더, 비밀번호 생성기, 타이핑 테스트 앱을 바닐라JS로 만들었고, 예산 계산기 앱을 React.js로 만들었다. 모든 과제를 클리어해보는 것이 목표 중 하나인데 이번 주에 총 5개의 과제를 완성시켜서 뿌듯했다. 배운 것(Learned)새로운 지식, 기술 또는 교훈이전에도 항상 헷갈리고 어떻게 사용해야할지 가늠이 되지않았던 최적화 부분을 여러번 학습했다.섹션3의 React.memo 를 이용한 렌더링 최적화,useCallback 을 이용한 함수 최적화,useMemo를 이용한 결과 값 최적화그 중에서 useCallback과 useMemo의 차이점은 알지만 활용하는 부분이 어렵다고 느껴졌는데, 이번 강의를 통해서 useCallback을 이해하며 과제에 적용해보았다. 부모 컴포넌트가 리렌더링될 때마다 함수가 재생성되면, 해당 함수가 자식 컴포넌트의 props로 전달되면서 자식 컴포넌트도 다시 리렌더링될 수 있다.따라서 useCallback을 사용하면 함수의 재생성을 방지하여 이러한 문제를 해결할 수 있고, 이를 통해 자식 컴포넌트의 불필요한 리렌더링을 최적화할 수 있다.부족했던 것(Lacked)부족한 정보, 기술 등 파악하고 개선할 수 있는 방안과제를 하느라 React.js강의의 Todo앱 class 컴포넌트에서 함수 컴포넌트로 변경하는 것과 드래그앤드랍 기능 부분을 실습해보지 못했는데, 추후에 실습해보려고 한다. (+ Hooks와 불변성 개념 복습해보기) 눈으로 봤을 때보다 직접 작성해보면서 느껴보는 것이 개인적으로 기억에 잘 남을 것 같다. 과제 기록을 하면서 그냥 GIF 이미지와 깃헙 링크만 올렸었는데, 작업하면서 생각했던 것들을 추가 작성해두었다. 큰 작업은 아니지만 어떤 점을 신경쓰면서 임했는지 다시 보면 좋을 듯 하다.바라는 것(Longed for)미래에 개선되었으면 하는 부분이나 바라는 상황앞으로 남은 강의도 집중해서 듣고, 남은 과제도 차근차근 해보도록 하겠다! 특히 경험해보지 않은 TDD 실습과 도커에 신경쓰며 들어보려고 한다. 화이팅!

웹 개발인프런워밍업클럽FE1기발자국

ddang

인프런 워밍업 클럽 스터디 1기 FE - 2주차 발자국

1주 동안 한 것Github Finder GitHub Finder 고민 사항처음에는 검색 창만 있었는데, 이후 깃헙 사용자를 검색하니 profile & repo list가 나타난다. 이 부분을 만족시키기 위하여 2가지 방법을 생각해보았다.사용자의 이름이 검색될 때 마다 삭제 후 생성.처음에는 profile & repo list을 display: none으로 설정 후, 나중에 변경. 예전에 비슷한 과제였던 음식 메뉴 앱에서는 a 방법으로 만들었었다. 그 때는 탭이 이동하여, 전체적인 내용이 변경되는 느낌에서 전체 페이지가 리렌더링 된다고 생각하였지만, 이번 과제에서는 탭의 이동이나 변경사항 없이 한 페이지에서 일어나는 동작이여서 b로 구현하기로 생각했다. 또한 a방법으로 구현하면 리렌더링 되는 부분의 요소가 많으므로 좀 더 비효율적이라고 생각했다.input 창에서 user 검색에 대한 결과를 보여주는 방식에도 고민했었다.input event로 즉각적인 검색 결과를 보여줌.onblur event나 onclick event로 결과를 보여줌. 처음에는 input으로 event를 적용하였을 경우, 중간에 불필요한 api 호출이나 리렌더링에 대한 생각때문에 꺼려졌다. 하지만 과제의 영상에서는 아마도 input을 event로 적용한 것 같았고, 또한 검색하는 페이지가 렌더링되는 걸 보여주는 것이 조금 더 사용자한테 지금 입력을 받고 반응 중이다라는 것을 보여주는 것 같아서 좋았다. 그리고 이 작은 페이지에서 일어나는 렌더링 반응이 많아 봤자 그렇게 크지 않을 거라 생각하기도 하여 결국 a 방안으로 가게 되었다. 그러나 지금 생각해보니, b 방안으로 가고 검색창에 입력이 들어오는 동안 보여줄 loading css 를 작성하는 것도 괜찮았을 거라는 생각이 든다. 워밍업 클럽이 끝나고 시간적 여유가 있을 때 수정해놔야겠다!회고이번주에 밀린 과제와 강의 내용을 다 들으려고 했다.하지만, 이번주 것까지 모두 밀리게 되었다...이렇게 된 이유는 휴식 시간을 생각 안 하고 일정을 계획하며, 모든 것을 할 수 있을 거라 믿었던 것 같다. 이번주에는 모든 과제를 다 하겠다는 생각은 버려두고 밀린 강의부터 듣어야 겠다.이번주도 화이팅!! 

웹 개발FE2주차회고

정진서

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

두 번째 걸음인프런 워밍업 클럽 1기 BE에서 자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지] 강의를 수강하며 작성하였다.  강의 학습Clean Code개발자는 요구사항을 구현하기 위해 코드를 작성하지만, 협업하는 경우 코드 작성 시간보다 코드를 읽는 시간이 더 많게 된다.따라서, 코드만 보고도 의미 파악이 가능하도록 Clean Code 리펙토링을 진행해야 한다.함수는 최대한 작게 만들고 한 가지 일만 수행클래스는 작아야 하며 하나의 책임만을 가짐그동안 작성하였던 Controller 코드를 3개의 역할로 나누어 보았다.API의 진입 지점으로써 HTTP Body를 객체로 변환 << Controller의 역할현재 유저가 있는지 확인하고 예외 처리 << Service의 역할SQL을 이용해 DB와의 통신 담당 << Repository의 역할Controller는 Service를 참조하고, Service는 Repository를 참조하기 때문에 불필요한 정보를 포함할 필요가 없도록 리펙토링하는 것도 중요하다. Spring Bean스프링 빈이란, 서버가 시작될 때 생성되는 거대한 컨테이너이다.컨테이너 안에는 여러 클래스가 들어갈 수 있으며, 다양한 정보와 함께 인스턴스화도 이루어진다.Controller는 @RestController, Service는 @Service, Repository는 @Repository를 입력해 스프링 빈으로 등록할 수 있다.JdbcTemplate같은 경우 build.gradle에 설정해놓은 Dependency(의존성)가 스프링 빈으로 미리 등록해 준다.스프링 빈을 이용하면 이렇듯 원래 역할이었던 Controller만이 JdbcTemplate를 참조하도록 만들 수 있다.  과제 수행5일차 과제 : Clean Code 적용하기Clean Code를 작성하는 방법을 조사하고 실제 코드에 적용시켜보았다.의미 있는 이름 사용하기함수는 작게, 한 가지 일만 하도록 만들기메서드 인수는 최대한 적게 받기중복되는 코드 제거하기주석 활용하기변하지 않거나, 일괄적으로 바꿔야 하는 숫자는 상수 처리하기  느낀 점이번 주는 자격증 시험 등 일이 많아 과제를 제때 제출하지 못한 것이 아쉬웠다.개발자들은 코드를 작성하는 것 만큼이나 코드를 읽는 일도 많으므로 단순히 돌아가는 코드가 아닌, 클린 코드 리펙토링을 통해 보기 쉬운 코드로 만드는 것의 중요성을 깨달았다.스프링 빈과 이를 등록하기 위한 어노테이션은 코드를 구현하면서 그 의미와 역할에 대해 자세하게 생각해보지 않았는데, 강의자님의 자세한 설명과 알기 쉬운 예시로 개념에 대해 알게 되었다. 이를 통해 프로그램에서 기능을 구현할 때에도 이 코드가 왜 쓰였는지 생각해보는 습관을 들이게 될 것 같다.

백엔드

정진서

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

첫 걸음인프런 워밍업 클럽 1기 BE에서 자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지] 강의를 수강하며 작성하였다.강의 학습HTTP와 APIHTTP란 다른 컴퓨터로 데이터를 보내기 위한 데이터 표준이다.API는 정해진 약속에 따라 특정 기능을 수행하는 코드이다. HTTP Method 중 하나인 GET은 쿼리를 통해 정보를 보낸 후 데이터를 요청한다.→ /add?number1=10&number2=20 Controller는 API가 실행되는 입구와 같다.@GetMapping("/add") public int addTwoNumbers(@RequestParam int number1, @RequestParam int number2) { return number1 + number2; } GET 방식에서 매개변수를 각각 하나씩 입력받을 때에는 @RequestParam을 사용하여 변수에 쿼리의 값을 넣는다.만약 매개변수가 많을 경우, DTO 객체로 만들어 관리한다.@Getter public class CalculatorAddRequest { private final int number1; private final int number2; public CalculatorAddRequest(int number1, int number2) { this.number1 = number1; this.number2 = number2; } }GET 방식의 DTO 객체는 반드시 생성자를 포함해야 한다. DTO 객체를 이용한 Controller는 다음과 같다.@GetMapping("/add") public int addTwoNumbers(CalculatorAddRequest request) { return request.getNumber1() + request.getNumber2(); }DTO를 이용할 때는 @RequestParam을 제거해야 하며 변수를 객체로 감싸 불러오기 때문에 getter를 사용해야 한다. 마찬가지로 HTTP Method인 POST는 Body를 통해 정보를 보낸다.객체 표기법인 JSON을 사용하고, List를 사용하거나 JSON 안에 JSON을 사용하는 것도 가능하다.POST 방식에서 DTO를 이용한 Controller는 다음과 같다.@PostMapping("/multiply") public int multiplyTwoNumbers(@RequestBody CalculatorMultiplyRequest request) { return request.getNumber1() * request.getNumber2(); } @RequestBody를 사용하여 HTTP Body로 들어오는 JSON을 DTO 객체 형태로 변환한다.GET 요청의 @RequestParam과는 달리 DTO 객체를 사용해도 Annotaion을 생략할 수 없다. GET 요청과 달리 POST 요청은 생성자가 필요하지 않다. Domain(Entity)와 DTO의 차이DTO는 계층 간 데이터 교환을 위해 사용된다. 반면, Domain은 DB 테이블과 매핑되어 데이터를 저장하거나 관리하는 실제 비즈니스 도메인을 표현한다. DTO는 단순히 어떤 데이터로 통신할 것인지 정의하고, 상세한 정의는 Domain에서 한다. Spring에서 Database 사용하기private final JdbcTemplate jdbcTemplate; public UserController(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @PostMapping("/user") public void saveUser(@RequestBody UserCreateRequest request) { String sql = "insert into user (name, age) values (?, ?)"; jdbcTemplate.update(sql, request.getName(), request.getAge()); }JdbcTemplate를 이용하면 Spring에 SQL을 전달할 수 있다.SQL문을 작성하여 문자열 변수로 저장하는데, 값이 들어갈 부분에 ?를 사용하면 데이터를 넣을 수 있다.  과제 수행1일차 과제 : JAVA Annotation어노테이션은 실제 데이터가 아닌 메타데이터로써 클래스와 메서드에 추가하여 다양한 기능을 부여한다.반복적인 코드 작성을 줄일 수 있어 코드량이 감소하고, 코드의 역할을 명확히 지정할 수 있어 유지보수가 용이하다는 장점이 있다.사용자가 원하는 기능을 수행하는 커스텀 어노테이션을 만드는 방법도 알아보았다. 2일차 과제 : GET & POST API날짜를 받는 API를 구현할 때, String으로 날짜를 받은 후 LocalDate로 변환하는 과정을 거쳤다.그러나, 스프링 부트 2버전에서는 @DateTimeFormat을 사용해 LocalDate를 바로 받을 수 있다고 한다.3버전대에서는 어노테이션 없이 LocalDate를 바로 받을 수 있다. 3일차 과제 : 람다식과 익명 클래스익명 클래스란 이미 정의되어 있는 부모 클래스의 자원을 일회성으로 재정의한 클래스이며, 자식 클래스를 정의할 필요 없이 객체화가 가능하다.람다란 자바의 인터페이스를 익명 클래스로 구현한 익명 구현 객체를 짧게 표현한 것이다. 메서드 타입과 이름, 매개변수 타입, 중괄호, return문을 생략하고 화살표 기호를 넣는다. 4일차 과제 : 과일 가게 API 만들기enum 타입을 통해 과일의 판매 여부를 ‘SOLD’, ‘NOT_SOLD’의 두 가지 상태로 구분하였다.COALESCE()를 사용하여 팔린 과일 혹은 팔리지 않은 과일이 존재하지 않을 경우, NULL이 아닌 0으로 표시되도록 하였다.쿼리의 결과가 하나이므로 queryForObject를 이용해 SQL의 결과를 직접 long 타입의 객체로 매핑하였다.  느낀 점Spring의 기초를 복습하면서 ‘이건 왜 이렇게 쓰일까’와 같은 질문을 던지며 천천히 학습할 수 있었다.특히, 인프런의 각 강의에 있는 질문 게시판을 활용하였다.강의를 들으며 의문이 든 부분들은 이미 선배 러너들이 질문을 했고, 강의자 분께서 자세하게 답변을 달아 주셨기 때문에 편하게 학습할 수 있었다. 매일 과제가 있지만 하루에 학습할 양을 안내해 주는 진도표가 존재하고, 하루치 공부 양이 그렇게 많지 않았기 때문에 오히려 꾸준하게 하루 공부를 진행할 수 있어 좋았다.일주일을 돌아보며 작성하는 발자국은 그동안 배운 내용을 정리하고, 느낀 점을 회고할 수 있어 좋은 방법인 것 같다.강의를 들으며 개조식으로 정리한 내용을 글로 풀어 쓰니 내가 얼만큼 이해하고 있는지 확인할 수도 있다.

백엔드워밍업클럽BE발자국1주차

잇택잇

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

출처: https://itaekit.tistory.com/13 들어가기 전에2주차를 마무리하였다. 나름대로 1주차를 충실히 보낸건지,2주차는 조금 더 수월하게 따라갈 수 있었다. 2주차에는 아래의 내용을 학습했다.스프링 컨테이너스프링 빈Spring Data JPA트랜잭션1주차의 내용에 깊이를 더했고,조금 더 프레임워크스러운 내용을 배웠다. Day 06 : 스프링 컨테이너의 의미와 사용 방법여섯째 날,드디어 스프링의 동작 원리에 대해 기본적인 내용을 학습할 수 있었다. 코드를 프로그래머가 직접 제어하는 라이브러리와 달리프레임워크는 프로그래머의 코드가 사용되는 입장이다보니,그 안에서 돌아가는 방식이 정말 궁금했다. Spring Container스프링 컨테이너는 스프링 프레임워크의 핵심 중 하나로 다음의 역할을 수행한다.스프링 빈 관리의존성 주입AOP트랜잭션 관리DI, IoCDI(Dependency Injection)은 '의존성 주입'으로,의존성이 발생하는 클래스에 대해 스프링 빈으로 등록되어있는 경우 스프링에 의해 자동 주입된다. IoC(Inversion Of Control)은 '제어 역전'으로,사용되는 대상을 프로그래머가 아닌 프레임워크가 결정하는 개념이다.Spring Bean스프링 컨테이너에 의해 생성되고 관리되는 객체를 의미한다. Spring Bean 등록 방법스프링 빈으로 등록하기 위해서는 아래의 방법 중 하나를 선택한다. @RestController, @Service, @Repository이전까지 사용하던 방법으로 사용자가 정의한 클래스에 직접 붙여 스프링 빈으로 등록한다. @Configuration, @Bean @Configuration과 @Bean은 세트다.  주로 외부 라이브러리, 프레임워크에서 사용하는 방법이다. @Component 스프링 빈이 되기 위해서는 반.드.시. 가져야하는 어노테이션 특정 클래스를 컴포넌트(스프링 빈)로 취급하기 위한 어노테이션으로,컴포넌트는 스프링 컨테이너의 감지 대상이 된다. @RestController, @Service, @Repository, @Configuration 모두 내부적으로@Component를 가지고 있다. 컨트롤러, 서비스, 레포지토리 이외의 클래스를 추가적으로 스프링 빈으로 등록하기 위해 사용하는 방법이다. Spring Bean 주입 방법스프링 빈에 대한 의존성을 갖는 경우,스프링 컨테이너에 의해 자동으로 DI된다. DI를 처리하기 위해서는 다음과 같은 방법 중 하나를 선택할 수 있다. 생성자를 이용한 주입 (권장) 근본 가장 권장되는 방법으로,특정 스프링 빈을 필드로 갖게 하고 생성자를 작성한다. 참고로 스프링 3이전에는 생성자 위에 @Autowired를 명시해야 했다. setter + @Autowried를 이용한 주입 벌써 불편 @Autowired는 스프링 빈을 찾아 연결해야 함을 전달한다. setter를 이용하는 경우,누군가가 setter를 사용할 수 있어 나도 모르는 사이에 문제가 발생할 수 있는 코드다. 필드에 @Autowired를 이용한 주입 작성하기 편해도 나중에 ㅅ 필드에 직접 주입하는 방법으로테스트가 어려워져 권장하지 않는다. @Qualifier @Qualifier(Spring Bean 이름) 스프링 빈을 매핑하여 사용해야하는 경우 사용하는 어노테이션정상적인 IoC를 위해 사용된다. 과제 리뷰첫번째는,지난 과제에 대해 Layered Architecture에 맞게 리팩토링하는 과제였다. Layerd Architecture로 구조를 잡으니,확실히 코드의 역할이 분명해졌고 유연하게 확장할 수 있게됐다. 두번째는,하나의 인터페이스를 구현하고 있는 여러개의 레포지토리 클래스 중 특정 레포지토리를 사용하기 위한 방법을 묻는 과제였다. 오늘 배운 @Qualifire로 매핑할 수도 있고,@Primary로 지정할 수도 있다. 짧은 회고조금씩 로우레벨로 들어가다보니 확실히 재밌다.그동안 궁금했던 내용에 대해 조금씩 알게 되니 속이 다 시원! 그러나 알아야 할 것들이 너무나 많다는 사실이 조금 섭섭하다. 아직 스프링 빈도 몇 개 안되고,각 레이어에서도 클래스가 한 개 씩 있다보니 아키텍쳐 관점에서의 힘을 충분하게 체감하지 못한 것 같다. Day 07 : Spring Data JPA를 이용한 DB 조작이전까지는 레포지토리 스프링 빈으로 DB와 통신했다.직접 SQL문을 작성했다. 과연 이것이 좋은 코드일까? Java는 객체지향 언어로 절차지향의 코드에서 벗어나야한다.그러나 SQL문을 그대로 작성하는 것 역시 절차지향 관점에 더 가깝다고 볼 수 있다. 직접 SQL을 사용할 때 단점쿼리를 문자열로 작성하게 되어 런타임에서만 오류를 알 수 있음특정 DBMS에 종속적인 코드를 짜게 됨DB의 Table과 코드의 Object는 서로 다른 패러다임으로 이루어져 있어 객체지향 활용이 어려움 JPA (Java Persistence API)Java 진영의 ORM(Object-Relational Mapping)으로 Hibernate를 구현체로 한다. 참고로,Hibernate의 내부는 JDBC로 동작한다. Spring Data JPA는 복잡한 JPA를 한번 더 Wrapping한 라이브러리다. Entity DB의 User tableUser Entity JPA의 객체로 간주되는 클래스를 일컫는다.DB Table과 완벽 호환되어 사용된다. Spring Data JPA를 이용한 쿼리 날리기JPA를 도입한 이유는,코드 레벨에서 DB와 스프링을 객체지향 관점으로 작성하기 위함이다. JPA를 통해 더이상 SQL문을 직접 작성하지 않고도,동일한 기능을 수행할 수 있게 된다. JpaRepository를 상속하는 Repository 생성 @Repository를 붙이지 않아도 스프링 빈으로 등록되는 마법 해당 레포지토리 인터페이스는 스프링에 의해 빈으로 등록되어 객체화된다.프로그래머는 추상화된 인터페이스를 갖고 활용만하면 된다. 아아... Spring Data JPA 너란 녀석은...(1) 기본적으로 다양한 SQL문에 대응하는 여러 연산을 지원한다.  아아... Spring Data JPA 너란 녀석은...(2) 필요에 따라 인터페이스 안에 추상메서드로 선언하는 것으로 기능을 구현할 수 있다. 과제 리뷰역시 바로 이전 과제의 연장선이다. MySQL로 직접 연결하여 사용한 코드를JPA로 리팩토링하는 문제였다. 사실 SQL에도 자신이 있어 크게 불편하지는 않았지만JPA가 손에 익으면 더 편해질 것 같았다. 특히 레포지토리 인터페이스에 새로운 메서드를 작성하는 것으로 손쉽게 SQL문을 그대로 구현할 수 있었다.조금 더 객체지향 코드에 가까워졌다. 그러나,과연 JPA로 복잡한 SQL문까지 완벽히 대체하는걸까? 라는 의문이 들기도 했다. 나중에 알게 되겠지. 짧은 회고처음엔 분명 겁을 먹었다. JPA...?ORM...?Hibernate...? 익숙하지 않아서,들어본 적 없어서 지레 겁을 먹고 배우기를 미뤘던 내용들이었다. 결국에는 일맥상통하는 개념이었다. 아마도,새로운 것을 배워나감에 있어 이런 기분은 계속 이어질 것 같다. 무엇을 배우더라도열린 마음으로 적극적으로 배워나가다보면,결국 익숙해지고다 알게 되는 것 같다.   Day 08 : 트랜잭션과 영속성 컨텍스트SQLD를 취득한 내게 트랜잭션은 꽤 익숙한 개념이다.트랜잭션에 대한 개념을 다시금 확인하고,스프링에서는 트랜잭션을 어떻게 구현하는지 알아보자. Transaction트랜잭션은 쪼갤 수 없는 업무의 최소 단위를 의미한다. 예를 들어,A 계좌에서 B 계좌로 송금이 되었다.그러나 전산 오류로 B 계좌는 돈이 들어오지 않았다. 어쨌거나 돈은 보냈으니,이는 정상적으로 동작했다고 볼 수 있는가? 당연히 아니다.본래 송금이라는 것은 상대방 계좌에 돈이 안전하게 들어가는 것 까지 모든 동작이 이뤄져야 한다. 이렇게 쪼갤 수 없는 업무의 단위를 트랜잭션이라고 한다. @Transactional 점점 프레임워크의 매력에 빠져간다...이렇게 쉽게 해주다니... 스프링은 트랜잭션을 허무할만큼 간단하게 구현할 수 있다.트랜잭션으로 처리할 메서드에 @Transactional을 붙이는 것으로 구현한다. 메서드의 모든 로직이 성공적으로 수행되면 commit 처리되며,동작 중 예외가 발생하는 경우 rollback처리된다. 영속성 컨텍스트 (Persistence Context)트랜잭션 수행 중 Entity 객체를 관리, 보관하는 역할을 수행한다.트랜잭션이 수행될 때 자동으로 생성되며,트랜잭션이 종료되면 함께 종료된다. 영속성 컨텍스트의 특징Dirty Check : Entity 변경 사항을 자동으로 감지하여 저장 (별도의 save가 필요없음)쓰기 지연 : 모든 SQL 요청을 한번에 묶어서 전송하여 DB 통신으로 발생하는 오버헤드를 줄임1차 캐싱 : id를 기준으로 DB로부터 읽어들인 Entity 객체를 캐싱하여 효율적인 입출력 처리 짧은 회고실제 서비스를 위한 재료를 많이 얻어간 날이다.어렵지 않으나 유익한 시간이기도했다. 단순 API 작성에서,JPA를 사용한 DB 처리와 트랜잭션을 고려한 API 작성이 가능하게 됐다. 프레임워크의 강력함에 대해 나날이 느끼고 있다.프레임워크의 내부 동작에 대해서는 여전히 많은 공부가 필요한 것도 사실이다. 사용법만 아는 코더가 되기보다,원리와 해결법 모두 이해한 엔지니어가 되도록 노력하자! Day 09 : 조금 더 복잡한 기능을 API로 구성하기새롭게 배운 내용 없어 정리는 생략! (개꿀) 짧은 회고아홉번째 날은 이제껏 배운 모든 내용을 활용하여 API를 작성하는 연습을 가졌다. 역시 프로그래밍은 내가 직접 만들어갈 때가 제일 재밌다. 세번째 Online Session : Test Code, Refactoring세번째 온라인 미팅은 정기 미팅이 아닌 깜짝 미팅이었다.참여자는 적었지만 배운 내용은 그 어느 때 보다 많았다. 테스트 코드 작성하는 방법많은 채용공고 우대사항 중 "TDD를 사랑하는 사람"이라는 내용을 많이 봤는데아직 내겐 먼 내용이라 생각해 배울 생각도 하지 못한 개념에 대해 맛 볼 수 있었다. 너무나 당연하지만,테스트 코드란 실제 작성한 코드의 구현을 테스트 하는 코드이다. 테스트 코드를 작성함으로써 얻을 수 있는 이점은,나중에 실제 코드를 변경하게 되더라도 동일한 결과를 내는 동일한 로직인지를 쉽게 알아낼 수 있다는 점이다. 작성하는 방법은,필요한 의존성을 설치하고 @Test를 붙이는 것으로 끝이다...public class CalculatorTest { @Test public void addTest() { // given : 데이터 준비 Calculator calculator = new Calculator(); // when : 테스트 메서드 호출 int result = calculator.operate(1, 5, '+'); // then : 값 검증 (예외 테스트 경우 when과 then 통합) assertThat(result).isEqualTo(8); } } 물론 좋은 테스트 코드를 작성하는 것은 지금 수준에서는 벽처럼 느껴졌으나그렇게 어렵지만은 않은 내용이겠구나라고 느낌을 가질 수 있던 것 만으로도 큰 수확이었다. 리팩토링리팩토링이라 하면 이전의 코드와 동일한 기능을 수행하되코드의 가독성을 개선하는 작업이다. 좋은 리팩토링을 하기 위해서는좋은 테스트 코드를 작성함으로써 준비할 수 있다고 한다. (아직 와닿지 않음) 2주차 후기스프링 부트에 대해 익었다고 표현할 수 있을 것 같다. 처음부터 프로젝트 설정에 대해 반복 연습을 하다보니,설정 관련 문제로 막히지 않아 낯설게만 느껴진 프레임워크가 점점 익숙해져간다. API 작성은 계속 연습하고 있고,그동안 배웠지만 흩어졌던 지식들이 하나로 합쳐지면서,"배운 건 어떻게든 돌아오는구나" 라고 느꼈다. 과제도 미리 다 끝내 놓으니 부담도 없다!우수 러너에 선정될지는 모르겠지만... 이미 너무나 많은 것을 배워가고 있단 생각에 이 과정에 참여한 것이 정말 잘한 선택이라고 생각한다.  멘토님 말씀으로,오늘까지 기본적인 재료들은 다 배웠고,앞으로는 조금 더 객체지향스러운 코드를 짜는 법을 배운다고 하신다. '좋은 코드'에 대한 고민을 게을리하지말자.지금부터 확실하게 연습해두자!

백엔드워밍업클럽스터디스프링최태현

성우

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

Section 3 정리클린 코드에 대해서 듣고 Controller를 3단 분리를 해보면서 가독성, 간결성 뿐만 아니라 특히 유지 보수 부분에서는 정말 사용이 필수적인 거 같다고 느꼈습니다.스프링 빈, 컨테이너와, Ioc에 대해서 배우고 나서 필요한 의존성이 자동을 설정된다는 점과, 컨테이너를 사용해서 Ioc를 구현 그리고 스프링 빈 주입을 통해 컨테이너와 클린 코드와 어떻게 연관이 있는지 이해할 수 있었습니다. Section 4 정리JPA를 배우고 나서 SQL을 작성하지 않고도 DB를 관리할 수 있다는 것을 알았고 yml 설정을 통해서 스프링에서 자동으로 해주는 것이 많구나라는 생각이 들었습니다.Spring Data JPA를 실습해 보면서 추상화된 다양한 메소드를 사용해 더 간편하게 쿼리를 보내는 법을 배웠습니다. 트랜잭션 부분에서 코드에서 어떻게 구현할까 궁금했었는데 스프링이 어노테이션 하나로 처리해 준다는 부분이 놀라웠습니다. 또한 영속성 컨텍스트의 능력이 개발자를 더욱 편리하게 해준다는 생각이 들었습니다.4일차 과제직접 dto , Controller를 구현해 봄으로써 jdbc에 대해 잘 이해하고 sql 문법도 익힐 수 있는 과제였던거 같다. https://velog.io/@sung515/%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%B0-BE-4%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C 5일차 과제클린 코드에 대해 배우고 이를 간단한 코드로 직접 구현해 보면서 앞으로도 코드를 짤때 개념을 숙지하면서 짜야겠다는 생각이 들었다.https://velog.io/@sung515/%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%B0-BE-5%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C 6일차 과제API를 3단 분리를 직접 해보면서 강의 때 조금 와닿지 않은 부분이 채워졌던 거 같고, 리포지토리 구현 부분에서도 어렵다고만 생각했는데 해보니까 코드가 훨씬 간결해지고 어노테이션으로 Ioc를 구현해보면서 클린 코드에 대해서 직접 깨달을 수 있던 거 같다.마무리처음에 들으면서도 어려운 부분(jdbc...부터) 은 몇 번이고 반복해서 들었던 거 같다. 특히 이리저리 클래스를 움직이면서 따라가는 것이 약간 버거웠지만 그래도 다 해놓고 나니까 보기도 편하고 이제 진짜 스프링을 통해서 개발을 한 것 같다. 이제 한 주밖에 남지 않았는데 열심히 해서 배포까지 성공적으로 마쳤으면 좋겠다~

백엔드백엔드워밍업클럽

이혜리

[인프런 워밍업 클럽 스터디1기] 백엔드 - 2주차 회고

2주차 정리 및 회고Section3. 역할의 분리와 스프링 컨테이너클린코드클린코드 : 함수는 최대한 작게 만들고 한 가지 일만 수행하는 것이 좋다. UserController.java 가api 진입점,현재 유저가 있는지 없는지 확인하고 예외처리,SQL을 사용해 실제 database와의 통신  을 담당하는 3가지 역할을 다 하고 있으므로, 클린코드가 아니다. 이러한 상태의 단점은 너무 큰 기능이기 때문에 테스트도 힘들다.종합적으로 유지보수성이 매우 떨어진다.따라서 Controller를 3단 분리하여 클린 코드로 작성하였다. 기존 api 진입점으로써 HTTP Body를 객체로 변환의 역할은 Controller 의 역할로 남겨두고,현재 유저가 있는지 없는지 확인하고 예외처리 의 역할은 Service가,SQL을 사용해 실제 database와의 통신 의 역할은 Repository가 담당한다. 스프링 컨테이너서버가 시작되면, 스프링 컨테이너(클래스 저장소)가 시작된다. 스프링 빈들(클래스들) 이 등록되고 - dependency 주입된, 사용자가 직접 설정해준 스프링 빈이 등록된다. 이때 필요한 의존성이 자동으로 설정된다.예를 들어, UserController에서 필요한 JdbcTemplate이 자동으로 생성자 내로 들어간다. 위와 같이 Book 관련 3단 분리 코드를 예시로 봤다.이때, 두 repository 중 어떤 것을 우선순위로 하는지는 @Primary @Qualifier 어노테이션을 사용하면 된다. Section4. 생애 최초 JPA 사용하기JPA 사용지금까지 작성한 코드를 살펴보면 아쉬운 몇 가지가 있다.repository 클래스 내에서 문자열로 쿼리를 작성하기 때문에 실수할 수 있고, 실수를 인지하는 시점이 느리다.특정 데이터베이스에 종속적이게 된다. 우리의 경우엔 MySql반복 작업이 많아진다.데이터베이스의 테이블과 객체의 매핑되는 패러다임이 다르다.따라서 JPA (Java Persistence API) 데이터를 영구적으로 보관하기 위해 java 진영에서 정해진 규칙을 사용한다.즉, 객체와 관계형 데이터베이스 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 돕는다.이를 사용하기 위해서는 Hibernate 가 필요하다.직접 매핑해보자유저 테이블에 대응되는 entity class 인 User.java 를 만들면 다음과 같이 코드가 수정된다.package com.group.libraryapp.domain; import org.springframework.lang.Nullable; import javax.persistence.*; @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; protected User() { } public User(String name, Integer age) { if (name == null || name.isBlank()){ throw new IllegalArgumentException(String.format("잘못된 name(%s)이 들어왔습니다.")); } this.name = name; this.age = age; } public String getName() { return name; } public Integer getAge() { return age; } public Long getId() { return id; } public void updateName(String name) { this.name = name; } } 또한 jpa 를 사용하기 위해서 application.yml 파일도 변경하자.hibernate 부분을 추가해준다.spring: 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😀 spring.jpa.hibrenate.ddl-auto : none스프링이 시작할 때 DB에 있는 테이블을 어떻게 처리할지에 대한 옵션이다. 현재 DB에 테이블이 잘 만들어져 있고, 미리 넣어둔 데이터도 있으므로 별 다른 조치를 하지 않는다. 자동으로 쿼리 날리기 (기본)repository 폴더 내에 UserRepository interface를 만들어준 뒤,JpaRepository 를 상속받게 해준다.package com.group.libraryapp.repository.user; import com.group.libraryapp.domain.User; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByName(String name); }UserService.java에서save, findAll, delete 등의 기본적인 쿼리들은 sql 문자열을 타이핑할 필요없이 자동으로날릴 수 있게 되었다.package com.group.libraryapp.service.user; import com.group.libraryapp.domain.User; import com.group.libraryapp.repository.user.UserRepository; import com.group.libraryapp.dto.User.request.UserCreateRequest; import com.group.libraryapp.dto.User.request.UserUpdateRequest; import com.group.libraryapp.dto.User.response.UserResponse; import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; @Service public class UserServiceV2 { private final UserRepository userRepository; public UserServiceV2(UserRepository userRepository) { this.userRepository = userRepository; } public void saveUser(UserCreateRequest request){ userRepository.save(new User(request.getName(),request.getAge())); }// INSERT SQL 이 자동으로 날라감. public List<UserResponse> getUser(){ return userRepository.findAll().stream() .map(UserResponse::new ) .collect(Collectors.toList()); } public void updateUser(UserUpdateRequest request){ User user = userRepository.findById(request.getId()) .orElseThrow(IllegalArgumentException::new); user.updateName(request.getName()); userRepository.save(user); } public void deleteUser(String name){ User user = userRepository.findByName(name) .orElseThrow(IllegalArgumentException::new); userRepository.delete(user); } }JpaRepository<Entity, ID>를 구현 받는 Repository에 대해 자동으로 기본적인 메소드(save, findAll) 를 사용할 수 있는 SimpleJpaRepository 기능을 사용할 수 있게 해준다. 그렇다면 다른 다양한 쿼리는 어떻게 작성할까?위 코드에서 삭제 기능인 deleteUser 메소드는userRepository.findByName 메소드를 사용하고 있다.이 메소드는 SimpleJpaRepository 기능이 아니라, 추가로 interface에 추상(?) 함수 정의만 해놓은 findByName 을 사용한 것이다. By 앞에는 다음과 같은 구절이 들어갈 수 있다. findfindAllexistscountBy 뒤에는 필드 이름이 들어가는데, And나 Or 로 조합될 수 있다. 또한 동등조건 (=) 외에도 다양한 조건을 사용할 수 있다.회고벌써 워밍업 클럽 스터디의 반이나 지났다. 확실히 이렇게 약간의 강제성을 부여하는 스터디가 나랑 잘 맞는 것 같다. 나 혼자서 공부했으면, 금방 흐지부지 되었을텐데 스터디 코치님들이 디스코드에 종종 올려주시는 글들이나, 다른 분들이 과제한 부분들을 읽으면서 배우는 점도 많은 것 같고, 완주러너의 혜택도 욕심이 나서 더욱 공부를 하게 되는 것 같다.

백엔드백엔드3단분리JPA2주차발자국

강호연

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

1. 강의 관련Class Component태어날 때부터 스마트폰이 있던 알파세대처럼, 프론트 입문하던 시기부터 react 훅이 있던 나는 class 컴포넌트에 대해 배우지 않았었다. 실제로 쓸 일도 없어서 크게 불편함은 없었다. 다만, 기술의 변천사를 이해하는 것은 현직자로서 중요한 덕목 중 하나라고 생각하기에 이번 기회에 공부를 했다. 구조나 돌아가는 원리는 이해할 수 있었지만, HOC등 좀 복잡한 개념들은 아직 자세히 이해를 못했다. 다시 복습해봐야한다.Next 12다음주부터 일정이 바빠서 강의를 땅겨 들었다. next의 경우도 마찬가지로 나는 처음 배울 떄부터 next 13버전 app router로 학습을 했기에 getStaticProps 같은 예전 방식을 몰랐는데 이번 기회에 알 수 있게 됐다.TDD워밍업 클럽을 듣기 전에 Jest, Cypress, StoryBook 등을 다루는 테스트 관련 강의(링크)를 들어서 test 방법을 알고 있었다. 다만, TDD 방법론으로 개발을 진행해 나가는 방법은 강의를 통해 배웠다. 실제로 개발을 진행해보니 링크 강의에서 들은 것 처럼 프론트엔드는 단위 테스트보다 e2e 테스트가 더 적합한 것 같다고 느꼇고, 처음부터 TDD로 진행하기 보단 기능 완성후에 e2e테스트를 진행하는 것이 바람직하지 않을까 싶다.Docker여기저기서 들어서 대충 뭔지만 알고 있었고, 워밍업 클럽 시작 전 가장 궁금했던 파트라 TDD와 같이 들었던 파트였다. 강의에서 진행하는 방식을 따라가다보니 docker 앱에 튜토리얼 항목이 있어서 따라가다보니 개념을 더 자세히 알 수 있었다. 아직 docker file을 작성하고 그런 것까진 못하지만 개념은 이해할 수 있게 됐다. 회고상술한 내용들을 제하면 대부분 알고 있던 내용이니 만큼 강의를 빠르게 넘기면서 복습했다. 다음주는 미션에 전념하여 역량을 키워나갈 수 있으면 좋겠다.  2. 미션 관련지난주 발자국을 월요일에 제출하는 바람에 이번 주가 짧게 느껴진다. 리액트 미션은 JS 미션과는 달리 패키지 메니져를 통해 라이브러리도 갖다 쓰면서 프로젝트가 커졌다. vite 템플릿을 통해 개발을 시작해서 초기 개발환경 세팅은 비교적 수훨하지만, 디렉토리 구조도 생각해야하고 컴포넌트별 역할도 나눠야해서 프론트엔드 개발자로서의 사고를 많이 한 한 주였다. 리액트 미션은 미션들이 기능면에선 크게 차이가 나지 않아서 모두 기능만 빠르게 구현하는 것보단 하고 싶은 걸 골라서 디테일에 신경을 쓰는 편이 좋을 것 같다고 생각이 들었다. 이 때문에 성과는 별로 없어 보이는 게 단점이지만, 성장은 할 수 있었다고 믿는다. 각 프로젝트별 상세는 각 게시물에서 확인바람. 미션 1 예산 관리 앱Github :https://github.com/KimPra2989/inflearn-warming-up-missions/tree/main/React/%EB%AF%B8%EC%85%98%201%20%EC%98%88%EC%82%B0%20%EA%B3%84%EC%82%B0%EA%B8%B0%20%EC%95%B1예산 계산기 미션이지만 기능면에서 똑같은 지출 내역으로 각색CRUD, deleteAll 구현react-toastify로 Toast UI 추가Button, Input 등 공통 컴포넌트 개발결과를 지출 항목 별 subTotal을 구할 수 있는 기능 추가.미션 3 포켓몬 도감 앱 (진행중...)다른 사람들 결과물을 보면 그냥 주어진 대로 생각 없이 개발하는 사람들이 많은 것 같다. 특히 이 프로젝트가 그런 경향성이 짙다고 느낀다. 나는 공장형 개발자를 지양하기에 생각을 해보며 진행하려한다. 회고리액트는 남이 하는 걸 보면 참 쉬운데, 막상 직접하려면 어려운 것 같다. 개념을 하나하나 설명하라면 할 수 있지만 그것들을 조합해서 한 단위의 큰 프로젝트로 만드는 과정이 특히 어렵게 느껴진다. 아마 지식대비 경험이 많이 부족해서 그런 것 같다. 경험을 쌓을 때다.

짙은

[인프런 워밍업 스터디 클럽 1기] 백엔드 2주차 회고록

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]를 수강하고인프런 워밍업 클럽에 참여하여 쓰는 회고록입니다.Plus 😍이번 주 내내 일정이 많았음에도 과제를 성실히 해나갈 수 있었던 건, 워밍업 클럽 덕분이라 생각한다! 특히 제출 예정 기간보다 빠르게 과제를 제출하시는 분들을 보며 자극을 많이 받는다. 나의 태도에 대한 반성은 덤Minus 🥶개인적인 일정이 많아 공부 시간을 확보하기 힘들었다. 이미 강의는 수강했기 때문에 제출일에 과제만 말아서 제출하는 방식으로 진행했는데, 추가 과제는 대부분 진행하지 못해 아쉬웠다. Interesting 🤔최근에 원온원 미팅을 진행하면서, 팀장님이 공부를 할 때 모든 것을 이해하려고 하지말고 빠른 속도로 훑어나가는걸 계속해서 반복하는 방법으로 공부 방법을 바꿔보는건 어떻겠냐고 조언을 주셨다. 백엔드 개발을 위해서는 하나하나를 아는 것도 중요하지만 전체적인 흐름을 알아야 하는 부분이 크다보니 실제 개발에 사용하기 힘들다고 생각되는 부분이 있었는데, 그렇게 공부 방법을 바꾸면 도움이 될 것 같았다. 실제로 팀장님은 백엔드 개발자이기도 하고. 이번 주에는 개인 시간을 조금 더 투자해서 강의를 더 많이 들을 수 있도록 해야겠다.

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

송세연

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

학습 내용리액트란Vue와 Angular는 프레임워크, 리액트는 라이브러리리액트가 라이브러리인 이유?리액트는 전적으로 UI를 렌더링하는 데 관여하기 때문.가상 돔: 실제 돔을 메모리에 복사해준 것기존 웹 앱의 경우 인터랙션이 발생할 때마다 렌더트리를 다시 생성하고 렌더링 과정을 다시 거치게 됨.인터랙션이 많이 일어나는 웹의 경우 불필요하게 DOM을 조작하는 비용이 너무 커진다.업데이트 전 후의 가상돔을 비교해 변경된 부분을 찾고(Diffing) 변경된 부분만 실제 돔에 적용한다.(reconciliation)webpack여러 파일의 자바스크립트 코드를 압축해 최적화할 수 있다.⇒ 로딩에 대한 네트워크 비용 절감모듈 단위의 개발이 가능, 가독성이 좋고 유지보수가 쉽다.babel: 최신 자바스크립트 문법을 지원하지 않는 브라우저를 위해 최신 자바스크립트 문법을 구형 브라우저에서도 돌 수 있도록 변환시켜주는 라이브러리.npx: 노드 패키지 실행을 도와주는 도구SPA(Single Page Application)리액트는 멀티페이지 어플리케이션이 아니라, 템플릿 하나를 이용해 동적으로 화면을 전환하는 SPA이다.JSX(Javascript Syntax eXtension)리액트에서 사용하는 자바스크립트의 확장 문법. 자바스크립트와 HTML 문법이 결합된 형태.원래 리액트에서 화면을 그리는 방식: React.createElement API 를 사용해 element를 생성하고 이 element를 in-memory에 저장한다. 그리고 RenderDOM.render() 함수를 사용해 실제 웹 브라우저에 그려준다.⇒불편하다!JSX로 작성한 코드는 babel에 의해 createElement로 변환된다.JSX Key 속성가상 돔을 구축할 때 key를 이용해서 어떤 부분이 변경되었는지를 인식할 수 있다.key로 index를 사용하는 것이 권장되지 않는 이유⇒리스트 요소가 추가되거나 제거되면 해당 리스트들의 key값도 바뀌게 되는데 새로 맨 앞에 들어온 요소가 그 전에 있던 index를 key값으로 가져서 원하는 대로 동작하지 않을 수 있다.React Hooks바벨을 이용해서 클래스 컴포넌트와 함수형 컴포넌트를 변환시키면 함수형 컴포넌트가 월등히 코드량이 적다.함수형 컴포넌트가 더 간결하고 성능도 좋다.HOC(Higher Order Component) 컴포넌트 : 화면에서 재사용 가능한 로직만을 분리해서 component로 만들고, 재사용 불가능한 UI와 같은 다른 부분들은 parameter로 받아서 처리하는 방법.⇒컴포넌트를 인자로 받아서 새로운 리액트 컴포넌트를 리턴하는 함수너무나 많은 HOC를 사용하면 wrapper가 너무 많아진다. React Hooks는 HOC 대신 Custom Hooks를 이용해 컴포넌트를 만들고 처리를 한다. 그로 인해 Wrapper가 많아지는 일을 방지할 수 있다.생명주기를 위해 componentDidMount, componentDidUpdate, componentWillUnmount를 사용했던 클래스 컴포넌트와 달리 Hooks는 useEffect 하나로 간단하게 생명주기를 처리할 수 있다.State와 Propsstate: 컴포넌트 내부에서 데이터를 전달할 때 사용. 변경 가능. State가 변하면 리렌더링된다.props: 부모 컴포넌트로부터 자식컴포넌트로 데이터를 전달할 때 사용. 변경 불가.react-beautiful-dnd: 리액트에서 드래그앤드랍 기능을 편하게 구현할 수 있게 해주는 모듈리액트에서 불변성이란: 값이나 상태를 변경할 수 없는 것.원시타입은 불변성을 가진다. 참조타입은 불변성이 지켜지지 않는다.불변성을 지켜야 하는 이유는 참조 타입에서 객체나 배열의 값이 변할 때 원본 데이터가 변경되어 이 원본 데이터를 참조하고 있는 다른 객체에서 예상치 못한 오류가 발생할 수 있어서이다.⇒프로그램의 복잡도 상승리액트에서 화면을 업데이트할 땐 값을 이전 값과 비교해서 변경된 사항을 확인한 후 업데이트하는데, 불변성이 지켜지지 않을 경우 비교할 대상인 이전 값도 함께 변경되기 때문에 불변성이 지켜져야 한다.불변성을 지키기 위해서는 값을 바꾸는 것이 아닌 새로운 배열을 생성해서 할당하는 방식으로 프로그래밍하면 된다.useCallback을 이용한 함수 최적화컴포넌트가 렌더링될 때 그 안에 있는 함수도 다시 생성되는데, 만약 함수가 자식컴포넌트에 props로 전달된다면 함수를 포함하고 있는 컴포넌트(부모 컴포넌트)가 리렌더링될 때마다 자식컴포넌트도 함수가 새롭게 만들어지기 때문에 계속 리렌더링하게 된다.styled components: javascript 파일 안에서 CSS를 처리할 수 있게 도와주는 라이브러리Iframe : HTML Inline Frame 요소로, inline frame의 약자.효과적으로 다른 HTML 페이지를 현재 페이지에 포함시키는 중첩된 브라우저.Iframe 요소를 이용하면 해당 웹 페이지 안에 어떠한 제한 없이 다른 페이지를 불러와서 삽입할 수 있다.scrollLeftElement.scrollLeft 속성은 요소의 콘텐츠가 왼쪽 가장자리에서 스크롤되는 픽셀 수를 가져오거나 설정한다. 학습 회고이번 주차동안 수강했던 강의 내용엔 내가 이미 알고 있던 것도 있었지만 잘 몰랐던 지식도 새롭게 접할 수 있어 좋았다.특히 리액트 강의의 섹션 3~4는 간단한 TODO 앱을 만들어보는 구현 파트와 여러 도구를 활용해 코드를 최적화하는 최적화 파트로 구성되어 있었는데, 어떻게 하면 내가 만든 앱의 성능을 최적화하고 수정하기 쉬운 코드로 만들 수 있을지를 고민해볼 수 있어서 좋았다.인프런 워밍업 클럽의 강의는 내가 학습할 수 있는 주제를 끊임없이 던져주는 것 같다. 인프런 워밍업 클럽이 끝난 뒤 내게 남은 과제는 이렇게 모아둔 학습 주제들에 심층적으로 파고들어 탄탄한 지식의 기반을 쌓는 일일 것이다.남은 한 주도 성실하게 임해서 잘 마무리 지을 수 있으면 좋겠다. 미션 해결 과정이번 주부터 리액트 미션을 시작했다. 레포를 어떻게 관리할까 고민하다가, 하나의 Home 페이지를 만들고 3개의 버튼을 두어 버튼을 클릭하면 각 미션의 결과물이 나오도록 만들기로 했다.이번 주에 완수한 미션은 ‘포켓몬 도감 앱’이다.기본적으로 https://pokeapi.co/에서 제공해주는 api를 사용해 포켓몬 데이터를 불러오고 화면에 띄우는 방식으로 구현했다.import axios from 'axios'; const PokedexInstance = axios.create({ baseURL: '<https://pokeapi.co/api/v2>', }); export default PokedexInstance; baseURL을 설정한 axios 객체를 만들고import PokedexInstance from './axios'; const findPokemons = async (targetOffset) => { try { const queryParams = new URLSearchParams({ limit: '20', offset: `${targetOffset}`, }); const res = await PokedexInstance.get(`/pokemon?${queryParams.toString()}`); const detailRes = await Promise.all( res.data.results.map((result) => { return PokedexInstance.get(result.url); }), ); return res.data.results.map((data, i) => { data = detailRes[i].data; return data; }); } catch (e) { console.error(e); throw e; } }; 포켓몬 목록을 불러오는 함수를 작성한다.포켓몬 목록을 조회할 때는 각 포켓몬의 디테일한 정보가 없고, 포켓몬의 정보를 얻을 수 있는 api 주소가 제공된다.그래서 다시 포켓몬별로 api를 일일이 호출해주어야 하는데, 이를 최적화하기 위해 Promise.all() 함수를 사용했다.Promise.all()을 사용하면 여러 개의 로직을 수행할 때 비동기적으로 수행하여 총 수행 시간을 절약할 수 있다.이 다음으로는 적절한 UI를 구성하고, 불러온 데이터를 화면에 띄우기만 하면 되었다. 미션 회고원래도 포켓몬을 좋아해서 리액트 첫 미션으로 포켓몬 도감 앱을 선택했는데, 생각보다 볼륨이 커서 오래 걸렸다.참고 영상에 나와있는 것과 유사하게 구현하려고 노력했는데, 포켓몬의 타입 별 색상을 맞추느라 삽질을 좀 했다. api에서 제공해주는 것이라 생각해서 계속 찾아보다가, 끝내 찾지 못해 하드코딩으로 색상을 적용해주었다. 아마 api로 제공되지 않는 정보인 것 같다.리액트 앱을 만들긴 정말 오랜만인데, 이번 미션을 통해 내 코딩 습관을 조금 돌아보게 된 것 같다.나는 보통 클린코드나 설계같은 걸 고려하지 않고 통으로 코드를 짜고, 기능 구현이 완료된 뒤에야 리팩토링을 하는 편이다. 작은 앱이라면 괜찮은데, 프로젝트의 규모가 커질수록 잘못된 설계로 인해 전체적인 코드 복잡도가 높아지고, 가독성도 나빠 좋지 못한 코드가 되는 것 같다.다음 미션부터는 컴포넌트 단위로 쪼개고 상태를 어떻게 관리할지를 천천히 설계해봐야겠다.

프론트엔드

박지원

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

섹션 3. 역할의 분리와 스프링 컨테이너스프링 컨테이너와 스프링 빈@RestController: 강의 중에 다루는 Controller 클래스를 스프링 빈으로 등록한다.스프링 빈: 스프링 컨테이너 안에 들어간 것. 클래스에 대한 다양한 정보 저장&인스턴스화가 이루어진다. 이때 필요한 의존성이 자동으로 설정되어 JdbcTemplate를 통한 인스턴스화가 가능하다.@Repository: Repository를 스프링 빈으로 등록한다.@Service: Service를 스프링 빈으로 등록한다.스프링 컨테이너의 필요성만약 필요에 따라 Repository를 구분하여 작성하게 된다면, Service 계층에서 어떤 Repository를 사용할지 수정해 주어야 한다. 큰 규모의 프로젝트에서는 담당하는 Repository를 변경하는 것이 번거롭기 때문에 Service 계층의 코드를 바꾸지 않고 Repository만을 변경할 방법을 고안해야 한다.이것에 대한 해결책이 스프링 컨테이너인 것.제어의 역전(IoC, Inversion of Control): 컨테이너가 필요한 Repository를 선택하고, Service를 만들어 주는 것.의존성 주입(Dependency Injection): Service를 만들 때 Repository 중 하나를 선택해 넣어주는 과정@Primary: 우선권 제어. 이 어노테이션이 붙은 Repository를 선택한다.스프링 빈을 다루는 법 스프링 빈으로 등록하기 @Service와 @Repository: 개발자가 만든 클래스를 스프링 빈으로 등록할 때 사용@Configuration와 @Bean: 외부 라이브러리나 프레임워크에 만들어져 있는 클래스를 스프링 빈으로 등록할 때 사용@Configuration : 클래스에 붙이는 어노테이션. @Bean을 사용할 때 함께 사용. @Bean : 메소드에 붙이는 어노테이션. 메소드에서 반환되는 객체를 스프링 빈에 등록.@Component: 컨트롤러, 서비스, 리포지토리 외의 추가적인 클래스를 스프링 빈으로 등록할 때 사용. 주어진 클래스를 컴포넌트로 간주한다. 스프링 서버가 사용될 때 자동으로 감지된다. 스프링 빈을 주입받기 생성자 이용하기: 가장 간단, 권장되는 방법ex. JdbcTemplate jdbcTemplatepublic UserRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }setter 사용하기: final 키워드 제거, 메소드에 @Autowired 붙이기필드에 직접 주입: 필드 위에 바로 @Autowired를 적어준다. @Qualifier: @Primary 어노테이션이 없는 상황에서 주입받는 쪽이 특정 스프링 빈을 선택함.@Primary와 @Qualifier를 모두 사용하고 있다면?: @Qualifier를 사용한다.섹션 4. 생애 최초 JPA 사용하기1-1. 문자열 SQL을 직접 사용하는 것의 한계문자열 작성에 실수가 있을 수 있고, 이를 인지하는 시점이 느림: 런타임 오류로 이어질 수 있다.특정 DB에 종속적: 특정 DB를 사용하다가 다른 종류의 DB로 바꿔야한다면 번거롭다.많은 반복작업: 많은 수의 쿼리를 작성해야 하고, SELECT 쿼리 시에는 필드 매핑이 번거롭다.DB의 테이블과 객체의 패러다임이 다르다: DB는 절차지향적이라면, 객체는 객체지향적.    1-2. 문자열 SQL의 한계에 대한 해결책JPA(Java Persistence API): 객체와 관계형 데이터베이스의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙(interface)Hibernate: JPA는 API이기 때문에 규칙일 뿐이고, 이 규칙대로 코드를 작성한 가장 유명한 프레임워크Spring Data JPA: SQL을 작성하지 않아도 쿼리가 나갈 수 있도록 자동으로 처리해준다. Spring Data JPA를 이용해 데이터를 생성, 조회, 수정, 삭제하기스프링은 JpaRepository<Entity, ID>를 구현 받는 Repository에 대해 자동으로 SimpleJpaRepository 기능을 사용할 수 있게 해 준다. SimpleJpaRepository에 있는 대표적인 메소드는 다음과 같다.save: 주어지는 객체를 저장하거나 업데이트findAll: 주어진 객체가 매핑된 테이블의 모든 데이터 가져오기findById: id를 기준으로 특정한 1개의 데이터 가져오기복잡한 JPA 코드를 직접 사용하는 게 아니라, 추상화된 기능으로써 사용하게 된다.Spring Data JPA를 이용해 다양한 쿼리 작성하기ex. 유저 삭제하기: 이름을 이용해 유저 존재 여부 확인/ 유저가 존재한다면 delete 쿼리 날리기UserRepository 인터페이스User: 이름을 기준으로 유저 데이터 조회해서 유저 객체 반환. 유저가 없다면 null이 반환됨findByName: 함수 이름만 작성하면, 알아서 select * from user where name = ?라는 SQL이 조립된다.find: 1개의 데이터를 가져옴.By: 뒤에 붙는 필드 이름으로 SELECT 쿼리의 WHERE 문이 작성된다 public interface UserRepository extends JpaRepository<User, Long> { User findByName(String name); }UserRepository: 기본적으로 들어있는 delete 메소드를 사용한다.public void deleteUser(String name) { User user = userRepository.findByName(name); if (user == null) { throw new IllegalArgumentException(); } userRepository.delete(user); }Spring Data JPA의 추가적인 쿼리 작성법By 앞find: 반환 타입은 객체 or Optional<타입>findAll: 쿼리의 결과물이 N개인 경우 사용 반환 타입은 List<타입> 이다.exists: 쿼리 결과가 존재하는지를 확인. 반환 타입은 boolean이다.count: SQL의 결과 개수를 센다. 반환 타입은 long이다.By 뒤: 필드 이름이 들어가고, 이들을 And나 Or로 조합할 수 있다. 동등 조건(=) 외 다양한 조건 활용도 가능함.findAllByNameOrAge 라 작성하게 되면, select * from user name = ? or age = ? 라는 쿼리가 나간다. 트랜잭션의 필요성과 스프링에서 트랜잭션을 제어하는 방법트랜잭션: 여러 SQL을 사용해야 할 때 한 번에 성공시키거나, 하나라도 실패하면 모두 실패시키는 기능commit: 트랜잭션 시작 후 사용된 SQL을 성공적으로 반영한다rollback: 트랜잭션 시작 후 사용된 SQL을 모두 취소한다.스프링에서 트랜잭션을 제어하는 방법: 대상 메소드에 @Transactional 어노테이션을 붙여준다.@Transactional 어노테이션데이터의 변경이 없고, 조회 기능만 있을 때는 @Transactional(readOnly = true)로 설정할 수도 있다.Unchecked Exception에 대해서만 롤백이 일어난다. (IOException과 같은 Checked Exception에 대해서는 일어나지 않음)영속성 컨텍스트: 테이블과 매핑된 Entity 객체를 관리/보관하는 역할 수행 스프링의 경우, 트랜잭션을 사용하면 영속성 컨텍스트가 생겨 나고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다.영속성 컨텍스트의 특징변경 감지 (Dirty Check): Entity는 명시적으로 save 해주지 않아도 알아서 변경을 감지하여 저장한다.쓰기 지연: 트랜잭션이 commit 되는 시점에 SQL을 모아서 한 번만 날린다.1차 캐싱: ID를 기준으로 Entity를 기억한다. 섹션 5. 책 요구사항 구현하기책 생성, 대출, 반납 API를 온전히 개발하며 지금까지 다루었던 모든 개념을 실습해 본 다.책 생성, 대출, 반납 API 개발하기 책 생성 API:book 테이블을 설계하고, Book 객체를 만들고, Repository, Service, Controller, DTO를 만든다. book 테이블 명세:create table book( id bigint auto_increment, name varchar(255), primary key (id) );책 대출 API: 어떤 유저가 어떤 책을 반납했는지 확인할 수 있는 user_loan_history 테이블을 추가로 만들고, 책이 대출되었는지 확인 후 대출되지 않아야 대출할 수 있다.user_loan_history 테이블 명세:create table user_loan_history ( id bigint auto_increment, user_id bigint, book_name varchar(255), /* 유저가 빌린 책을 대출 중인지, 반납 완료했는지 확인하는 필드이다. 이 필드에 0이 들어가 있으면 대출 중인 것이고, 1이 들어가 있으면 반납한 것이다. tinyint는 객체와 매핑되면 true인 경우 1이, false인 경우 0이 저장된다. */ is_return tinyint(1), primary key (id) )user_loan_history 테이블에 대응되는 객체 loanhistory 패키지와 Repository를 만든다.서비스 계층: 책 이름으로 책을 가져오고, 책이 없는 경우를 확인해 예외처리한다. Book 객체를 확인하고 대출 기록을 확인한다. 대출되지 않았다면 유저 객체를 가져오고 대출 기록을 저장한다.책 반납 API대출 기능에서 사용하는 HTTP Body 스펙이 유저 이름과 책 이름으로 동일하지만, 새로운 DTO를 만들어 주는 것이 추후 side-effect의 발생을 줄인다.유저 이름을 찾아 유저 객체를 받아오고 유저 아이디와 책 이름으로 대출 기록 객체를 받는다. 해당 책의 is_return 값을 '1'로 바꾼다.<2주차 학습 내용 회고>API 개발을 계속해서 더 객체지향적으로 발전시키는 법을 배웠다. 아직도 SQL을 API에 가져와 쓰는 것이 익숙하지는 않지만, 이번주 학습 내용에 포함된 JPA를 자유롭게 다룰 수 있으면 훨씬 보기 쉽고 안정적인 서버를 개발할 수 있을 것 같다.특히 책 대출 기능 개발 부분이 어려웠는데, exists 메소드를 작성할 때 exist로 오타를 내서 스프링 서버가 동작하지 않아 아찔했던 기억이 있다. 여러 개의 클래스, 패키지 등을 다루는 만큼 더 꼼꼼하게 작성하도록 주의를 기울여야겠다.이번주는 평일에 이런저런 일들이 많아 제시간에 강의를 듣지 못한 날이 있다. 다음주가 마지막인만큼 하루에 들어야 할 강의는 꼭 그 날 해결할 수 있도록 할 것이다.  <미션>과제4과일 가게 운영을 표현하는 API를 만들기3단 분리를 해서 만들었는데, 알고 보니 과제6이 관련된 과제였어서 조금 후회되었다. 그래도 작성한 코드가 완벽하게 분리된 것은 아니어서 다음 과제에서는 더 다듬어진 코드로 만들 예정이다.SQL문을 통해서는 테이블에서 필요한 값을 뽑아내는 것이지, SQL문을 통해 모든 것이 더 계산된 결과를 받는 것이 아니다. 필요한 계산은 Repository 내에서 일어나도록 코드를 작성한다.  과제5클린 코드로 리팩토링하기강의 중에서도 클린 코드에 대한 언급이 간략하게 있지만, 직접 구글링으로 클린 코드에 대해 자세히 정리한 글을 읽으며 다시 한번 복습했다. 주어진 과제 코드를 리팩토링하면서 앞서 읽은 클린 코드에 대한 지식을 적용해 보려고 노력했다. (변수명, 클래스명, 함수명 짓기와 함수의 역할 분리)과제 코드는 간단한 동작을 하는 것이기 때문에 클래스와 메인 함수를 같은 java 파일 내에서 작성했지만, 규모가 더 큰 프로젝트라면 지금 하고 있는 도서 관리 어플리케이션처럼 많은 패키지와 클래스로 나눠서 작성하여 더 클린하게 코드를 작성하도록 유의해야 한다.클린 코드에 대한 것은 어렴풋이 알고 있었던 것이지만 의식해서 '클린 코드로 만들어보자'고 작성한 것은 이번 과제가 처음이라 새로운 경험이었다. 앞으로도 클린 코드 작성 원칙을 잊지 않도록 유념해야겠다.  프로그래밍 과제가 많아 힘들었지만, 해결했을 때의 뿌듯함은 역시 프로그래밍 과제만 한 것이 없는 것 같다. 남은 과제들도 모두 잘 수행해 보겠다.

인프런워밍업클럽스터디