[인프런 워밍업 스터디 클럽 0기_BE] 1주차 회고록 정리
주차 별 내용 간단 정리
Day1
강의
서버에 대한 내용과 네트워크에 대한 개념적인 내용을 배웠습니다.
네트워크 : 두대 이상의 컴퓨터를 연결하고 통신
도메인 : 인터넷에 연결된 컴퓨터를 사람이 쉽게 기억할 수 있도록 만든 주소
라이브러리와 프레임워크 차이에 대한 내용
라이브러리 : 프로그래밍을 개발할 때 필요한 구조나 기능들을 모아두고 개발자가 직접 코드 구현하는 것
프레임워크 : 개발에 필요한 것들을 미리 구현 후 필요시에 꺼내 사용하는 것
HTTP API에 대한 내용과 설명
내용 정리
API : 정해진 약속이나 규칙에 따라 특정 기능을 수행
URL : 인터넷 상의 자원을 찾기 위한 주소
( 프로토콜 / 구분기호 / 도메인 이름, 포트 -> IP는 도메인 이름으로 대체 가능 / 자원경로 / 쿼리 스트링 )
HTTP 요청 메서드
GET : 데이터 조회시 자주 사용하며, 쿼리 스트링을 통해 정보를 전송
POST : 데이터 저장시 자주 사용하며, Body에 담아 요청 정보 전송
PUT : 데이터를 수정할 때 , PUT이외에도 PATCH방식도 있음
DELETE : 데이터 삭제 요청을 보낼 때 사용
Client와 Server
Client : 요청을 보내주는 사람
Server : 요청받은 요청에 따라 필요한 응답을 내려주는 사람
GET
/portion?color=red&count=2
Host: spring.com:3000
GET방식으로 PATH는 /portion 쿼리 스트링은 color : red , count : 2
서버는 spring.com:3000
파라미터 보내는 방식은 (키,값) 으로 되어있습니다.
@Getter
public class CalculatorAddRequest {
private final int number1;
private final int number2;
public CalculatorAddRequest(int number1, int number2) {
this.number1 = number1;
this.number2 = number2;
}
}
DTO객체를 생성하여 값을 받는 것을 확인했었습니다. 평소에 DTO 객체를 사용할때 요청,응답에 대한 DTO객체를 하나로 묶어서 사용을 했었지만 강의를 보고 DTO 객체는 요청과 응답에따라 각각 객체를 생성해주는 것이 좋다 생각했습니다.
또한 Setter함수는 사용하는 것을 지양하기때문에 생성자로 값을 받아오는 작업을 진행했습니다.
@RestController
public class CalculatorController {
@GetMapping("/add")
public int addTwoNumbers(CalculatorAddRequest request){
return request.getNumber1()+request.getNumber2();
}
}
@RestController : 해당 클래스를 API 진입지점으로 만들어주는 어노테이션 컨트롤러
@GetMapping : GET방식 요청 정보를 받는 어노테이션
@RequestParam : 요청된 쿼리 스트링에 대한 파라미터
미션
첫번째 미션 접근 방식은 어노테이션 사용 이유와 나만의 어노테이션을 작성하는 것이였습니다.
어노테이션에 대한 내용을 파악하고 코드로 사용을 사용했지만 직접 만들어본적은 없기때문에 많이 헷갈렸던거 같습니다.
또한 어노테이션을 사용하는 이유에 대해 정확하게 정의를 내리지 못했지만 1주차 과제를 진행하며 많이 얻어갔던 것 같습니다. 나한테 들리는 왜?라는 질문에 대한 대답을 하였던 것 같아 재밌었던거 같습니다.
한가지로 아쉬웠던 점으로는 문서 작성에 대한 미숙함으로 인해 두서없이 작성되는 것같아 다음에 잘 작성해야겠다 생각했습니다.
정리 : https://silvercastle.notion.site/1-aea485f7cd5a433a8fb52715b16a81c9?pvs=4
Day2
강의
POST요청을 받기위해 Body에 데이터를 담아 보낸다.
Body에 데이터를 보내는 방법으로는 JSON형태로 보내면 된다.
JSON이란?
데이터를 쉽게 교환하고 저장하기 위한 표준 방법
형식은 (키 : 값) 형식으로 되어있으며 자바에 자료구조인 Map과 유사합니다.
작성 방법
1. 처음 작성시 중괄호가 들어간다 배열은 []로 생성하면된다.{ //중괄호 생성 객체가 생성이 되었습니다. }
2. 중괄호 안에 (키,값)형태로 표기 숫자는 큰따옴표가 들어가지 않으며, 속성은 쉼표로 구분합니다. 배열 작성시 위에 내용과 마찬가지로 []을 넣으면된다. JSON에 또 다른 객체를 넣고 싶다면 {}를 넣어 표현하면 됩니다.
{
"name" : "이은성",
"age": 1000,
"pocket" : ["핸드폰","지갑"],
"info" : {
"address" : "서울",
"phoneNum" : "010-1111-1111"
}
}
서버(SpringBoot)에서는 어떤 방식으로 POST요청에 대한 Body 데이터 값을 받을까?
{ "number1": 1, "number2": 2 }
public class CalculatorAddRequest { private final int number1; private final int number2; //생성자.. //getter }
@PostMapping("/multiply") public int multiplyTwoNumbers(@RequestBody CalculatorAddRequest request){ return request.getNumber1() * request.getNumber2(); }
@PostMapping : POST방식으로 요청을 받기 위한 어노테이션
요청한 Body에 대한 key값과 DTO에 정의한 key값은 일치 해야합니다.
@RequestBody : HTTP Body로 들어오는 JSON을 변환해주는 어노테이션
CalculatorAddRequest에 요청받은 JSON값을 넣어준다.
유저 생성/조회 API 개발
사용자를 등록하려면 POST방식을 사용하며, 이름(필수)과 나이(선택)에 따라 요청이 들어왔습니다.
요청을 받은 값을 Controller에 받아 List 자료구조에 값을 저장했습니다.
유저를 조회하기 위해서 List.get(index)를 활용해야하는데 이것이 id값으로 id는 겹치지않은 유니크한 값입니다. 고유한 번호로 있으면 중복되는 문제는 없습니다.
여기서 문제점은 List에 저장하는 방식은 메모리에 저장하는 방식으로 웹서버를 재시작하는 경우, 기존에 있던 값들이 날아가는 문제가 있어 서비스 운영이 어려워집니다. 이를 해결하기 위해선 어떤 방안이 있을까요?
미션
첫번째 미션은 두 수를 입력하면 다음과 같은 결과가 나오는 GET API를 만들자
제가 설계한 방법으로는 요구사항대로 첫번째 쿼리스트링이기때문에 @RequestBody를 사용하지 않아야 된다 생각했으며, 강의에서 배운 DTO객체를 request와 response를 나눠 작업을 진행했습니다.
첫번째 문제는 크게 어렵지 않았습니다.
두번째 문제는 날짜를 입력하면 무슨 요일인지 알려주는 GET API를 만들어보는 것이였습니다.
코치님이 조언해주기를 LocalDate를 활용해보라해서 넘어오는 날짜 : yyyy-mm-dd 형식으로 받아오는것을 String으로 받아와 자바에서 지원하는 LocalDate를 활용하여 String값을 split하여 of에 넣어주는 작업을 진행 후 getDayOfWeek과 getDisplayName에 있는 메서드를 활용하여 진행했습니다.
하지만 추가적으로 LocalDate를 사용하는 방법중에 yyyy-mm-dd를 직접넣어 파싱해주는 메서드를 찾았고 그것을 활용하여 사용해봤습니다.
코치님께서 모든 과제를 확인후 String을 받지않고 직접 LocalDate를 파라미터 값으로 받아 사용하면 훨씬 코드가 깔끔해진다는 내용을 듣고 앞으로 설계할때 고려해야겠다 생각했습니다.
LocalDate나 LocalDateTime에 대해 자주 사용해보지 않았지만, 내용들을 이해하며 사용해보니 많이 와닿았습니다.
[노션] : https://silvercastle.notion.site/2-3d17d8447562464eb081c340bbfbdfc8?pvs=4
Day3
강의
Day2에서 고민한 내용에 대한 답변은 데이터베이스를 활용하여 데이터를 저장하는 방식을 사용하면 좋습니다.
실무에서 회사내에서 데이터베이스를 어떤방식으로 활용하면 좋을지 고민을 많이 했고, 아직 많이 부족한 실력이라 인지하고 있습니다. 또한 RDBMS를 지금까지 MariaDB,PostgreSQL을 사용해보았고 물론 크게 다른 점은 없지만 MySQL을 활용해보는 계기가 되었습니다.
DDL : 데이터 정의 언어로 데이터를 생성, 수정, 삭제 등의 데이터 전체 골격을 결정하는것을 이야기합니다.
create database [데이터베이스명] : 데이터베이스(스키마)를 만드는 명령어입니다.
show database : 현재 생성되어있는 데이터베이스를 확인하는 명령어입니다.
drop database [데이터베이스명] : 데이터베이스(스키마)를 삭제하는 명령어
show table : 테이블 목록을 보는 명령어
create table [테이블명] ( 필드이름 속성 부가 기능 primary key(필드) ) : 테이블을 생성하는 명령어 입니다.
속성에는 정수,실수,문자열,날짜등이 있습니다.
id값은 표현을 할수있는 정수의 크기가 많은 long을 사용하는 것이 좋습니다 int는 2의32 long은 2의64이기때문입니다.
DML : 데이터에 대한 CRUD(생성, 조회, 수정, 삭제)에 대한 데이터를 관리합니다.
INSERT INTO [테이블 이름] (필드1, 필드2) VALUES (필드1값,필드2값) : 테이블에 값을 생성하는 명령어입니다.
필드1,필드2 = 필드1값,필드2값 이런식으로 위치를 맞춰줘야하며 필드값이 달라지면 안됩니다. 순서가 매우 중요합니다 원하지 않은 데이터가 들어갑니다.
Select [조회할 필드 명] from [테이블] where [조건 문] .. : 테이블 안에있는 원하는 필드명을 가져와 조건에 따라 조회하는 명령어입니다.
조건문의 연산자로는 and,or,between,IN 등등이 있습니다.
Spring에서 Database 연결하는 방법
spring: datasource: username: "root" password: "1234" url: "jdbc:mysql://localhost:3306/library" driver-class-name: com.mysql.cj.jdbc.Driver
yml방식으로 데이터베이스에 필요한 정보를 가지는 명령어입니다.
아이디, 비밀번호, url, driver로 구성되어있으며, 만약 일치하지 않거나 DB서버가 죽었을경우 컴파일 과정에서 문제가 발생합니다.
코드에서 직접 구성하기
기존에 있는 코드에서 List를 지우고 JdbcTemplate을 사용하여 쿼리를 직접 작성하고 사용해보는 작업을 진행했습니다.
String sql =""; 으로 쿼리를 제작하고
jdbcTemplate메서드를 사용하여 jdbcTemplate.update, jdbcTemplate.query를 활용하여 CRUD의 기능을 구현했습니다. 여기서 update는 업데이트문이 아닌 쿼리 변경에 대한 업데이트처리를 위한 메서드입니다.
저는 시작을 jdbcTemplate이 아닌 Mybatis와 JPA같은 기술스택을 먼저 사용해보고 이후로 사용을 했는데 예전 개발자님들은 상남자이며, 정말 예외에 대한 처리를 하나하나생각하기 머리가 아팠을꺼같습니다. 그리고 이전기술을 사용하니 JPA와 MyBatis와 같은 기술들이 얼마나 간편하고 좋은지에 대해 알아갔습니다.
미션
과제에 대한 내용중에 익명클래스,람다,Stream문 ,함수형 프로그래밍 @FunctionalInterface, 메소드 레퍼런스등을 정리하며 기존에 인텔리제이에서 제안 및 변환작업만 자동으로 진행했지 이게 무슨 내용인지에 대해 찾아보려 하지 않았습니다. 정말 인텔리제이는 좋은 도구지만 용도를 더 잘 알고 사용하는 것이 나중에 1000퍼 더 이해되기 쉽다를 느꼈습니다.
또한 익명클래스와 람다식에 대한 차이점과 람다식을 왜 등장했는지에 대한 내용을 정리하며, 동작원리를 이해하고 이래서 익명 클래스에 대한 불편함과 그로인해 람다를 사용하는 방법을 알았습니다. 점점 더 내안의 "왜?"를 채울 수있어서 좋았습니다.
[노션] : https://silvercastle.notion.site/3-f34ffaa6ae8147d58f24659af459bf9e?pvs=4
Day4
강의
기존에 배웠던 내용을 가지고 유저 업데이트API, 삭제 API 개발과 테스트를 진행을 해보았습니다.
HTTP body
{
"id" : Long,
"name" : String
}
HTTP Response : Void // 200 OK!
HTTP Method : PUT
HTTP Path : /user
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request){
String sql = "update user set name = ? where id = ?";
jdbcTemplate.update(sql, request.getName(),request.getId());
}
HTTP Method : DELETE
HTTP Path : /user
@DeleteMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request){
String sql = "delete from user where name = ?";
jdbcTemplate.update(sql, request.getName());
}
이전 강의에서 마찬가지로 코드를 sql문과 update를 활용하여 데이터베이스 변경작업을 진행했습니다.
기존에 준 웹 UI를 가지고 변경과수정 작업을 진행했습니다.
또한 예외처리를 배웠는데 사용자가 없을경우? 이런저런것에 대한 처리가 되어있지않아 서비스를 운영할때 큰 문제로 다가올 수 있습니다.
String readSql = "SELECT * FROM user WHERE id= ?";
boolean isUserNotExist = jdbc.query(readSql,(rs,rowNum) 0,request.getId()).isEmpty
if(isUserNotExist){
throw new IllegalArgumentException();
}
사용자의 정보에 대해 조회를하고 만약 존재하지 않는다면 List가 공백으로 나오며 , 비어있다면 true 비어있지 않으면 false로 반환하는 코드를 작성 후 인자값 오류에 대한 예외처리를 진행했습니다. 이것말고 다른 예외처리도 생각을 꼭꼭해야합니다. 그래서 개발하기 전에 어떤 문제를 야기할지 생각한 후 코드를 개발하는것이 더 좋다 생각합니다.
하지만 Controller메서드들에 너무 많은 기능과 역할을 하고있다 생각하고 있습니다. 나중에 코드가 1000줄이상 늘어나면 보기 복잡해질 것이며, 가독성과 유지보수성이 떨어져 개발하면서 어려움을 겪을 수있습니다. 나중에 Day5의 강의의 클린코드를 통해 변경하는 작업을 진행해야겠다 생각했습니다.
미션
문제별로 설계 방법은 첫번째로 어떤 table을 제작해야할지, table안에 어떤 column을 생성하면 좋을지 분석 및 구현을 진행했으며, 두번째로 패키지구조를 나눠 각 메서드마다 역할분담을 해야한다 생각했습니다.
문제를 해결하면서 3번문제를 잘못 읽는바람에 시간이 소요되는 문제가 있었습니다. 항상 개발자는 요구사항에 대한 분석을 해야한다 느꼈습니다.
시간이 부족한탓에 예외처리를 완벽하게 처리를 하지 못했는데 나중에 그것도 설계해서 예외처리를 둬야겠다 생각했습니다.
[노션] : https://silvercastle.notion.site/4-9621a06cc0d24a63871a9f50e8c6cd48?pvs=4
Day5
강의
CleanCode의 중요성
개발자는 요구사항을 구현하기 위해 코드를 읽고 작성
그런데 코드가 만약 지저분하고 더럽다면 코드를 이해하는데 많은 시간이 들어 유지보수성이 떨어진다.
좋은 코드는 코드만봐도 어떤 목적을 가진 것인지 확인할수 있다.
더 나아가서 이전에 작성했던 코드들에 대해 생각을 해보면 Controller에 모든 기능을 구현하면 안될까?
네 메서드는 하나의 기능을 수행하는 것이 좋습니다.
@GetMapping("/user") public List<UserResponseDto> getUsers() { String sql = "select * from user"; return jdbcTemplate.query(sql, new RowMapper<UserResponseDto>() { @Override public UserResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException { long id = rs.getLong("id"); String name = rs.getString("name"); int age = rs.getInt("age"); return new UserResponseDto(id, name, age); } }); }
해당 코드는 조회하는 쿼리에 대해 대한 컨트롤러 메서드입니다. 딱 봐도 기능적 분리가 필요해보입니다.
sql문은 어떤식으로 분리하면 좋을까?라는 생각과 비지니스로직을 어디다 분리 할까 생각하다 Layered Architecture
에대해 배운 내용을 바탕으로 나눴습니다.
Controller : HTTP Body 요청을 받아 객체로 변환하는 계층
Service : 비지니스로직(현재 유저 확인)기능이 동작하기 위한 작업을 진행하는 계층
Repository : 데이터베이스와 접근 및 상호작용을 하기위해 나타나는 계층
UserController
@GetMapping("/user")
public List<UserResponseDto> getUsers() {
return userService.getUsers();
}
UserService
public List<UserResponseDto> getUsers() {
return userRepository.getUser();
}
UserRepository
public List<UserResponseDto> getUser() {
String sql = "select * from user";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
long id = rs.getLong("id");
String name = rs.getString("name");
int age = rs.getInt("age");
return new UserResponseDto(id, name, age);
});
}
해당 3계층으로 나눠 진행했습니다! 해당 기능을 분리를 진행했으며, 이전 코드에 비해 깔끔해졌으며 나중에 코드를 추가및 변경할때 해당 계층으로 들어가 작업을 하면 됩니다.
미션
오랜만에 코딩테스트 문제 풀듯이 풀어 재밌었다.
첫번째방식은 기존에 긴 코드에 대한 기능에 대한 분리를 진행을 해봤습니다. 객체지향 SOLID 특징 중 SRP(단일 책임 원칙)을 생각하여 나누려고 진행했습니다. 나눈 기능에 대한 세부 동작을 나눴으며, 그로 인해 클래스를 나눠 구현하도록 설계를 진행했습니다. 또한 애매한 변수 네이밍, 메서드 네이밍에 대한 수정도 이루어지도록 생각을 했습니다.
코드를 수정후 한 걸음 더에 대한 요구사항에 대한 제 분석은
현재 코드는 1~6이지만 동적으로 변경할 수 있는 방법
주사위의 시행 횟수를 동적으로 변경하는 방법
해당 방법 2가지를 생각했으며, 그에 따라 정적배열, for문등등을 활용하여 작업을 진행했습니다.
[노션] : https://silvercastle.notion.site/5-89b621e69f094263af872580ac19324c?pvs=4
1일차 전체 후기
첫 주차정리를 했는데 문서에 대한 내용이 너무 두서없이 작성되어 다음 주차부터는 깔끔하게 문서 작성하도록 노력해야겠다 생각했습니다.
내가 알고있다고 생각했던 내용에 대해 다시 들으니 아 이런 내용을 몰랐다고? 하는 내용도 많고 기존에 알고있던 내용도 혼동되었습니다. 내가 알고있다고 자만?하지말고 계속 기본기를 쌓아 공부를 해야겠습니다.
코치님에게 질문을 드렸고 만족한 대답을 들어서 너무 행복하고, 몰랐던 내용과 애매한 내용에 대해 배울 수 있어서 너무 좋았습니다.
회사를 다니면서 강의를 듣는 상황이 오니 좀 더 체계적으로 시간을 잡아 진도를 따라가야겠다 생각했습니다.
댓글을 작성해보세요.