블로그

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 구현하기클린코드 이해하기 마무리우려하던 일은 현실이 돼버렸다. 컨디션 관리에 실패했다. 궁금한 주제를 탐구하기도 하고 딴짓을 하다 늦게 잠들었다. 수면패턴이 꼬이고 생산성도 저하됐다. 결국 시간을 알차게 보내지 못했다. 과제를 해결하는데 급급하기도 했고, 진도표를 몰아서 듣기도 했다. 연쇄반응으로 걱정도 늘어났다. 불행 중 다행으로 긍정적인 사실도 찾을 수 있었다. 잠(루틴)의 중요성을 느꼈다. 푹 자고 일어나서 루틴을 다시 시작하니 금방 제모습으로 돌아왔다. 이외에도 다양한 주제를 탐구하다 보니 견문이 넓어졌다. 시간을 효율적으로 보내고 얼른 접하고 싶은 욕심이 든다.

백엔드인프런워밍업클럽

90년대 컴퓨터 공학 이야기 (2) — 컴퓨터 공학과

다행히 수험생 시절 공부를 꽤 열심히 해서 과를 골라서 지원할 수 있는 상황이 되었고, 더 많은 운을 기대하며 자연스럽게 컴퓨터가 들어가는 과를 찾아 지원하였는데, 관련된 이야기 몇 가지…컴퓨터 공학 vs 전자계산기공학원서 접수 시 무의식적으로 다른 과 대비해서 과 이름이 멋지다는 생각을 했었다. 10대의 마음에 아마 과의 이름이 예전의 전자계산기공학이었으면 지원을 하지 않았을 것이다. 당시 한국의 입시 제도는 학교와 과를 먼저 선택하고 주어지는 경쟁률에 따라 시험 성적으로 우열을 매기는 개인적인 생각으로는 당일의 운이 매우 중요했던 기억이다.과 연혁을 보면, 1978년에 전자계산기공학과 줄여서 전산기공으로 불렸었다 한다. 당시 국립대의 학과 이름에 영어를 쓸 수 없던 규칙이 있었더랬고, 1988년 올림픽을 지나면서 조례가 바뀌어 영어 이름이 과에 허락이 되었고, 컴퓨터공학으로 바뀌었다고 한다. 당시 이 혜택을 받은 과가 컴퓨터공학과와 산업디자인학과, 두 과 모두 이름의 버프를 받아서 당분간 각 단과대의 대표주자가 되었다고 한다. 몇 년 위 선배들은 2지망으로 의대를 내려 보내기도 하고 전체 수석 선배님도 계셨더랬다.컴공 ? 전전제 ? 전산 ?당시 입시 정보로 컴퓨터를 만지려면 갈 수 있는 과는 아래의 세가지,공과대학 컴퓨터공학과 — 정원 75명공과대학 전기전자제어공학과군 — 정원 270명자연과학대학 계산통계학과 전산과학전공 — 정원 30명 소위 과 이름의 ‘간지’를 찾아서, 그리고 적당한 인원(?)이 끌려 지원을 했고, 아마도 증원 ( 60 → 75 ) 의 혜택으로 합격을 했던 거 같다. 흐릿한 정보로 소프트웨어와 하드웨어 둘을 반반씩 하려면 컴퓨터공학이 맞다고 하였고, 전전제의 경우 2:8 , 전산과의 경우 9:1 의 비율이 소프트웨어와 하드웨어의 비율이라 했었다.과 이름이 주는 오해도 나름 상당해서 게임을 만들고 싶어 했던 신입생 후배들이 여기가 아닌가 해서 실망해 하던 기억들과 각종 올림피아드에서 날고 기던 아이들이 시대에 뒤떨어진 교수님이라며 불평을 하던 시기도 금방 왔었다. 대학 생활 중에 인터넷, PC 통신, 스타크래프트까지, 삐삐에서 핸드폰까지, 지금 돌이켜 보면 아이폰 빼고 모든 일이 벌어진 세상이었으니 그 와중에 어떤 역할을 잡았어야 하나 모두가 고민 많았었던 시기였으리라.컴퓨터 공학부1999년 석사 졸업하던 해까지 나는 영향이 없었지만 이후 다양한 학부 대학원의 통폐합이 있었고, 우여곡절 끝에 지금은 자연대의 전산과와 합쳐서 컴퓨터공학부로 정리되어 왔다 ( https://cse.snu.ac.kr/greetings ). 위의 30명 전산과 동기들과 졸업 후 동문이 되었지만, 접점이 없던 탓에 사회에서 한 번씩 만나도 많이 서먹하긴 하다. 나이가 꽤 들고 멀리서 고생을 좀 하고 나서는 뭐 많이 둥글둥글해 진 것도 사실이겠다.

교양컴퓨터공학90년대

김찬희

[인프런 워밍업 클럽 스터디 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와 같이 라이브러리를 추가하면서 겪는 문제들이 많아졌다. 그러다보니 시간이 더 오래걸리는 것 같다. 그래도 끝까지 마무리하는 습관을 가져야지!👏

프론트엔드

홍승찬

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

두 번째 발자국배운것들스프링 컨테이너의 의미와 사용 방법국비교육에서 이미 스프링 컨테이너에 대해 배웠었기 때문에 어느 정도 알고 있었는데, 강사님의 상세한 강의로 모르고 있었던 개념들과 헷갈렸던 부분들을 확실하게 잡고 갈 수 있었다. 특히 "@bean 어노테이션의 경우 메서드에 사용하고, @Component어노테이션은 클래스에 사용한다" 라는 것만 알고 있었는데, 기존에 이미 사용하고 있었던 어노테이션들도 @Component를 사용한 것이 었다는 것을 알고 더 깊게 이해할 수 있었다.  Spring Data JPA를 사용한 데이터베이스 조작이제까지 MyBatis만 사용하고 SQLMapping기술만 사용해서 어떻게 sql을 쓰지 않고 DB를 조작할 수 있는지 의문이었는데, 강의를 듣고 JPA에 대해 알아가면서 SQLMapping기술과는 너무 달라서 충격이었다. 단지 JpaRepository를 상속받은 인터페이스를 만든 것 만으로 SQL없이 DB를 조작하는 것을 보고 너무 생소해서 필기하면서 공부하고 복습이 필요하겠다는 것을 느꼈다. 그리고 이제까지 MyBatis처럼 JPA가 하나의 라이브러리인줄 알았는데, JPA는 하나의 규칙이라는 것을 새롭게 알게 됐다. JPA의 구현체 중 하나가 Hibernate이며 이 전체를 쓰기 쉽게 해주는 것이 Spring Data JPA 라이브러리이다. 라는 부분을 들으면서 JPA에 대해 하나도 몰랐구나를 알게 됐다.. 트랜잭션과 영속성 컨텍스트JPA를 사용하면서 가장 흥미로웠던 부분이 Update부분이다. 기존 자료를 수정하기 위해서는 Update 쿼리를 날려줘야하지만 JPA에서는 도메인 내부에서 데이터 수정함수를 만들면 기존 데이터에서 바뀐 데이터를 감지하고 update문을 알아서 날려준다는 것이다. 이 부분이 가능했던 이유가 영속성 컨텍스트 라는 것의 변경감지 기능 덕분이다. 이 외에도 쓰기지연(여러 sql문이 commit될 때 한번에 저장됨/ DB커넥션비용을 절감), 1차 캐싱(ID를 기준으로 엔티티를 기억)등이 있다!회고저번주까지는 알고 있던 내용들이었기에 복습하는 과정이었다면, 이번주는 JPA를 다루기 시작하면서 새롭게 배우는 것들이 훨씬 많아졌다. 그중에서도 JPA 직접 다뤄보면서 SQL을 직접 만들어서 쓰던 것과 다르게 신세계를 경험할 수 있었다. 이제까지 따로 필기는 하지 않으면서 과제 정도만 진행했었는데, 배우는 내용이 많아지면서 필기를 하지 않으면 까먹겠다는 생각이 들어 뒤늦게 블로그에 배운 내용들을 올리고 있다. 이번주 금요일에 깜짝 라이브 방송이 있었는데, 까먹고 참여하지 못해서 너무 아쉬웠다. 다음주 금요일은 진짜 꼭 참여해야겠다. 

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

전재민

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

두번째 발자국배운 내용Inputbutton, checkbox, radio button, switch, labeltext field, text area, selected Displayavatar, accodion, badge, tooltips, dividerchip, card, table  5/7 8일차component 파트의 첫날button - 일반적인 버튼checkbox - 누르면 체크 표시가 뜨는 네모난 버튼radio button - 동그란 버튼switch - 스위치 버튼label - 버튼이나 다른 곳에 자주 쓰이는 텍스트이름 정해주고 properties 세팅하는게 서툴러서 힘들었지만 결과를 보니 뿌듯했다,5/8 9일차갑자기 몸살 감기가 걸려서 하루 밀리게 됨 5/9 10일차텍스트 박스 같이 글자를 입력할 수 있는 ui를 만들었다.text field - 일반적인 텍스트 입력할수 있는 바text area - text field보다 더 넓은 공간selected - 라디오, 체크박스가 선택되었을때 달라지는 ui대부분이 default, hover, press, focus, disabled, error 순으로 가서 점점 적응이 빨라졌다.그리고 이전에 등록했던 컬러 베리어블을 사용하면서 미리 등록하면 정말 편하다는걸 느낌.5/10 11일차display 컴포넌트를 시작한 날.처음 봤을 땐 간단해 보였지만 막상 해보니 제일 시간이 오래 걸렸던 날이다.avatar - 텍스트, 사진, 아이콘으로 만든 프로필accodion - 접고 펼 수 있는 컴포넌트badge - 카톡 알람 같이 오른쪽 상단에 있는 점, 999+tooltips - 메세지 같은 튜토리얼 바divider - 중간을 나누는 stroke이때 properties, 간격, 정렬 등 여러가지가 많이 꼬여버려 정리하는데 어려움을 느꼈다. 5/11 보충하루 밀린 과제를 마무리한 날하루씩 밀리면서 생각했던 건, 지금 커리큘럼의 하루 일정이 내가 소화할 수 있는 적절한 양이라는걸 알게됨chip - 간결하게 속성을 표시하는 uicard - 만능으로 쓰이는 카드 table - 헤더랑 셀로 만들어진 표개인적으로 table 만들때 쓴 한글더미 플러그인은 정말 마음에 들었다 느낀 점 + 아쉬운 점, 다음주는?전체적인 내용이 비슷비슷해서 초반은 좀 힘들었지만 후반에는 수월하게 진행된 주.중간에 아파서 하루가 밀렸는데 다시 따라잡기 힘들다는 걸 느낌.input에서 보너스 미션을 못한 게 아쉽다. -> 다음 주에 시간이 남으면 추가적으로 할 예정. 특히 컴포넌트를 만들고 결과물을 봤을 때 뿌듯함이 굉장히 컸었다. 다음 주는 밀리는 날 없이 또 빼먹는 거 없이 완벽하게 할 것이다  

UX/UI