블로그

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기] 백엔드 - 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 파일 내에서 작성했지만, 규모가 더 큰 프로젝트라면 지금 하고 있는 도서 관리 어플리케이션처럼 많은 패키지와 클래스로 나눠서 작성하여 더 클린하게 코드를 작성하도록 유의해야 한다.클린 코드에 대한 것은 어렴풋이 알고 있었던 것이지만 의식해서 '클린 코드로 만들어보자'고 작성한 것은 이번 과제가 처음이라 새로운 경험이었다. 앞으로도 클린 코드 작성 원칙을 잊지 않도록 유념해야겠다.  프로그래밍 과제가 많아 힘들었지만, 해결했을 때의 뿌듯함은 역시 프로그래밍 과제만 한 것이 없는 것 같다. 남은 과제들도 모두 잘 수행해 보겠다.

인프런워밍업클럽스터디

스미슈

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

인프런 워밍업 클럽1기 두번째 회고록 Day06 : 스프링 컨테이너의 의미와 사용 방법Day07 : Spring Data JPA를 사용한 데이터베이스 조작Day08 : 트랜잭션과 영속성 컨텍스트Day09 : 조금 더 복잡한 기능을 API로 구성하기Day10 : 객체지향과 JPA 연관관계  [Day06] 스프링 컨테이너의 의미와 사용 방법 스프링 컨테이너와 빈?스프링 컨테이너서버가 시작될 때 스프링 서버 내부에 만들어지는 컨테이너컨테이너 내부에 클래스가 들어가게 된다스프링 빈스프링 컨테이너 내부로 들어간 클래스빈을 식별할 수 있는 이름, 타입 등 다양한 정보가 저장되고 인스턴스화된다 스프링 컨테이너 사용 이유Service의 코드를 변경하지 않고 Repository만 갈아 끼울 수 있다제어의 역전(IoC; Inversion of Control)컨테이너가 대신 인스턴스화 하고, 그 때 알아서 결정해준다컨테이너가 Repository 구현체 중 하나를 선택해 Service를 만들어준다의존성 주입(DI; Dependency Injection)컨테이너가 Service를 인스턴스화 할 때 Repository 중 하나를 선택해 넣어주는 과정 스프링 빈 다루기@Configuration : 클래스에 붙이는 어노테이션, @Bean 과 함께 사용@Bean :메소드에 붙이는 어노테이션, 반환 객체를 스프링 빈에 등록@ComponentRestController, Service, Repository, Configuration은 모두 Component를 가짐해당 어노테이션이 붙은 클래스를 스프링 서버가 뜰 때 자동 감지@Primary : 의존성 주입에서 우선권을 결정하는 어노테이션@Qualifier의존성을 주입 받는 쪽에서 특정 스프링 빈을 선택할 수 있도록 한다스프링 빈을 사용하는 쪽/등록하는 쪽 모두 사용 가능 → Qualifier 어노테이션에 적어준 값이 같은 것끼리 연결된다@Qualifier 가 @Primary 보다 우선순위가 높다  [Day07] Spring Data JPA를 사용한 데이터베이스 조작 SQL 직접 작성의 한계점작성 실수를 인지하는 시점이 느리다(런타임에 발견된다)특정 데이터베이스에 종속적이다반복 작업테이블과 객체의 패러다임 차이이런 문제점을 해소하기 위해 등장한 것이 JPA (Java Persistence API) 이다 JPA자바 진영의 ORM객체와 관계형DB를 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영 규칙 HibernateJPA의 구현체 프레임워크 → JPA는 인터페이스이므로 실질적인 구현 코드가 필요하다내부적으로 JDBC를 사용 Spring Data JPA복잡한 JPA 코드를 스프링에서 쉽게 사용할 수 있도록 도와주는 라이브러리SQL을 작성하지 않아도 쿼리가 나갈 수 있도록 자동으로 처리해준다  [Day08] 트랜잭션과 영속성 컨텍스트 트랜잭션쪼갤 수 없는 업무의 최소 단위모든 SQL을 성공시키거나(commit) / 하나라도 실패하면 모두 실패시킨다(rollback)@Transactional 어노테이션을 대상 메서드에 붙여 적용한다 영속성 컨텍스트테이블과 매핑된 Entity 객체를 관리/보관하는 역할트랜잭션 사용 → 영속성 컨텍스트 생성트랜잭션 종료 → 영속성 컨텍스트 종료 영속성 컨텍스트의 능력변경 감지(Dirty Check) 영속성 컨텍스트 내의 Entity는 명시적 save가 없어도 변경을 감지해 자동으로 저장된다쓰기 지연(Lazy Loading)DB의 INSERT/UPDATE/DELETE SQL을 그때그때 날리지 않고 트랜잭션이 commit 될 때 모아서 한 번만 날린다통신 횟수가 줄어드는 이점1차 캐싱조회 요청이 올 때 우선 1차 캐시에서 데이터를 찾는다만약 1차 캐시에 데이터가 있으면 → DB를 찾아보지 않고 바로 반환만약 1차 캐시에 데이터가 없다면 → DB에서 데이터를 찾고 1차 캐시에 저장 후 반환  [Day09] 조금 더 복잡한 기능을 API로 구성하기 도서를 생성, 대출, 반납하는 API를 만들어보며 이전에 배운 것들을 익힐 수 있었다.book, user_loan_history 테이블 설계 및 추가테이블에 맞춰 객체를 만들어준다DTO, Controller, Service 구현 HTTP Body 스펙이 동일할 때, DTO를 새로 만들어야 할까?→ 새로 만드는 것이 좋다→ 한쪽의 기능에 변화가 생겼을 때 side-effect 없이 대처할 수 있기 때문!  [Day10] 객체지향과 JPA 연관관계 객체 지향적으로Service에서 UserLoanHistory에 접근하던 기존의 구조→ User 에서 UserLoanHistory를 가져와 처리하도록 바꾸고 싶다→ User와 UserLoanHistory는 서로를 알고 있어야 한다 연관 관계@ManyToOneN : 1 의 관계를 표현하기 위해 사용하는 어노테이션1명의 사람이 여러 개의 대출 기록을 가질 수 있다 → UserLoanHistory와 User 의 관계는 N : 1단방향으로만 활용 가능하다UserLoanHistory에서 User로 접근할 수 있다User에서 UserLoanHistory로 접근할 수 없다@OneToMany1 : N 의 관계를 표현하기 위해 사용하는 어노테이션mappedBy 옵션: 연관관계의 주인이 아님 → JPA에게 알려주기 위해 필요한 옵션@OneToOne1 : 1 의 관계를 표현하기 위해 사용하는 어노테이션@ManyToManyN : M 의 관계를 표현하기 위해 사용하는 어노테이션직관적이지 않으므로 사용하지 않는 것을 추천 연관관계의 주인객체가 연결되는 기준 → 연관관계의 주인을 기준으로 테이블이 연결된다Table을 보았을 때 관계의 주도권(FK)을 가지고 있는 쪽을 의미한다User와 UserLoanHistory의 테이블을 보면 UserLoanHistory가 FK를 가지고 있다연관관계의 주인은 UserLoanHistory연관 관계의 주인이 아닌 User에 mappedBy 옵션을 달아주어야 한다주인을 통해 객체를 이어줬을 때 즉시 반대쪽이 이어지는 것은 아니다(주의)하나의 setter 안에서 객체를 완전히 연결 시켜 해결할 수 있다 옵션cascadecascade = “폭포처럼 흐르다”객체가 저장되거나 삭제될 때, 연관 관계에 놓인 테이블까지 함께 저장되거나 삭제됨orphanRemovalorphan = “고아” + removal = “제거”연관관계가 끊어진 데이터를 자동으로 제거 지연 로딩영속성 컨텍스트의 4번째 능력이다예시: User와 UserLoanHistory는 연관관계이다User를 가져올 때, UserLoanHistory 를 필요할 때 가져온다fetch 옵션LAZY : 꼭 필요할 때 가져온다EAGER : 처음 데이터를 로딩할 때 바로 가져온다 제출 과제 [과제4] 과일 가게 API제출물 :https://warp-fig-837.notion.site/4-API-cdb1a87c4c1844bab92ed2af71f247e2?pvs=4API의 요청에 따라 MySQL DB에 데이터를 저장하고 데이터를 가져오는 것을 연습할 수 있었다. Controller에서 SQL을 작성해 jdbcTemplate로 전달하도록 구현된 상태이다. [과제5] 클린 코드 적용하기제출물 :https://warp-fig-837.notion.site/5-e53bf1459ff84cc594907426b1e359d9?pvs=4과제 5를 바탕으로 깜짝 라이브가 있었다. 라이브의 핵심 내용을 요약하자면 다음과 같다.리팩토링 전 가장 먼저 테스트 코드를 준비해야 한다테스트 코드를 작성하기 어려운 구조라면, 테스트 코드 작성을 위한 준비부터 해야 한다(Point!) 테스트를 작성하려고 노력하면 자연스럽게 좋은 구조가 나올 확률이 올라간다과제 5를 진행하며 테스트 코드에 대한 생각은 하지 않았기 때문에… 과제 5의 코드를 바탕으로 실제 테스트코드를 작성하고 리팩토링 하는 과정을 살펴보며 얻어가는 부분이 많았다. 특히 랜덤 부분을 테스트하기 위해 NumberGenerator라는 인터페이스를 생성하고 인터페이스를 inplements하는 RandomNumberGenerator를 만들었던 부분이 인상적이었다.

백엔드워밍업스터디

sun

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

[강의 내용 정리]Section3. 스프링 컨테이너와 스프링 빈스프링 빈서버 실행 → 서버 내부에 컨테이너가 만들어짐 → 컨테이너에 클래스가 들어감컨테이너의 역할 : 서로 필요한 관계에 있는 스프링 빈끼리 연결시킴스프링 컨테이너Service를 대신 인스턴스화 하고, 그 때 알아서 Repository를 결정하여 주입 : 제어의 역전어떤 Repository가 사용될 지는 Repository에서 결정 (사용할 것에 @Primary붙여주기)@Primary : 우선권을 결정하는 어노테이션Repository에서 인터페이스 구현@Configuration, @Bean, @Component, @Qualifier 등의 어노테이션을 통해 스프링 컨테이너 사용Section 4. JPA(Java Persistence API)SQL을 직접 작성하면 아쉬운 점SQL 문자열 작성에서 실수가 발생할 수 있으며, SQL 관련 오류가 컴파일 시점이 아닌 런타임 시점에 발견됨특정 데이터베이스에 종속적임반복 작업이 많아짐(CRUD를 모두 작성해야 함)데이터베이스의 테이블과 객체의 패러다임이 다름JPA객체와 관계형 DB의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙Spring Data JPA를 이용해 자동으로 쿼리 날리기Repository에서 JdbcTemplate를 사용하여 결과를 하나하나 매핑해 주는 방식이 아닌, 객체 간의 변환 진행트랜잭션쪼갤 수 없는 업무의 최소 단위 (모두 성공시키거나, 모두 실패시키거나)한 몸처럼 묶어서 저장스프링에서 트랜잭션 적용@Transactional (org.springframework.transaction.annotation)해당 함수가 실행될 때, start transaction;함수가 예외 없이 잘 끝나면, commit, 문제가 있다면 rollback역할변경 감지쓰기 지연1차 캐싱지연 로딩[과제 정리][과제 4] POST, PUT, GET API[과제 5] 클린 코드[회고]과제를 수행하며 더 가독성 있고 클린한 코드를 작성하기 위해 어떻게 하면 좋을지 고민했던 한 주였다. 다른 사람들이 작성한 코드도 살펴보면서 내 코드에서 부족한 점과 업그레이드할 점을 찾아보고 더 공부할 수 있었다. 과제 마감 후, 과제 수행 목적에 맞게 풀이했는지 확인하는 것도 많은 도움이 됐다.

백엔드워밍업클럽

sun 20일 전
이상현

인프런 워밍업 클럽 1기 FE 2주차

이번 주를 돌아보며 :동아리에서 나가는 아이디어톤 때문에 강의를 듣는데 시간을 내지 못했다. 틈을 내서 했어야했는데 생각보다 시간을 내지 못했던 것 같다. 강의를 진도표에 턱걸이에 맞춰 항상 듣는 것 같다. 진도표가 없었다면 더욱 진도를 맞추기 어려웠을 것 같다.중간 점검때 강사님의 질문 답변 시간이 앞으로의 목표나 궁금했던 것을 해결할 수 있는 좋은 시간이 되었다.다음 주면 끝나가는데 진도를 빨리 빼고 과제를 도전해보는 시간을 가져야겠다. 학습 내용 : JS 센션 8~9, 리액트 섹션 1 ~4 ReactAngular와 Vue 는 프레임워크이고 React는 라이브러리이다.프레임 워크는 어떠한 앱을 만들기 위해 필요한 대부분의 것을 가지고 있는 것.라이브러리는 어떠한 특정 기능을 모듈화 해놓은 것. 가상돔(Virtual Dom)웹페이지 빌드 과정(Critical Rendering Path)브라우저는 서버에서 페이지에 대한 HTML 응답을 받고 화면에 표시하기 전에 여러단계가 있다.웹 브라우저는 HTML 문서를 읽고, 스타일을 입히고, 뷰포트에 표시하는 과정이 있다.문제점 : 어떤 인터렉션에 의해 DOM에 변화가 발생하면 그때마다 RenderTree가 재생성되는데, 즉 모든 요소들의 스타일을 다시 계산하고, Layout, Paint 하데 되므로써 적은 변화로 인해 모든 DOM을 조작하게 되므로 불필요한 비용이 많이 들게 된다. ⇒ 가상돔 가상돔실제 DOM을 메모리에 복사하여 둔 것데이터가 바뀌면 가상돔에 렌더링되고 이전에 생긴 가상돔과 비교하여 바뀐 부분만 실제 돔에 적용시켜준다. 바뀐 부분을 찾는 과정을 Diffing 이라고 부르며, 바뀐 부분만 실제 돔에 적용시켜주는 것을 재조정(reconciliation)이라고 한다. React 기본 구조이름을 수정하면 안되는 파일public/index.html : 페이지 템플릿scr/index.js : 자바스크립트의 시작점src 폴더리액트와 관련된 소스 코드들을 작성하는 폴더.이곳에 JS 파일과 CSS 파일들을 넣으면 된다.Webpack은 src 폴더에 있는 파일만 보고, 이외의 폴더에 넣은 것은 Webpack에 의해 처리되지 않는다.Package.json 파일필요한 라이브러리와 버전이 명시되어 있다.리액트 앱 실행, 빌드, 테스트 등의 스크립트가 명시되어 있다.프로젝트에서 자주 실행되는 명령어를 scripts 에 작성해두면 명령어로 실행이 가능하다.소스 코드를 입력할때 문법이나 코드 포맷을 체크하는 것에 대해 설정을 명시할 수 있다. SPA(Single Page Application)특징옛날에는 각 페이지마다 html 문서파일을 만들어두고, 각 html 파일을 불러와 해당 페이지를 보여주는 형식인 MPA(Multi Page Application)를 많이 사용했다.하지만 SPA는 하나의 파일(index.html)의 id가 root인 div 태그 안에 요소들을 동적으로 바꿔주면서 하나의 html 파일로만 여러 페이지를 구성하는 형식이다. History APIHTML5 의 History API 를 사용해서 현재 페이지 내에서 화면이동이 일어나는 것 처럼 작동하게 해준다.History API는 React-Router-Dom 라는 라이브러리를 통해 사용한다.

shihy

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

안녕하세요, 오늘은 어떻게 이번 주 회고록을 남길까 하다가 일기+반성+다짐 느낌으로 가보려고 합니다. 우선, 저번 주에 일이 마감해야 하는 일이 몰려, 권장 진도를 모두 따라가지는 못했던 관계로, 이번 주에는 저번 주에 해야 됐던 강의를 듣고 과제를 진행했습니다. 백엔드 강의를 이전에도 듣긴 했지만, 아직 자바 문법과 코드 작성에 익숙하지 않은 터라 20분 강의를 1시간 동안 들으며 노션에 강사님 말씀과 코드를 정리해가며(물론 인텔리제이에서 실습도 했고요ㅎㅎ) 공부했답니다. 이번에 공부하면서 막혔던 부분은 크게 두 파트였는데요, 다른 분들이 보시면 왜 저기서...? 라고 생각하시겠지만, 아무것도 모르는 저에게는 꽤나 큰 일이었습니다. 첫 번째는 MySQL 연동 과정이었는데요, 분명히 (그날 기준) 어제도 되었던 연동이 갑자기 안 되는 일이 생겼습니다. User에 root, password에는 1234로 했는데 안 된다고 하더라고요... 그래서 패스워드도 안 넣어보고, 데이터베이스를 새로 추가하기도 하고, 정말 이것저것 했는데 안 되길래 그만 데이터베이스에 있는 모든 파일을 지워버리는 큰 실수를 하게 된 것입니다... 하하... 모든 파일을 지우니 당시에는 마음이 편해지고 이제 완전히 새로운 마음으로 데이터베이스를 만들어야지!라고 하며 만들었는데 이번에는 새로운 오류가 뜨더라고요..? 그래서 오류를 인터넷에 복붙해서 검색했더니 제가 그만 루트 파일(모든 권한이 있는 엄청나게 중요한 파일)을 함께 지웠더라고요... 하하... 그래서 root를 처음에는 복구하려고 여러 시도를 했는데, run configuration에 vm editor에 새로운 파일을 추가했는데 변화가 없었고, 인텔리제이 컨솔창에서 무언가를 하려고 해도 뭘 해야할지 모르겠고, MySQL CLI에 들어가서 뭘 쳐보려고 해도 비번만 입력해도 화면이 다운되었습니다. 그러다가 cmd에서 MySQL에 접근할 수 있다는 것이 떠올라 어떻게 해서 접근해서 블로그에 나와있던 대로 MySQL에서 root를 재생성하는 코드를 쳤는데요, 이번에는 그런 명령어가 없다고 떴습니다. 하하... 그래서 그런 명령어를 치려면 고급 시스템 변수 - Path에 MySQL bin 파일을 추가해야 한다고 하길래 거기에 파일 추가까지 했는데요, 뭐 놀랍지도 않겠지만 cmd에서 그런 명령어는 없다고 뜨며 완전 힘이 빠져가고 있었습니다... 그 뒤에는 계속 인터넷에 관련 블로그를 찾아봤는데요, 어떤 분도 이렇게 생고생하시다가 결국은 MySQL 관련 폴더를 완전히 지우고 재설치하셨다고 하더라고요... 저도 처음에는 파일을 완전히 지우는 거에 좀 트라우마(과거에 파이썬 버전 여러 개 잘못 설치해서 폴더 지우는 데 엄청 고생한 경험 유)가 있어서 망설였지만, 이 방법 외에는 그 어떤 방법도 떠오르지 않아 결국은 모두 지우고 재설치했습니다^-^결론은 MySQL에서 root 파일은 절대 절대 절대 지우는 게 아니라는 것을 배웠고, 앞으로는 삭제->재설치가 아니라 스스로 복구해보는 경험도 해보고 싶다는 생각을 했습니다. 물론 아무런 문제도 발생하지 않는 게 최고긴 하지만요ㅎㅎ 두 번째는 아직 진행 중인데요, 앞에서 말씀 드렸듯 전 백엔드 극극 입문자입니다. 그래서 Controller, Service, Repository, Domain, DTO가 각자 하는 일은 알겠는데, 그 사이의 연결, 생성자 만드는 이유, 람다 문법 등 아직 모르는 것들이 엄청나게 많아서 (강의 내용 중) 3단 분리까지 완성한 이후 정리한 모든 코드들을 한 페이지씩 만들어서 코드를 다시 읽어보며 분석할 예정입니다... 저는 아직 강의를 들으며 따라하고 있기는 하지만 난도가 조금씩 올라가고 관계가 복잡해질수록 어떻게 공부해야 제 머릿속에 다 남고, 이걸 어떻게 바로 응용해가며 쓸 수 있을지 고민에 있는데요, 우선 밀린 진도부터 따라잡고 나서 차차 생각해봐야 할 것 같습니다... 다음 주에는 부지런히 공부해서 권장 진도도 맞추고, 백엔드 공부를 어떻게 하면 효율적으로, 효과적으로 제 것으로 만들 수 있을지 연구해서 돌아오겠습니다!안녕~

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

cynh K

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

피그마 베리어블을 활용한 디자인시스템 구축 2주차 회고2주차 회고 시작입니다! 연휴가 있어서 진짜 눈깜짝할 사이에 지나간 2주차여서 사실 너무 놀랐어요...ㅎ그래도 회고 남기러 돌아왔습니다 !.2주차 다짐과 느낀점오전시간 활용퇴근후의 시간활용을 더 주를 이뤘던 것 같아요 ㅠ오전 시간을 활용하려고 했는데 그것을 못지킨게 이번주 가장 큰 리스크였던 것 같습니다 ㅠㅠㅠ그래서 다시 한 번 도전해보려고 합니다.돌아오는 월요일부터는 꼭..꼬옥..!  단순히 강의수강이 목적이 아닌 내것을 만들기사실 초반 흐름을 따라가려다보니 자연스레 볼드멘토님이 하시는 것을 하나하나 따라만 할 뿐,되돌아보니 챕터별 스스로가 온전하게 이해되는 공부가 진행된 흐름은 아니었다는 걸 느꼈어요!하지만 2주차가 되고 Local Variables 자연스레 누르고 진행하는 저를 보며, 구조에 대한 이해가 점점더 확실히 된다고 느꼈습니다. 제것으로 만들어가는 흐름이 처음으로 느꼈던 한 주이기때문에 이번주도 만끽하면 내것으로 만들어보고싶어요! 3주차 시작에 있어 다짐재수강하고싶었던 파트는 재수강완료, 추가로 더 듣고싶은 그림자,보더 다시 듣고 채우기 (추가시간 틈틈히!)오래걸려도 이해할 때 까지 듣고 듣고 또 듣기!발자국 먼저 남기고, 동기부여 다시 팍팍 받고!늦었지만 빠르게 이번주 진도를 빼보려고 합니다.볼드멘토님도 멘티님들도 스터디 하는 모든 분들 다음주도 화이팅이에요!

UX/UIUXUI인프런워밍업클럽

미플

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

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]2주 차는 이론보다 실습이 많았다. 그리고 이전보다 조금 더 깊은 주제를 다뤘다. 한 번에 이해가 가지 않는 주제들도 많아서 여러 번 반복해서 보고 있다. 트랜잭션 스크립트패턴과 도메인 모델패턴을 사용해 봤던 게 가장 인상 깊었다. 무엇을 배웠나? 6일 차: 스프링 컨테이너의 의미와 사용 방법스프링 컨테이너- 서버가 시작되면 컨테이너가 생기고 스프링 빈이 들어간다. - 컨테이너는 무엇이고, 스프링 빈은 무엇일까? - 컨테이너는 클래스의 정보(스프링 빈)를 담고 있다. - 빈으로 등록된 클래스의 연관관계를 정리해 준다. - 스프링빈으로 등록될 때 인스턴스화를 진행한다. - 스프링빈은 두 가지의 타입을 가진다. 1. 의존성을 추가하여 등록되는 빈 2. 사용자가 직접 추가하는 빈 - 빈으로 등록되지 않은 클래스를 의존하려 할 때 컨테이너에 조회되지 않고 빈으로 등록하라고 에러가 발생한다. - 그렇다면 왜 스프링 컨테이너와, 빈을 사용해야 할까? `new` 키워드를 사용해서 직접 인스턴스화하면 되지 않을까?IoC, DI- 스프링 컨테이너를 이해하기 위해서는 3단 변화를 직접 느껴야 함 - class -> interface -> 스프링 컨테이너(IoC, DI) - IoC(제어의 역전)는 객체의 생성, 삭제등 관리를 내가 직접 하지 않고 프레임워크(컨테이너)에게 위임함 - DI(의존성 주입)는 의존성을 직접 주입하지 않고 컨테이너가 주입함 - 같은 타입의 빈이 등록되어 있을 때 컨테이너도 어떤 빈을 주입해야 하는지 교통정리를 해줄 수 없음, 이때는 사용자가 빈의 우선권을 등록해줘야 함(@Primary) - 결국 컨테이너를 사용하는 이유는 변화에 유연하게 대응하기 위해서임, 클래스를 사용하는 코드에는 변화를 주지 않고 변화가 필요한 구현코드에만 수정함빈을 어떻게 등록하고, 주입할까?- 컨테이너에 등록되는 빈을 등록하기 위해서는 `@Configuration`과 `@Bean`을 이해해야 함 - `@Configuration`은 클래스에 사용하고 `@Bean`은 메서드에 사용함 - 일반적으로 사용자가 직접 만든 클래스는 Controller, Service, Repository 어노테이션을 사용함. - 외부 라이브러리, 프레임워크에서 제공하는 클래스를 빈으로 등록할 때 두 어노테이션을 조합하여 사용함 - `@Component`는 컨트롤러, 서비스, 리포지토리 외에 추가 클래스를 스프링 빈으로 등록할 때 사용함 - 빈을 주입시키는 방법은 3가지가 있음(생성자, setter, 필드) - 생성자 주입이 가장 권장되는 방식임(불변, null 체크) - setter 주입은 setter 메서드를 열어둠으로써 누군가 사용하여 오염될 수 있음 - 필드 주입의 경우 `@Autowired`를 사용하는데 테스트 코드 작성시 어려움 - @Qualifier: 같은 타입의 빈을 구별하는데 사용함 - @Primary: 우선권을 지정할 때 사용 - @Qualifier 는 사용하는 쪽과 등록하는 쪽 모두에서 사용해 연결할 수 있음 - @Qualifier와 @Primary가 동시에 사용될 경우 Qualifier가 우선권을 가짐 - 스프링은 사용자가 직접 지정한 설정을 우선으로 함 7일 차: Spring Data JPA를 사용한 데이터베이스 조작문자열 SQL을 직접 사용할 때 문제점과 JPA- 문자열을 직접 사용하는 것은 실수(오탈자)가 발생할 확률이 높음. 에러가 컴파일 시점에 발견되지 않고 런타임 시점에 발견되는 치명적인 문제(운영 중 발견) - 프로그래밍 언어와 관계형 데이터베이스의 패러다임 불일치 - 반복적인 작업 발생(CRUD) - 변화에 유연한 프로그램 구현이 어려움: 특정 데이터베이스에 종속됨 - JPA(Java Persistence API)는 자바진영의 ORM 기술 표준을 의미함: 데이터를 영구적으로 보관하기 위한 규칙 - 영속성(Persistence)은 영구적인 속성 - 규칙(Interface)을 구현하기 위해 Hibernate(구현체)를 사용 - Hibernate는 내부적으로 JDBC를 사용함Entity Class 만들기- Entity는 관리되어야 할 데이터를 의미함 - 기존 클래스를 엔티티로 선언하기 위해서는 `@Entity`를 사용 - id를 기본키로 만들어 주기 위해서는 `@Id`를 사용 - `@GeneratedValue` 해서 기본키 생성전략을 제공해야 함 - JPA를 사용하기 위해서는 기본 생성자가 제공되어야 함 이때 `protected`로 선언 - `@Column`은 테이블과 매칭, 다양한 옵션을 선언할 수 있음. nullable, length, name... - JPA를 사용하기 위해서는 설정에 추가해야 함 - `ddl-auto`: 서버가 시작될 때 테이블을 어떻게 처리할 것인지를 정함 - `hibernate.show_sql`: 데이터베이스에 날리는 SQL을 보여줌 - `hibernate.format_sql`: 포맷팅 해서 보기 좋게 보여줌 - `hibernate.dialect`: SQL 방언을 JPA가 수정해 줌Spring Data JPA 사용하기- JPA를 편리하게 사용할 수 있도록 Spring에서는 Spring Data JPA를 지원함 - Spring Data JPA -> JPA -> Hibernate -> JDBC - save: 객체를 저장하거나 업데이트 - findAll: 일치하는 모든 데이터 조회 - findById: id를 기준으로 일치하는 데이터 1개 조회 - Spring Data JPA를 사용하면 다양한 쿼리를 조합할 수 있음 - find, findAll, count, 등등...8일 차: 트랜잭션과 영속성 컨텍스트- 트랜잭션이(Transaction)이란 더 이상 쪼갤 수 없는 업무의 최소단위를 의미함 - 트랜잭션을 시작하면 모두 성공(commit)하거나 되돌리기(rollback)할 수 있음 - 트랜잭션을 적용할 때 `@Transactional`을 사용함 - 영속성 컨텍스트가 핵심 9일 차: 조금 더 복잡한 기능을 API로 구성하기API 스펙을 설계하고 직접 구현하는 것을 권장 10일 차: 객체지향과 JPA 연관관계이전에 구현된 코드는 객체가 협력하지 않고 직접 객체를 가져다 쓰는 방식으로 작성되었음. 어떻게 하면 객체가 서로 협력하는 관계를 맺어줄 수 있을까? > ![비즈니스 로직구현 Entity VS Service](https://www.inflearn.com/questions/117315/%EB%B9%84%EC%A7%80%EB%8B%88%EC%8A%A4-%EB%A1%9C%EC%A7%81%EA%B5%AC%ED%98%84-entity-vs-service) - 서비스에 작성된 비즈니스 로직을 도메인 계층으로 이동시킴 과제과일가게 API 구현하기클린코드 이해하기 마무리우려하던 일은 현실이 돼버렸다. 컨디션 관리에 실패했다. 궁금한 주제를 탐구하기도 하고 딴짓을 하다 늦게 잠들었다. 수면패턴이 꼬이고 생산성도 저하됐다. 결국 시간을 알차게 보내지 못했다. 과제를 해결하는데 급급하기도 했고, 진도표를 몰아서 듣기도 했다. 연쇄반응으로 걱정도 늘어났다. 불행 중 다행으로 긍정적인 사실도 찾을 수 있었다. 잠(루틴)의 중요성을 느꼈다. 푹 자고 일어나서 루틴을 다시 시작하니 금방 제모습으로 돌아왔다. 이외에도 다양한 주제를 탐구하다 보니 견문이 넓어졌다. 시간을 효율적으로 보내고 얼른 접하고 싶은 욕심이 든다.

백엔드인프런워밍업클럽

김찬희

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

스프링 컨테이너 (1) Static 이 아닌 코드를 사용하려면 인스턴스화가 필요하다 . 이때, @RestController( Controller 클래스) 등을 사용해 클래스를 스프링 빈으로 등록시켜준다. 서버가 시작되면 스프링 서버 내부에 컨테이너를 만들게 되는데 이때, 스프링 컨테이너에 기존에 등록되어 있던 빈들이 다 등록 되고 나면 @RestController 등으로 스프링 빈 등록한 클래스 들이 등록된다. 이때, 다양한 정보들도 함께 들어있고 인스턴스화도 이뤄진다. ex ) UserController에 @RestController를 붙였다면 이름 : UserController , 타입 : UserController 로 등록되는 것이다. 이렇게 스프링 컨테이너 안에 들어간 클래스들을 스프링 빈이라고 한다. 우리가 이전에 사용했던 JdbcTemplate 은 이미 스프링 빈으로 등록되어 있어 따로 등록하지 않아도 된다. ( 우리가 bulid.gradle 에서 dependencies 설정을 해줬기 때문이다.) 이후에 빈 등록이 완료되면 필요한 의존성을 자동으로 연결시켜주는데 UserController는 JdbcTemplate의 의존 관계가 연결된다. 그런데 만약 이때 BookController -> BookService-> BookMemoryRepository 에서 BookMySqlRepository를 연결하고 싶다면 기존의 Repository 코드뿐만 아니라 Service 코드에서의 인스턴스화 부분등 수정코드가 발생한다 우리는 이를 해결하기 위해 스프링 컨테이너를 사용해서 BookController -> BookService -> <interface>BookRepository <- BookMySqlRepository <- BookMemoryRepository 로 BookRepository 라는 인터페이스를 2개의 구현체가 구현하는 형태를 만들고 컨테이너가 어떤 Repository를 사용할지 선택하게 한다. 이러한 방식을 제어의 역전 (IOC ,Inversion of Control) 이라고 하고 컨테이너가 구현체를 선택해 BookService에 넣어주는 과정을 의존성 주입 (DI, Dependency Injection)이라고 한다.(2) Bean 을 등록하는 방법 @ Configuration : 클래스에 붙이는 어노테이션 , @Bean 과 함께 사용한다.@ Bean : 메소드에 붙이는 어노테이션 , 메소드에서 반환되는 객체를 스프링 빈으로 등록한다.@Service, @Repository : 개발자가 직접 만든 클래스를 스프링 빈으로 등록시 사용 @Component : 주어진 클래스를 컴포턴트로 간주한다. 이 클래스들은 스프링 서버가 시작할때 자동으로 감지(스프링 빈 등록) , Component는 @Service ,@ Controller, @Repository 에 다 있다.(3) 스프링 빈을 주입 받는 방법생성자 주입 ( 권장 ) : 프로젝트에서 제일 많이 사용하는 방식으로 private final 타입 변수 ; 로 선언후 생성자를 통해 인스턴스화 하는 방법 Setter 와 @Autowired 사용 : 누군가 Setter 사용시 오류가 발생할 여지가 있음 (주의) 생성자 주입에도 @Autowired 를 사용해야 하지만 생략이 가능하다.3. 필드에 직접 @Autowired 사용 : 제일 편리하지만 추후 테스트 작성시 코드 작성을 어렵게 하는 요인이 된다.  (4) <interface> 의 구현체가 여러개 일때 선택 기준  1. @Primary : @Primary 어노테이션이 있는 구현체가 우선권이 있다. 2.@Qualifier : 사용하는 Service 와 사용하는 Repository 구현체에 @Qualifier("main")을 적어주고 사용하는 Service 에 @ Qualifier("구현체이름") 을 추가한다.이때 @Primary 와 @Qualifier을 동시에 사용할 경우 더 자세한 @Qualifier 이 우선 순위를 가진다.회고 이번 주는 강의를 복습 하고 개념을 정리하는데 집중했다. 강의를 2번씩 들어보면서 스프링 컨테이너 ,빈 과 등록방법, DI, IOC 등 스프링의 핵심이라고 할 수 있는 개념을 정말 이해해보는데 시간을 많이 사용했고 전보다 깊이 있는 이해가 되었다. 다음주 강의에서는 개발한 API를 배포하는 과정을 거치는데 기대된다. 나만의 서비스를 만들어보고 싶은 마음이 컸는데 강의를 통해 목표에 조금 더 가까워진듯하다.

백엔드BE

공존

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

학습 내용강의 내용좋은 코드란?clean code Layered Architecture 3단 분리의 중요성각 역할에 맡게 분리해서 진행ControllerServiceRepository 스프링 컨테이너스프링 빈@Configuration@Bean @Controller@Service@Repository@Component@Qualifier JPA데이터를 영구적으로 보관하기 위해 java 진영에서 정해진 규칙영속성자바 진영의 ORMHibernate는 내부적으로 JDBC를 사용JPA 어노테이션@Entity@Id@GeneratedValue@ColumnJPA 기능 save주어지는 객체를 저장하거나 업데이트 시켜준다.findAll주어지는 객체가 매핑된 테이블의 모든 데이터를 가져온다.findByIdid를 기준으로 특정한 1개의 데이터를 가져온다.  Spring Data JPA복잡한 JPA 코드를 스프링과 함께 쉽게 사용할 수 있도록 도와주는 라이브러리 다양한 Spring Data JPA 쿼리By 앞에 들어갈 수 있는 구절find 1건을 가져온다. 반환 타입은 객체가 될 수도 있고, Optional<타입>이 될 수도 있다.findAll쿼리의 결과물이 N개인 경우 사용. List<타입> 반환.exists 쿼리 결과가 존재하는지 확인. 반환 타입은 booleancount SQL의 결과 개수를 센다. 반환 타입은 long이다.By 뒤에 들어갈 수 있는 기능GreaterThan : 초과GreaterThanEqual : 이상LessThan : 미만LessThanEqual : 이하Between : 사이에StartsWith : ~로 시작하는EndsWith : ~로 끝나는 트랜잭션쪼갤 수 없는 업무의 최소 단위@Transactional회고록강의 자체가 처음 진입하는 사람들도 이해할 수 있게 쉽게 설명해주셔서 복습용으로 듣기 너무 좋은 수업이다. 뭔가 다듬어지지 않은 생각이 정리가 되는 편이였다.  미션실습하면서 생각보다 재미있었다. 요구조건이 정해져 있다보니까 다들 비슷하게 소스 짜올줄 알았는데 생각보다 많이 달라서 놀램.미션 5일차 클린코드 미션편은 뭔가 짜놓고 다른 스터디분들꺼 봤는데 공부가 많이 됐다.매번 미션 제출일이 지나면 강사님이 디코에 댓글로 미션의 제출 의도를 남겨주시는데 생각보다 도움이 많이되서 좋음

백엔드워밍업클럽백엔드워밍업클럽1기스터디

미플

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

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]1주 차가 끝이 났다. 고민을 많이 하고 시작한 스터디였는데 무엇을 알고, 모르는지 확인함에 도움을 받고 있다. 무엇을 배웠나?강의는 교과서 같았다. 각 강의와 섹션마다 학습목표와 정리가 이뤄진다. 반복되는 과정을 통해 점진적으로 문제가 해결되는 과정을 배웠다. 서버개발자가 되기 위한 최소한의 이론을 다루고 실습을 먼저 시작했다. 간단한 기능으로 시작했던 애플리케이션에 요구사항이 추가되고 어떻게 계층화 아키텍처로 나눌 수 있을지 이야기하는 시간을 가졌다. 1일 차: 서버 개발을 위한 환경 설정 및 네트워크 기초스프링 프로젝트를 시작하는 방법어떻게 새로운 프로젝트를 시작할까?기존에 운영 중인 프로젝트에 투입 됐을 때 어떻게 시작할 수 있을까? 서버 개발자가 되기 위해 알아야 하는 기본적인 지식네트워크, IP, 도메인, 포트, HTTP 요청과 응답, 클라이언트 - 서버, API란 무엇인가  과제: 자바 어노테이션무의식 중에 많이 사용했지만 궁금해하지 않았다. 이전에는 어떻게 문제를 해결했는지 알 수 있었다. 2일 차: 첫 HTTP API 개발Spring Boot를 사용해 API 만들기 GET, POST웹 개발에 기본이되는 HTTP를 다룬다.GET은 쿼리를 사용해 조회에 사용되고, POST는 body를 사용해 생성에 주로 사용된다.   과제: API 실습 1, 2일 차를 제대로 이해하고 있는지 점검을 했다. 문제를 해결하는 데 시간이 오래 걸리지 않았지만 정리하는데 오랜 시간이 걸렸다.3일 차: 기본적인 데이터베이스 사용법디스크와 메모리의 차이, 데이터베이스(Database)는 왜 필요한가?SQL 사용, MySQL 다루기이전에 만들었던 기능들은 서버가 종료되면 데이터가 모두 사라졌다. 데이터를 계속 저장하기 위해서 데이터베이스를 사용하자.테이블 생성, 데이터 추가, 조회, 수정, 삭제 과제: 익명 클래스와 람다 4일 차: 데이터베이스를 사용해 만드는 API스프링 서버와 연결하여 데이터베이스 다루기, API 예외상황 다루기, 예외처리PUT, DELETE를 학습하고 수정데이터베이스와 통신해서 조회되는 데이터가 없으면 어떻게 에러를 반환할지 배운다.  5일 차: 클린코드의 개념과 첫 리팩터링좋은 코드는 왜 중요한가? 계층화 아키텍처(Layered Architecture)의 등장, 리팩터링Controller에 역할을 덜어주기 위해 리팩터링을 진행했다.역할을 나누고 왜 좋은 코드의 개념에 대해 배웠다. 마무리스터디 시작 전에 강의를 듣고 정리해 둬서 다행이다. 주말을 앞두고 몸도 마음도 지쳐서 과제를 제출하지 못할 뻔했다. 문제가 발생했던 이유는 전 날 푹 잠들지 못해서 발생했다. 단거리가 아니라 장거리 달리기라 생각하고 컨디션 관리에 더욱 신경 써야겠다. 다음 주도 미루지 않고 마무리했으면 좋겠다.

백엔드인프런워밍업클럽