블로그

박지원

[인프런 워밍업 클럽 스터디] 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] 클린 코드[회고]과제를 수행하며 더 가독성 있고 클린한 코드를 작성하기 위해 어떻게 하면 좋을지 고민했던 한 주였다. 다른 사람들이 작성한 코드도 살펴보면서 내 코드에서 부족한 점과 업그레이드할 점을 찾아보고 더 공부할 수 있었다. 과제 마감 후, 과제 수행 목적에 맞게 풀이했는지 확인하는 것도 많은 도움이 됐다.

백엔드워밍업클럽

이상현

인프런 워밍업 클럽 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에 역할을 덜어주기 위해 리팩터링을 진행했다.역할을 나누고 왜 좋은 코드의 개념에 대해 배웠다. 마무리스터디 시작 전에 강의를 듣고 정리해 둬서 다행이다. 주말을 앞두고 몸도 마음도 지쳐서 과제를 제출하지 못할 뻔했다. 문제가 발생했던 이유는 전 날 푹 잠들지 못해서 발생했다. 단거리가 아니라 장거리 달리기라 생각하고 컨디션 관리에 더욱 신경 써야겠다. 다음 주도 미루지 않고 마무리했으면 좋겠다.

백엔드인프런워밍업클럽

eus247

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

리액트 강의 정리(섹션1~5)Section 1컴포넌트- 리액트로 만들어진 앱을 이루는 최소한의 단위(함수형/클래스 컴포넌트)가상돔- 인터렉션이 많은 웹의 경우 불필요한 DOM을 조작하는 비용이 큰 문제를 해결하기 위해 나오게 됨- 데이터가 바뀌면 가상돔에 렌더링이 되고 이전에 생긴 가상돔과 비교해서 바뀐 부분만 실제 돔에 적용시켜 줌 Section 2SPA Single Page Application- 웹 사이트의 전체 페이지를 하나의 페이지에 담아 동적으로 화면을 바꿔가며 표현한 것- HTML5 History API를 사용하여 페이지 전환 해줌JSX Javascript Syntax eXtension - 자바스크립트, HTML 구조 같이 사용할 수 있음 → 기본 UI에 데이터가 변하는 것을 쉽게 구현할 수 있음 - createElement 쉽게 사용하기 위해 사용React State컴포넌트의 렌더링 결과물에 영향을 주는 데이터를 갖고 있는 객체 Section 3React Hooks- class없이 state를 사용할 수 있는 기능- useAuth(), useState() ...Propsproperties상속하는 부모 컴포넌트에서 자식 컴포넌트에 데이터 등을 전달하는 방법읽기 전용, 자식 컴포넌트 입장에서는 변하지 않음변하게하려면 부모 컴포넌트에서 state 변경해야 함State해당 컴포넌트 내부에서 데이터 전달변경 가능state가 변하면 re-render 됨구조 분해 할당 Destructing → 클린코드 목적- 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JS 표현식// 구조 분해 할당 function buildAnimal(animalData){ let {accessory, animal, color, hairType} = animalData; ... } // 깊게 들어간 객체 구조 분해 할당 let {address:{zipcode, street, number}} = person;React.memo- React 컴포넌트를 메모이제이션하여 불필요한 리렌더링을 방지하는 데 사용 - 컴포넌트의 props가 변경되지 않으면 이전에 렌더링된 결과를 재사용useCallback- 동일한 콜백 함수가 계속 재생성되는 것을 방지하고, 의존성이 변경되지 않으면 이전에 생성된 콜백 함수를 재사용useMemo- compute함수에 넘겨주는 a,b 값이 이전과 동일하다면 컴포넌트가 리렌더링 되더라도 연산을 다시 하지 않고 이전 렌더링 때 저장해주었던 값을 재활용하게 됨Section4,5Axios- http 비동기 통신 라이브러리, promise api 활용- 인스턴스화 하여 사용React 애플리케이션에서 라우팅을 관리하기 위한 도구라우팅 컴포넌트 및 구조 관련- 중첩 라우팅 : 라우팅 시스템에서 하위 경로에 대한 라우팅을 부모 경로의 컴포넌트 내에서 처리하는 것- outlet : 라우팅 구성 요소 내에서 렌더링된 컴포넌트의 자식 컴포넌트를 표시하는 데 사용라우터 훅 관련- useNavigate : 특정 이벤트 또는 조건에 따라 사용자를 다른 경로로 이동시키고 싶을 때- useParams : 현재 라우팅된 경로의 URL 매개변수에 액세스하는 데 사용- useLocation : 현재 애플리케이션의 위치(경로, 쿼리 매개변수 등)에 대한 정보 제공. 이를 통해 현재 경로나 쿼리 매개변수를 읽을 수 있음- useRoutes : 라우터 구성을 동적으로 생성할 때 사용Debounce- 연이어 호출되는 함수 중 마지막 호출 이후 일정 시간이 지난 후에만 실제로 함수를 실행하도록 하는 기술- 일정 시간 동안 함수 호출을 무시하고, 마지막 호출 이후에만 함수를 실행하여 성능을 향상시키거나 불필요한 작업을 방지할 때 사용useRef- React 함수 컴포넌트 내에서 변수를 유지하고 DOM 요소에 접근하는 데 사용- 컴포넌트 재렌더링 시에도 값이 유지되며, 변경 시에는 컴포넌트가 다시 렌더링되지 않음후기리액트를 처음 접했을 때, 컴포넌트 기반 설계의 아이디어는 매력적으로 다가왔다. 한 페이지에서 모든 요소를 관리하고 조작할 수 있다니!! 하지만 이를 실제로 코드로 구현하는 것은 예상보다 훨씬 복잡했다.컴포넌트 간의 상호작용과 데이터 흐름을 이해하는 데 어려웠다. 예를 들어, 상태가 변경될 때마다 컴포넌트가 어떻게 업데이트되는지 이해하는 것이 쉽지 않았다. 이해하는 것에 매몰되지 말고 일단 구현해보자 하고 예산 계산기 앱 과제를 진행하는데컴포넌트를 나누는 것까지는 어떻게 했는데 props를 전달하는 메커니즘을 생각하는 게 어려웠다. 부모 컴포넌트에서 자식 컴포넌트로 어떤 데이터를 props로 전달해야 하는지, 어떤 형식으로 전달해야 하는지.. 또한, useState와 useEffect 같은 리액트 훅의 개념을 이해하고 적용하는 것도 쉽지 않았다.처음에는 막막했지만, 구글과 챗GPT의 도움을 받으면서 조금씩 이해가 되기 시작했다. 그리고 중간 점검때 강사분께서도 실제로 기능 구현을 많이 해보고 다른 사람의 소스코드도 보면서 공부하라는 조언을 새겨들으면서 남은 3주차도 열심히 해보자!!

웹 개발워밍업클럽프론트엔드FE2주차발자국

eus247

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

 강의 정리노션 링크로 대체합니다.https://synonymous-currant-9b2.notion.site/FE-Javascript-542dcc2333df4ef0a2fb9c478011d171?pvs=4미션가위 바위 보 앱컴퓨터가 랜덤으로 가위바위보를 출력하도록 하는 로직을 구성하는게 어려웠다. 랜덤으로 숫자를 생성하는 Math.random()을 이용하면 될 것 같은데 이 함수는 숫자만 랜덤으로 만든다. 가위바위보 결과는 string이다. 어떻게 랜덤으로 출력하도록 할까 검색을 해본결과 랜덤숫자를 배열의 인덱스로 하면 컴퓨터 결과값이 랜덤으로 출력될 수 있음을 알게되었다.1주차 후기타 사이트에서 자바스크립트 강의를 들은 적이 있어서 이번 워밍업 스터디는 기존에 배웠던 것을 한 번 다시 리마인드하는 기분으로 가볍게 생각해야지 했는데 이건 경기도 오산이였다. 배울 때는 겸손한 태도로 임해야 한다는 것과 지식을 아는 것과 그것을 활용하는 것은 다르다는 것을 다시 한 번 깨닫는 1주차였다.강의 들으면서 열심히 정리한다고 했는데 다음날 진도나가기 전에 복습으로 보는데 왜 적었지 하는게 있어서 강의를 집중하고 이해하는 것도 중요하지만 정리할 때도 미래의 나 자신을 위해 정확하게 적어야 하는것도 중요함을 알게되었다.

웹 개발워밍업클럽프론트엔드FE1주차발자국

seong2808

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

발자국강의는 진도표에 맞춰 진행하였으며 회고록 또한 그에 맞춰 작성하였다.인프런 워밍업 스터디 클럽 완주를 목표로 남은 기간동안 매일매일 꾸준히 학습하기 위해 노력하겠다.2주차 학습 내용DAY6 : 스프링 컨테이너의 의미와 사용 방법19강. UserController와 스프링 컨테이너UserController의 의아한 점static이 아닌 코드를 사용하려면 인스턴스화 필요인스터스화를 하기 위해선 생성자를 호출하게 된다.하지만 이전 강의까지 new UserController 이렇게 호출한 적이 없다!UserController는 JdbcTemplate에게 의존하고 있다.하지만 JdbcTemplate이라는 클래스를 직접 설정해준 적이 없다!→ 그 이유는 @RestController 어노테이션에게 있다. → SpringBean으로 등록해준다!SpringBean서버가 시작되면, 스프링 서버 내부에 거대한 컨테이너를 만든다.컨테이너 안에 여러 클래스가 들어간다.이때, 다양한 정보도 함께 들어있고, 인스턴스화도 이루어 진다.스프링 빈이란? 컨테이너 안에 들어간 클래스를 말한다.UserController와 다르게 JdbcTemplate은 언제 스프링 빈으로 등록하였을까?→ 의존성 설정을 할 당시에 스프링 빈으로 등록된다.스프링 컨테이너의 역할은 서로 필요한 관계에 있는 스프링 빈끼지 연결을 시켜주는 역할이다.이론 정리서버가 시작되면 스프링 컨테이너(클래스 저장고)가 시작된다.기본적으로 많은 스프링 빈들이 등록된다.우리가 설정해준 스프링 빈이 등록된다.이때 필요한 의존성이 자동으로 설정된다.왜?그렇다면 UserRepository는 JdbcTemplate을 가져오지 못할까?→ UserRepository가 스프링 빈이 아니기 때문이다.실습UserService와 UserRepository를 스프링 빈으로 등록해준 뒤 UserRepository에게만 JdbcTemplate 필요하게 되었고 controller는 service만을 호출하고 service는 repository만을 호출하여 사용할 수 있게 된다.실습상황실습한 코드의 서버가 시작하면,가장 기본적인 스프링 빈이 등록된다.JdbcTemplate을 의존하는 UserRepository가 스프링 빈으로 등록되면서 인스턴스화된다.UserRepository를 의존하는 UserService가 스프링 빈으로 등록된다.UserService를 의존하는 UserController가 스프링 빈으로 등록된다. 20강. 스프링 컨테이너를 왜 사용할까?다음 요구사항을 생각해보자책 이름을 메모리에 저장하는 API를 매우 간단하게 구현하라. Service, Repository는 Spring Bean이 아니어야 한다.구현된 그림BookController —> BookService —> BookMemoryRepository실습진행스프링 빈을 설정하지 않고 메모리에 저장한다는 가정하에 실습 진행추가 요구사항 구현메모리가 아닌 MySQL과 같은 DB를 사용해야 한다. JdbcTemplate은 Repository가 바로 설정할 수 있다고 해보자.구현된 그림BookController —> BookService BookMemoryRepository —> BookMysqlRepository하지만 Repository 뿐만 아니라 Service까지 바꿔야 한다!이런 상황에서 Repository를 다른 Class로 바꾸더라도 Service를 변경하지 않는 방법은? → Interface를 활용하자수정된 구현BookController —> BookService —> BookRepository ← BookMemoryRepository ← BookMysqlRepository실습진행인터페이스 생성하여 레포지토리가 바뀌더라고 쉽게 사용할 수 있게 실습 진행2개의 레포지토리로 인해 에러가 발생하는데 사용하는 레포지토리에 @Primary 어노테이션을 활용해서 조절하면 에러가 해결된다.하지만 Service의 변경 범위가 줄어들었지만 아쉬운 부분이 있다.그래서 등장한 것이 스프링 컨테이너이다.컨테이너를 사용하면, 컨테이너가 Service를 대신 인스턴스화 하고 그 때 알아서 Repository를 결정해준다.이런 방식을 제어의 역전(IoC, Inversion of Control)이라고 한다.컨테이너가 선택해 Service에 넣어주는 과정을 의존성 주입(DI, Dependency Injection)라고 한다. 21강. 스프링 컨테이너를 다루는 방법빈을 등록하는 방법@Configuration클래스에 붙이는 어노테이션@Bean을 사용할 때 함께 사용해 주어야 한다.@Bean메소드에 붙이는 어노테이션메소드에서 반환되는 객체를 스프링 빈에 등록한다.실습진행UserRepository에 Bean를 사용해보자@Configuration public class UserConfiguration { @Bean public UserRepository userRepository(JdbcTemplate jdbcTemplate) { return new UserRepository(jdbcTemplate); } } 언제 @Service, @Repository를 사용해야 할까?개발자가 직접 만든 클래스를 스프링 빈으로 등록할 때사실 위의 실습은 @Repository를 사용하는 것이 관례이다.언제 @Configuration + @Bean을 사용해야 할까?외부 라이브러리, 프레임워크에서 만든 클래스를 등록할 때@Component주어진 클래스를 ‘컴포넌트’로 간주한다.이 클래스들은 스프링 서버가 뜰 때 자동으로 감지된다.@Component 덕분에 ****우리가 사용했던 어노테이션이 자동감지 되었다.언제 @Component는 사용해야 할까?컨트롤러, 서비스, 레포지토리가 모두 아니고개발자가 직접 작성한 클래스를 스프링 빈으로 등록할 때 사용되기도 한다.스프링 빈을 주입 받는 방법(가장 권장) 생성자를 이용해 주입 받는 방식setter와 @Autowired 사용 : 누군가 setter를 사용하면 오작동할 수 있음필드에 직접 @Autowired 사용 : 테스트를 어렵게 만드는 요인@Qualifier스프링 빈을 사용하는 쪽, 스프링 빈을 등록하는 쪽 모두 @Qualifier를 사용할 수 있다.스프링 빈을 사용하는 쪽에서만 쓰면, 빈의 이름을 적어주어야 한다. @Primary vs @Qualifier사용하는 쪽이 직접 적어준 @Qualifier가 이긴다. DAY7 : Spring Data JPA를 사용한 데이터베이스 조작23강. 문자열 SQL을 직접 사용하는 것이 너무 어렵다.SQL을 직접 작성하면 아쉬운 점문자열을 작성하기 때문에 실수할 수 있고, 실수를 인지하는 시점이 느리다.컴파일 시점에 발견되지 않고, 런타임 시점에 발견된다.특정 데이터베이스에 종속적이게 된다.반복 작업이 많아진다. CRUD 쿼리가 항상 필요하다.데이터베이스의 테이블과 객체는 패러다임이 다르다.그래서 등장했다.JPA (Java Persistence API) & 자바 진영의 ORM (Object-Relational Mapping)Persistence (영속성) → 서버가 재시작되어도 데이터는 영구적으로 저장되는 속성객체와 관계형 DB의 테이블을 짝지어 데이터를 영구적으로 보관하기 위해 Java 진영에서 정해진 규칙HIBERNATE(구현체) — 구현(Implements) —> JPAHIBERNATE은 내부적으로 JDBC를 사용한다. 24강. 유저 테이블에 대응되는 Entity Class 만들기Java 객체와 MySQL Table을 매핑할 것이다.User 객체 활용하여 실습진행User Class에 @Entity 어노테이션을 붙인다.@Entity : 스프링이 User 객체와 user 테이블을 같은 것으로 바라본다.Entity : 저장되고, 관리되어야 하는 데이터고유 id를 설정@Id : 이 필드를 primary key로 간주@GeneratedValue : primary key는 자동 생성되는 값기본 생성자 생성JPA를 사용하기 위해서는 기본 생성자가 꼭 필요하다.// 예시 protected User() {} @Column : 객체의 필드와 Table의 필드를 매핑한다.여러 옵션이 존재한다.// name varchar(20) @Column(nullable = false, length = 20, name = "name") Column은 생략 가능하다. → 옵션이 필요없고 테이블과 동일하다면 생략이 가능하다.JPA를 사용하니 추가적인 설정 필요 (한번만 하면 된다.)application.yml ****jpa: hibernate: ddl-auto: none properties: hibernate: show_sql: true format_sql: true dialect: org.hibernate.dialect.MtSQL8Dialect ddl-auto : 스프링이 시작할 때 DB에 있는 테이블을 어떻게 처리할지create : 기존 테이블이 있다면 삭제 후 다시 생성create-drop : 스프링이 종료될 때 테이블을 모두 제거update : 객체와 테이블이 다른 부분만 변경validate : 객체와 테이블이 동일한지 확인none : 별다른 조치를 하지 않는다show_sql : JPA를 사용해 DB에 SQL을 날릴 때 SQL을 보여줄 것인가format_sql : SQL을 보여줄 때 예쁘게 포맷팅할 것인가dialect : DB을 특정하면 조금씩 다른 SQL을 수정해준다. 25강. Spring Data JPA를 이용해 자동으로 쿼리 날리기SQL을 작성하지 않고, 유저생성/조회/업데이트 기능을 리팩토링UserRepository 인터페이스를 User 옆에 만들어준다.JpaRepository를 상속 받는다.package com.group.libraryapp.domain.user; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, Long> { } 저장기능 → save 메서드에 객체를 넣어주면 INSERT SQL이 자동으로 날아간다.@Service public class UserServiceV2 { private final UserRepository userRepository; public UserServiceV2(UserRepository userRepository) { this.userRepository = userRepository; } public void saveUser(UserCreateRequest request) { // u에는 생성한 id가 반환된다. User u = userRepository.save(new User(request.getName(), request.getAge())); } } 조회기능 → findAll 메서드를 사용하면 모든 데이터를 가져온다.// 자바8 문법을 이용한 public List<UserResponse> getUsers() { return userRepository.findAll() .stream().map(UserResponse :: new) .collect(Collectors.toList()); } 업데이트기능Optional의 orElseThrow를 사용해 User가 없다면 예외를 던진다.객체를 업데이트해주고 save 메서드를 이용하면 UPDATE 쿼리가 날아간다.public void updateUser(UserUpdateRequest request) { // select * from user where id = ?; // Optional<User> User user = userRepository.findById(request.getId()) .orElseThrow(IllegalArgumentException::new); user.updateName(request.getName()); userRepository.save(user); } 이렇게 동작할 수 있는 이유?Spring Data JPA : 복잡한 JPA 코드를 스프링과 함께 쉽게 사용할 수 있도록 도와주는 라이브러리우리가 사용한 메서드들은 SimpleJpaRepository에 담겨 있다. 26강. Spring Data JPA를 이용해 다양한 쿼리 작성하기삭제 기능을 Spring Date JPA로 변경하자public void deleteUser(String name) { User user = userRepository.findByName(name); if (user == null) throw new IllegalArgumentException(); userRepository.delete(user); } findeByName 이란 SimpleJpaRepository에 존재하지 않는다. 그러므로 UserRepository에 findByName를 작성해주어야 한다.public interface UserRepository extends JpaRepository<User, Long> { User findByName(String name); } 반환 타입은 User, 유저가 없다면 null이 반환된다.find → 1개 조회By → SELECT 쿼리의 WHERE 문이 작성By 앞에 들어갈 수 있는 구정 정리find : 1개, 반환 타입은 객체 또는 Optional<타입> findAll : 쿼리의 결과물이 N개인 경우 사용. List<타입> 반환 exists : 쿼리 결과가 존재하는지 확인. 반환 타입은 boolean count : SQL의 결과 개수를 센다. 반환 타입은 long 각 구절은 And 또는 Or로 조합할 수 있다.// List<user> findAllByNameAndAge(String name, int age); SELECT * FROM user WHERE name = ??? AND age = ???;  By 뒤에 들어갈 수 있는 구절GreaterThan : 초과 GreaterThanEqual : 이상 LessThan : 미만 LessThanEqual : 이하 Between : 사이에 StartsWith : ~로 시작하는 EndsWith : ~로 끝나는 By 뒤에 들어갈 수 있는 구절 정리//List<User> findAllByAgeBetween(int startAge, int endAge); SELECT * FROM user WHERE age BETWEEN ??? AND ???;  DAY8 : 트랜잭션과 영속성 컨테이너27강. 트랜잭션 이론편트랜잭션쪼갤 수 없는 업무의 최소 단위쇼핑몰에 주문을 한다면?주문 기록 저장포인트 기록 저장주문 결제 기록 저장만약 주문 기록과 포인트 기록이 저장되고 주문 결제 기록이 저장되지 않는다면 문제가 발생한다. 이러한 문제를 해결하기 위해 모두 성공시키거나 모두 실패시키자는 개념이 등장한다.이렇게 쪼갤 수 없는 작업 단위를 트랜잭션이라고 한다.트랜잭션 시작하기start transaction; 정상 종료commit; 실패 처리rollback; 트랜잭션을 시작 후 commit이나 rollback를 하지 않으면 확인할 수 없다.이는 묶여서 저장된다는 것을 의미한다. 28강. 트랜잭션 적용과 영속성 컨텍스트@Transactional어노테이션으로 붙이면 간단히 사용가능하다.주의사항IOException과 같은 Checked Exception은 롤백이 일어나지 않는다.영속성 컨텍스트테이블과 매핑된 Entity 객체를 관리/보관하는 역할스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생겨나고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다.특수 능력 4가지변경 감지 (Dirty Check)영속성 컨텍스트 안에서 불러와진 Entity는 명시적으로 save하지 않더라도, 변경을 감지해 자동으로 저장된다.@Transactional public void updateUser(UserUpdateRequest request) { // select * from user where id = ?; // Optional<User> User user = userRepository.findById(request.getId()) .orElseThrow(IllegalArgumentException::new); user.updateName(request.getName()); // userRepository.save(user); } save()를 명시적으로 하지 않아도 user.updateName()으로 user의 변경을 감지하고 save()를 하지 않아도 적용된다.쓰기 지연DB의 INSERT, UPDATE, DELETE SQL을 바로 날리는 것이 아니라, 트랜잭션이 commit될 때 모아서 한 번에 날린다.1차 캐싱ID를 기준으로 Entity를 기억한다.이렇게 캐싱된 객체는 완전이 동일하다.반복되는 findById(”1”)이 있다면 1번 할때, DB와 통신하여 id가 1인 무엇을 기억하고 다른 2번의 findById(”1”)은 통신하지 않고 조회할 수 있다.  DAY9 : 조금 더 복잡한 기능을 API로 구성하기30강. 책 생성 API 개발하기요구사항책을 등록할 수 있다.API 스펙 확인HTTP Method : POSTHTTP Path : /bookHTTP Body (JSON){ "anme" : String } 결과 반환 X (HTTP 상태 200 OK이면 충분)book 테이블 생성create table book ( id bigint auto_increment, name varchar(255), primary key (id) ); @Column의 length 기본값은 255문자열 필드는 최적화를 해야 하는 경우가 아닐 때 여유롭게 설정하는 것이 좋다.book 객체를 만들어 설계했던 테이블과 맵핑 시키기@Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; @Column(nullable = false) private String name; } BookService → loanBook() 생성@Transactional public void saveBook(BookCreateRequest request) { bookRepository.save(new Book(request.getName())); }  31강. 대출 기능 개발하기요구사항사용자가 책을 빌릴 수 있다. 다른 사람이 그책을 진작 빌렸다면, 빌릴 수 없다.API 스펙 확인HTTP Method : POSTHTTP Path : /book/loanHTTP Body (JSON){ "userName" : String, "bookName" : String } 결과 반환 X (HTTP 상태 200 OK이면 충분)user_loan_history 테이블 생성create table user_loan_history ( id bigint auto_increment, user_id bigint, book_name varchar(255), is_return tinyint(1), primary key (id) ); UserLoanHistory 객체를 만들어 설계했던 테이블과 맵핑 시키기public class UserLoanHistory { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; private long userId; private String bookName; private boolean isReturn; } boolean으로 처리하면 tnyint에 잘 매핑된다.BookService → loanBook() 생성@Transactional public void loanBook(BookLoanRequest request) { // 1. 책 정보를 가져온다. Book book = bookRepository.findByName(request.getBookName()) .orElseThrow(IllegalAccessError::new); // 2. 대출기록 정보를 확인해서 대출중인지 확인한다. if (userLoanHitstoryRepository.existsByBookNameAndIsReturn(book.getName(), false)) { // 3. 만약에 확인했는데 대출 중이라면 예외를 발생시킨다. throw new IllegalArgumentException("진작 대출되어 있는 책입니다."); }; // 4. 유저 정보를 가져온다. User user = userRepository.findByName(request.getUserName()) .orElseThrow(IllegalAccessError::new); // 5. 유저 정보와 책 정보를 기반으로 UserLoanHistory를 저장한다. userLoanHitstoryRepository.save(new UserLoanHistory(user.getId(), book.getName())); }  32강. 반납기능 개발하기요구사항유저가 책을 반납한다.API 스펙 확인HTTP Method : PUTHTTP Path : /book/returnHTTP Body (JSON){ "userName" : String, "bookName" : String } 결과 반환 X (HTTP 상태 200 OK이면 충분)이번 반납기능을 위한 API와 대출기능을 위한 API의 HTTP Body가 똑같다! 이런 경우 새로 만드는 것이 좋은지? 아니면 기존의 있는 DTO를 활용하는 것이 좋은지? 고민이 되는데 이러한 경우 새로 만드는 것을 추천한다고 한다.이유 : 만약 두 기능 중 한 기능에 변화가 생겼을 때, 유연하고 side-effect 없이 대처할 수 있기 때문이다.BookService → returnBook() 생성@Transactional public void returnBook(BookReturnRequest request) { User user = userRepository.findByName(request.getUserName()) .orElseThrow(IllegalAccessError::new); UserLoanHistory history = userLoanHitstoryRepository.findByUserIdAndBookName(user.getId(), request.getBookName()) .orElseThrow(IllegalAccessError::new); history.doReturn(); } @Transactional을 사용하고 있기 때문에 영속성 컨텍스트의 변경감지기능으로 엔티티객체의 변화를 감지하여 자동으로 업데이트된다!!기능을 완성했지만 한 가지 고민할만한 내용이 존재한다.우리가 ORM을 사용하게 된 이유 중 하나는 “DB 테이블과 객체는 패러다임이 다르기 때문”이다.우리는 DISK(장기기억)와 RAM(메모리, 단기기억)의 차이 때문에 데이터의 영속성을 부여하기 위해서 DB테이블에 데이터를 저장하는 것은 필수이다.하지만 JAVA 언어는 객체지향 언어이고, 대규모 웹 애플리케이션을 다룰 때에도 절차지향적 설계보다 객체지향적 설계가 좋다!그러므로 우리는 좀 더 객체지향적으로 개발할 수 없을까?와 같은 고민을 할 필요가 있다.DAY10 : 객체지향과 JPA 연관관계 - 33강33강. 조금 더 객체지향적으로 개발할 수 없을까?현재 대출기능과 반납기능을 보면 BookService에서 User와 UserLoanHistory를 모두 끌어다가 처리하는 것을 볼 수 있다. 이러한 부분을 수정하여 같은 도메인에 속해 있는 User와 UserLoanHistory가 협업하여 BookService에서 User만 가져와 대출 및 반납을 처리할 수 있게 수정한다.선행조건 : User와 UserLoanHistory가 서로 알아야한다.@Entity public class UserLoanHistory { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; @ManyToOne private User user; private String bookName; private boolean isReturn; @ManyToOne : 내가 1이고 너가 Many이다. 즉, N:1 관계이다.N:1 관계학생과 교실을 생각하면 편하다. 학생(다수)와 교실(1)반대로 User에는 @OneToMany를 붙여주어야 한다.@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; private Integer age; @OneToMany(mappedBy = "user") private List<UserLoanHistory> userLoanHistories = new ArrayList<>(); 연관관계의 주인테이블을 봤을 때, 누가 관계의 주도권을 가지고 있는가? 위 같은 경우 UserLoanHistory주도권이라는 것은 누가 상대방을 도고 있는가로 생각하면 편하다.@OneToMany(mappedBy = "user") 연관관계의 주인이 아닌 쪽에 mappedBy를 해주어야 한다.2주차 과제과제5제시된 코드를 읽어보며, 더 좋은 코드로 고쳐보기클린코드에 대해 배우고 또 알아보면서 생각보다 많은 항목을 주의할 필요가 있었다.하지만 현재 그 많은 항목들을 주의하면서 코딩하기엔 부족한 점이 많은 것 같다는 생각이 들었다. 실제로 프로젝트를 하면서 느낀 점은 시간에 쫓겨 막 작성할 때가 있는데 특히 내 경우에는 중복 코드가 발생하고 네이밍을 할때 문제가 발생한다. 이번 과제를 통해 앞으로 주의하면서 코드를 작성하고자 한다.

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

김체토

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

2주 차 - 학습했던 내용 요약 디자인 시스템과 피그마 배리어블, 디자인 토큰 등에 관한 이론을 공부했습니다.배리어블 계층과 이름을 어떻게 정하는지에 대하여 익혔습니다.color, spacing, radius 등 foundation 스타일과 배리어블 등록을 했습니다. ✔ 디자인 시스템이란재사용 가능한 컴포넌트, 패턴 그리고 가이드 ✔ 디자인 시스템의 6가지 구성1. 디자인 원칙 : 디자인 시스템이 왜 필요한가 (비전, 미션, 가치 설정)2. 스타일 가이드 : 브랜드를 나타내는 스타일 가이드EX) 로고, 칼라, 레이아웃/그리드, 간격, 아이콘, 모션, 일러스트레이션, 사진, 디자인 토큰, 타이포그래피, 톤 오브 보이스3. 컴포넌트 라이브러리 : 재사용이 가능한 UI 기본 요소 (코드 포함)EX) 버튼, 인풋 필드, 체크 박스, 라디오 등4. 패턴 라이브러리 : 자주 반복 사용되는 디자인 템플릿EX) 로그인 폼, 탐색 메뉴, 컨텐츠 카드 배치5. 문서화 : 가이드라인, 컴포넌트, 패턴, 스타일 가이드 등을 문서화 한 자료6. 시스템 관리/운영 : 디자인 시스템을 효과적으로 관리하고 유지하기 위한 프로세스와 규칙EX) 업데이트, 학습 자료, 등 (=가버넌스) ✔ 디자인 시스템이 있으면 좋은 점디자인 일관성 유지, 브랜드 강화, 효율적인 개발, 시간 단축, 팀 간 협업 강화, 빠른 온보딩, 유지 보수 용이, 높은 품질의 경험 ✔ 배리어블 계층Component (=component)Alias (=semantic)Global (=primitive)Raw value  2주 차 - 회고이론을 복습하고 Foundation 만드는데 시간이 많이 걸려 컴포넌트를 아직 만들어보지 못했어요 😭조금 더 부지런히 작업을 해보겠습니다..!  3주 차 - 다짐 및 계획파운데이션 설정과 문서화를 빨리 끝내고 다음주에는 컴포넌트들을 모두 만들겠습니다.  

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

한지은

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

day6 - 6번 과제https://github.com/jjajan2/inflearn_study/tree/main/day6_password_generator처음에는 아스키코드 번호를 이용해서 만들려고했지만 특수문자의 경우 각각 적어줘야되기 때문에 한번에 문자열을 넣는 방식을 선택했다. range를 사용할 일이 많이 없어서 거의 처음으로 다뤄보았는데, 스타일의 경우 따로 div를 넣어서 변경해주는 방식으로 하는것같았다. 이 부분은 나중에 추가적으로 보고 적용해봐야겠다!day7 - 7번 과제https://github.com/jjajan2/inflearn_study/tree/main/day7_typing_speed7가지의 과제를 하면서 타이밍 스피트 테스트 과제가 생각보다 어렵게 느껴졌다. 한 문장을 완성하고 다음문장으로 넘어갈때 Error와 Accuracy가 누적되지않고 0으로 초기화되는 현상이 있었는데, totalErrors와 totalAccuracy를 추가해서 한 문장이 끝날때마다 누적하는 방식으로 해결했다! 생각해보면 별거 아니었던것같은데 바로 생각해내지 못해서 아쉽다.그리고 7번 타이핑 스피드 과제와 3번 퀴즈 과제에서 json파일로 데이터를 따로 빼서 사용했는데, 과제를 하던 도중 콘솔창에 에러가 생기는걸 발견했다.이 에러 메시지는 import 구문에서 assert 옵션을 사용하는 것이 더 이상 권장되지 않으며, 향후 V8 v12.6과 Chrome 126부터 지원이 중단될 것이라는 내용이고, 과거에 정적 분석을 위해 사용되었다고 한다. 이를 대신해 with을 사용하도록 권장되고있다. 라는것을 알게되었다. 하지만 fetch를 사용하는 방식으로 변경했다. 7번과제를 할때까지 몰랐던거 보면 3번과제를 할때 콘솔창을 제대로 확인하지 않았던것 같다ㅠㅠ 에러를 꼼꼼히 확인하는 습관을 기르자..!그리고 타이머를 체크하는 부분을 setTimeout과 반복문을 사용해서 만들었는데, 다 만들고나니까 코드가 허술하다는 생각이 들었다.. 그래서 setInterval을 사용하는 방식으로 변경했다!day9 - 8번 과제https://github.com/jjajan2/inflearn_study/tree/main/day9_budget_calculator예산 계산기 과제를 스터디 팀원분들과 함께 코드리뷰를 했다!총 합계를 계산하는 부분을 map을 사용해서 계산하는 코드를 작성했는데, 팀원분이 reduce를 사용하지 않은 이유를 물어보셨다..! 사실 reduce를 생각하지 못했어서 바로 reduce를 사용하는 방식으로 변경했다. (감사합니다! 😊)나도 팀원분들의 코드를 보면서 피드백을 해드리고 싶었는데, 아직 실력이 부족해서 딱히 해드릴수 있는게 없었다..확실한건 다른사람이 작성한 코드를 보는건 많은 도움이 되는것같다!인프런 스터디가 끝나도 다른 여러가지 스터디, 프로젝트를 해보면서 실력을 많이 키워야겠다

프론트엔드워밍업클럽FE1기

슬프구나

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

2주차는 드디어 본격적으로 리액트와 Next.js 를 하는 주간이었다! useState()useEffect()useLayoutEffect()useRef()useMemo()useCallback()useContext()useReducer()등에 다양한 훅을 복습 하였다. 리액트 훅은 16.8 에 추가가된 기능이다. 등장하면서, 클래스 컴포넌트의 시대는 저물었다. 리액트 훅 함수는 반드시 함수 컴포넌트에서만 사용해야만 한다.리액트 훅은 조건에 또는 반복문에 따라 호출이 되면 안된다.useState() 는 함수 컴포넌트내에서 상태를 관리하는 훅이다.useEffect(), useLayoutEffect 는 함수 생명주기에 대응하는 훅이다.2번째 인자로 배열을 가지는(의존성 배열) 훅들은 사용할 때 항상 주의해야한다. -> 안그러면 클로저로 인해 이전 값을 계속 참조한다.useEffect() 훅은 함수 컴포넌트가 반환하는 JSX 구문 즉 ReactElement 가 실제DOM에 렌더링 된 후 paint 후에 비동기로 동작하는 반면 useLayoutEffect() 훅은 동기적으로 페인트 이전에 실행이 된다. 리액트 함수 컴포넌트 생애주기는Render 단계와 Commit 단계로 나뉜다.Render 단계에서는 함수가 실행되어, JSX 를 반환한다. JSX 는 ReactElement 를 생성하는 함수로 변환이 되어 ReactElement 를 생성한다. 이걸 가지고 가상 DOM을 만든다. 이전에 만든 가상DOM이 있다면 이를 비교하는 작업을 한다.Commit 단계에서는 가상DOM을 실제 DOM에 반영한다.  Next.js는 React 프레임워크를 기반으로 한 웹 개발 도구로, 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG), 그리고 최근에는 클라이언트 사이드 렌더링(CSR)과 같은 다양한 렌더링 방식을 지원합니다. 각 렌더링 방식에 대한 설명과 특징을 살펴보겠습니다. 서버 사이드 렌더링 (Server-Side Rendering, SSR)개념: SSR은 각 요청이 있을 때마다 서버에서 HTML을 동적으로 생성하여 클라이언트에게 전송하는 방식입니다. 이는 초기 페이지 로딩 시 서버에서 모든 페이지를 미리 렌더링하고, 완성된 HTML을 클라이언트에게 보내줍니다.장점: 검색 엔진 최적화(SEO)에 유리하고, 초기 로딩 시 사용자에게 완성된 페이지를 보여줄 수 있어 사용자 경험이 개선됩니다.단점: 서버 부하가 늘어날 수 있으며, 렌더링 시간이 길어질 수 있습니다.정적 사이트 생성 (Static Site Generation, SSG)개념: 빌드 시 모든 페이지를 미리 HTML로 변환하여 저장합니다. 사용자의 요청에 따라 미리 생성된 HTML 파일을 그대로 전송합니다.장점: 서버 부하가 감소하고, 빠른 로딩 속도를 제공합니다. 보안이 강화되며, CDN을 통한 쉬운 배포가 가능합니다.단점: 실시간 업데이트가 필요한 경우 적합하지 않을 수 있습니다. 사이트 빌드 시간이 길어질 수 있습니다.클라이언트 사이드 렌더링 (Client-Side Rendering, CSR)개념: 초기 로딩에서는 기본적인 HTML과 JavaScript를 로드하고, 이후 모든 렌더링은 브라우저에서 JavaScript를 통해 이루어집니다.장점: 서버 부하가 줄어들고, 사용자 인터랙션에 따라 동적인 페이지 변화를 빠르게 구현할 수 있습니다.단점: 초기 로딩 시 필요한 자원이 많아져서 속도가 느려질 수 있으며, SEO에 불리할 수 있습니다.증분형 정적 재생(Incremental Static Regeneration, ISR)개념: ISR을 사용하면, 빌드 시 생성된 정적 페이지를 배포 후에도 필요에 따라 업데이트할 수 있습니다. 이는 특정 페이지를 새로운 데이터로 다시 생성하게 할 수 있는 옵션을 제공하여, 정적 사이트의 장점을 유지하면서도 동적 콘텐츠의 필요성을 충족시킬 수 있습니다. 장점성능과 캐싱: 정적 파일로 서빙되기 때문에 빠르고, CDN을 통해 캐싱될 수 있어 성능이 우수합니다.스케일링: 정적 파일을 사용하기 때문에 트래픽 증가에 따른 서버 부하가 적습니다.신선도: revalidate 옵션을 통해 정적 콘텐츠임에도 불구하고 일정 기간마다 콘텐츠를 자동으로 업데이트하여 최신 상태를 유지할 수 있습니다.단점복잡성: ISR 설정과 관리는 일반적인 SSG나 SSR에 비해 복잡할 수 있습니다.비용: 재생성 로직에 따라 추가 서버 자원이 필요할 수 있으며, 이로 인해 비용이 발생할 수 있습니다.Next.js 에서는 개발자를 위해 다양한 기능을 제공해 주고 있다.파일 기반 라우팅api 라우팅Image 최적화Metadata API등 다양해서 좋다. 그런데 프로젝트를 작성해나가다보면 예약어 파일들이 너무 많아져서 큰 회사들은 이걸 어떻게 관리하는지 궁금해진다.

프론트엔드인프런워밍업클럽FE1기회고

강나현

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

강의 수강1) 일주일 간 학습한 내용이전에 접했던 개념이지만 다시 봐도 헷갈렸던 개념, 몰랐던 개념 위주로 정리해보았다.const vs let vs varconst , let → 블록 레벨 스코프function func(){ if(true){ let a = 0; } console.log(a) // reference error } var → 함수 레벨 스코프function func(){ if(true){ var a = 0; } console.log(a) // a 출력 } 호이스팅- 코드 실행 전 변수나 함수 선언을 맨 위로 끌어올려지는 것을 의미함.// 1. var 변수 생성시 undefined로 선언 후, hello 할당 console.log(greeting); //undefined 출력 var greeting = 'hello'; // 2. let, const 변수 생성 시 // 호이스팅은 발생하지만 초기에 초기화되지 않고 값을 할당하기 전에 콘솔 로그가 발생함. // 발생 원인: TDZ(Temporal Dead Zone) // → 선언단계와 할당 단계 사이 변수를 사용할 수 없는 일시적 비활성 상태 console.log(greeting); // reference error let greeting = 'hello';  최대한 let보다 const를 사용하되 let 사용시 scope를 좁게 만들어서 사용하자.for vs forEachfor가 forEach 보다 성능이 좋음.따라서 복잡한 코드인 경우에는 for가 좋지만 가독성 측면에서는 forEach가 좋을 수 있음.for는 await과 함께 동작하지만 forEach는 await과 완벽하게 동작하지 않음.DOMDOM vs BOMDOM(Document Object Model)- DOM은 웹 브라우저가 HTML 페이지를 인식하게 해주는 트리구조로 된 객체 모델을 의미함.- JavaScript와 html을 연결해주는 역할BOM(Browser Object Model)- JavaScript가 브라우저와 소통하는 역할- window객체를 제어함.DOM 동작방식브라우저가 서버에서 페이지에 대한 응답을 받아 화면에 표시하는 단계1. DOM 트리 생성2. Render 트리 생성 - 브라우저가 DOM과 CSSOM(javascript가 css를 조작할 수 있는 api)을 결합하는 과정으로 화면에 표시되는 노드의 정보, 스타일 정보를 포함3. Layout - 브라우저 요소의 크기와 위치 계산 4. Paint - 실제 화면에 렌더링Document Object 이용document.getElementsByTagName으로 불러온 노드를 배열로 변환하는 방법let li = document.getElementsByTagName('li'); //collection으로 출력 li = Array.from(li); console.log(li); // 배열로 출력innerHTMLhtml까지 같이 보여줌.innerText 사용자에게 보여지는 화면 그대로 보여줌.(실제 코드에서 공백이 여러개이지만 1개 공백으로 처리)textContentdisplay:none과 같이 숨겨진 노드도 출력하고 텍스트 값 그대로 보여줌.childNodes 또한 collection 이며 collection의 특징은 아래와 같음.collection을 순환할때 for…of, forEach() 사용가능하며 for…in 은 사용 불가능함.collection은 배열이 아니기 때문에 filter와 같은 배열 메서드 사용 불가함. eventeventBubbling이벤트가 발생했을 때 중첩된 상위 요소로 이벤트가 전달되는 현상e.stopPropagation()으로 해당 현상을 막을 수 있음.eventCapturing이벤트가 아래 요소로 전달되는 현상preventDefault()별도의 브라우저 행위(ex. submit 태그 실행 시 화면이 새로고침 되는 현상)를 막을 수 있음.2) 학습 내용에 대한 회고연휴 겸 여행을 가게 되어 ktx 열차 안에서 틈틈이 강의를 들었다. 덕분에 진도를 따라잡을 수 있었지만 꼼꼼하게 내용을 기록하지 못해 아쉬웠다. 또한, 과제를 더 완벽하게 해낼 시간이 부족했기 때문에 2주차는 스터디에 시간을 더 소비해야겠다는 생각이 들었다. 미션1) 미션 해결 과정문제 현상가위 바위 보 앱을 구현하며 다시 시작 버튼을 누르고 가위 바위 보 버튼 중 하나를 클릭하면 게임 총 횟수가 2개씩 줄어드는 현상이 발생했다.문제점콘솔로 가위 바위 보 버튼 이벤트 타겟을 찍어보니 클릭은 한 번만 했지만 이벤트 타겟은 2개가 찍히는 문제가 있었다.원인처음엔 버튼을 감싸고 있는 부모태그까지 이벤트가 전달되는 '버블링 현상' 인줄 알고 e.stopPropagation() 을 적용해보았지만 해결이 되지 않았다. 구글링을 통해 익명함수로 이벤트 리스너를 사용하면 새로운 객체로 생성되어 중복이 발생한다는 점을 알게되었다.해결방안익명함수 대신 선언적 함수로 코드를 수정하니 클릭 이벤트가 한번만 발생했다. 2) 미션 해결에 대한 회고음식 메뉴 앱반응형 레이아웃을 적용해보려고 노력했지만 의도와 다르게 정렬이 흐트러졌다. 해당 과제를 통해 css 지식이 많이 부족하다고 느꼈고 추후에 css 개념을 공부해서 수정해야겠다는 생각이 들었다. 지금은 JavaScript 공부에 더 집중해야겠다.2. 가위 바위 보 앱, 퀴즈 앱가위 바위 보 앱을 구현하며 이벤트 중복 현상을 해결하기 위해 시간을 많이 소비했고 처음부터 설계를 제대로 못해서 스파게티 코드가 된 것 같다. 평소에 토이 프로젝트로 프론트엔드 개발 역량을 많이 쌓아야겠다.3. 퀴즈 앱이전 과제들의 부족한 점을 생각하며 init() 함수에 미리 구현해야할 함수명들을 적어놓고 시작했다. 하지만 중간에 버튼을 변경하는 부분에서 코드가 꼬이기 시작하더니 마찬가지로 코드가 복잡해졌다. retry, next 버튼을 변경하는 부분에서 display: none으로 스타일링에 변화를 줘야할지 innerText로 버튼명을 변경해야할지 고민을 했던 것 같다. 정답 코드가 나오면 더 효율적인 코드가 무엇인지 체크해봐야겠다.  

프론트엔드

강나현

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

강의 수강1) 일주일 간 학습한 내용이번주도 마찬가지로 이전에 접했던 개념이지만 다시 봐도 헷갈렸던 개념, 몰랐던 개념 위주로 정리해보았다.symbol()유니크한 식별자를 만들기위해 사용함.객체를 for in으로 추출할때 symbol 식별자는 통과하지 않음.  Generator 함수사용자의 요구에 따라 다른 시간 간격으로 여러 값을 반환 function* generatorFunc(){ yield 1; //return 1과 같은 의미 yield 2; yield 3; } const number = generatorFunc(); console.log(number.next()); //1 console.log(number.next()); //2 console.log(number.next()); //3 //아래 2개는 같은 의미 const generator = generatorFuncion(); const generator = generator[Symbol.iterator](); 디자인 패턴Singletone design pattern 각각의 다른 객체를 하나의 객체로 제한하는 패턴Factory design pattern 비슷한 객체를 반복적으로 만들어야하는 상황에 이용하는 패턴Mediator Pattern 채팅방 예시) 채팅방에 입장후 메시지를 보낼때 중재자를 통해서 메세지를 보내는 패턴Observer Pattern subject를 관찰하는 observer들이 있을 때 관심있는 주제를 구독하고 취소하는 Publisher(게시자)-Subscriber(구독자) 관계 패턴Module Pattern 코드를 최대한 분할하여 모듈화하는 패턴프로젝트 개발setInterval(startTimer,10); 1000ms 가 1초이면 10ms 간격으로 startTimer 함수 실행<React>프레임워크 vs 라이브러리프레임워크 : 앱을 만들기 위해 필요한 대부분의 라이브러리를 포함하고 있음.라이브러리 : 특정 기능을 모듈화 해놓은 것.프레임워크는 라이브러리를 포함하고 우리가 작성한 코드를 호출함. 또한 코드는 기능 구현을 위해 라이브러리를 호출하는 관계를 가짐.Node.js웹 브라우저 환경이 아닌 곳에서도 자바스크립트로 연산가능하게 하는 자바스크립트 런타임.리액트 설치 시 필요한 이유: 프로젝트를 개발하는데 필요한 도구들이 Node.js를 사용하기 때문 ex) 주요 개발 도구 - 바벨 : 최신 js 문법을 지원하지 않는 브라우저에서도 최신 js문법이 돌아갈수 있도록 변환해주는 라이브러리 - 웹팩 : 모듈화된 코드를 하나의 js코드로 압축하는 라이브러리 - npx: 노드 패키지 실행을 도와주는 도구가상 돔 virtual dom 등장 배경웹페이지 빌드 과정에서 dom에 변화가 발생하면 render tree재성성 → layout → repaint 의 과정을 반복함. 인터렉션이 많아지면 성능상의 문제를 초래하기 때문에 실제 dom을 메모리에 복사해준 virtual dom이 등장함.가상 돔은 브라우저 문서에 직접 접근하여 화면 요소를 수정할 수 없음.가상 돔 virtual dom 작동방식랜더링 이전 가상돔과 바뀐 가상 돔을 비교 → Diffing바뀐 부분만 실제 돔에 적용시켜주는 것 → reconciliation (재조정)재조정 과정에서 바뀐 state가 n개라면 n번 조작하는 것이 아닌 한번의 dom조작으로 변화를 반영함. → batch update리액트 기본구조webpack 은 src내 파일만 처리함.전개 연산자객체const obj1 = { a: 'A' }; const obj2 = { b: 'B' }; const objWrap = {obj1,obj2}; console.log(objWrap) /*{ obj1:{ a: 'A' }, obj2:{ b: 'B' } }*/ const objWrap2 = {...obj1, ...obj2}; console.log(objWrap2); /* { a: 'A', b: 'B' } */ SPASPA에서 페이지 전환(브라우징)은 html5의 history api를 사용해서 가능하게 함.history.back() : 브라우저의 뒤로가기 효과history.go(): 특정 세션기록으로 이동하게 해주는 비동기 메서드. 1을 넣으면 바로 앞페이지/-1을 넣으면 바로 뒤페이지로 이동history.pushState(): 주어진 데이터를 세션 스택에 넣음.React Hooksclass없이 state를 사용할수 있는 기능TailWindCSShtml안에서 css스타일을 만들게 해주는 css 프레임워크빠른 스타일링이 가능하며 class혹은 id명을 작성하지 않아도 됨.리액트 불변성배열과 객체 같은 참조 타입은 불변성을 가지고 있지 않음.(mutable)리액트에서 화면을 업데이트할때마다 변경된 부분을 확인해야하므로 불변성을 지켜줘야함. → spread 연산자, map, filter, slice, reduce 활용(splice, push 는 원본 데이터 변경함.) useDebouncedebounce란 검색 입력에 입력결과가 나타날때까지 지연이 있는 기능위 기능을 사용하지 않으면 입력한 모든 문자를 처리해서 성능이 저하됨.2) 학습 내용에 대한 회고그동안 React로 토이 프로젝트를 하면서 겉핡기식으로만 알고 있었다는 것을 절실히 깨달았다. 이번주 강의를 수강하며 성능을 고도화시키기 위해 hooks를 만들어 사용하는 점을 배웠다. 아직 부족하지만 앞으로 사이드 프로젝트를 하면서 적용해봐야겠다.미션1) 미션 해결 과정문제 현상예산 계산기 앱을 구현하며 예상치 못한 문제가 발생했다. 예산 데이터 리스트 Lists 컴포넌트 아래 각각의 데이터를 나타내는 List 하위 컴포넌트를 구현했다. 하지만 List 컴포넌트가 화면에 보이지 않았고 에러 메시지도 없었기 때문에 당황스러웠다.원인List 컴포넌트를 map 함수로 표기하는 과정에서 JSX 반환코드를 {} 안에서 사용한 것이 문제였다. 이러한 경우에는 return 키워드로 반환하거나 ()로 감싸서 반환해야한다. 해결방안//변경 전 코드 const Lists = ({ budgetData }) => { return ( <div> {budgetData.map((data) => { <List key={data.id} id={data.id} title={data.title} price={data.price} />; })} </div> ); }; //변경 후 코드 const Lists = ({ budgetData }) => { return ( <div> {budgetData.map((data) => ( <List key={data.id} id={data.id} title={data.title} price={data.price} /> ))} </div> ); };  2) 미션 해결에 대한 회고타이핑 테스트 앱wpm, cpm 등 각각의 기능을 계산하는 방법을 파악하는데 시간이 꽤 소요됐다. 또한, 글자를 타이핑하면서 실시간으로 맞은문자, 틀린 문자를 초록색, 빨간색으로 변경하는 방법도 고민됐었다. 다른 사람들에겐 쉬운 과제였을수 있겠지만 나에게는 생각보다 고려해야할 부분이 많았던 과제였다.2. 예산 계산기 앱오랜만에 리액트 앱으로 개발을 하게되어 떨리는 마음으로 과제를 시작했다. 중간점검 때 강사님께서 어느정도 관습성을 가진 코드가 좋은 코드라 했던 말이 떠올랐다. 그래서 강의에서 다뤘던 내용을 중심으로 따라가다보니 재미를 느끼며 개발을 할 수 있었다. 물론, 모방이 주가 아닌 본인만의 색깔을 가져야 한다고 하셨으니 나만의 색을 가진 코드를 짤 수 있도록 개발 역량을 쌓아야겠다.3. 디즈니 플러스 앱아직 구현할 기능들이 조금 남아있지만 확실히 swiper와 같이 라이브러리를 추가하면서 겪는 문제들이 많아졌다. 그러다보니 시간이 더 오래걸리는 것 같다. 그래도 끝까지 마무리하는 습관을 가져야지!👏

프론트엔드