블로그

볼드 UX

[인프런 워밍업 스터디 1기 디자인] 1주차 슬기롭게 보내기

발자국 1주차드디어 첫 주가 시작되었어요. 새로운 회사 일도 시작한 지 2주 차라 정신이 없었어요.조용하던 디자인 디스코드 채널이 드디어 활발해지기 시작했어요. 이번 주에는 코치로서 다음과 같은 일을 해야 했어요.폭발적인 강의 질문 대응하기미션 꼼꼼히 체크하기특별 강의 준비하기  첫째, 강의 질문 방에서는 수강생들이 강의를 듣기 시작하면서 질문이 쏟아졌어요. 조용하던 채널이 질문으로 가득 차는 것은 매우 바람직한 현상이에요. 둘째, 미션 제출이 시작되었어요. 평소에는 회사 일에 집중하고, 저녁 늦게나 새벽에 수강생들이 제출한 과제를 살펴봤어요. 처음에는 단순히 미션 여부만 확인하려고 했지만, 과제를 살펴보다가 몇 가지 흥미로운 점을 발견했어요.흥미로운 점 세 가지는 다음과 같아요:1. 같은 강의를 듣고도 실수를 반복하는 수강생이 있다는 것이에요. 이는 온라인 강의의 한계일 수 있어요.2. 이러한 실수가 일부 수강생에게만 나타나는 것이 아니라 반복적으로 나타난다는 점이고, 이것을 데이터로 정리해서 다른 수강생들에게도 요약 노트 등으로 알리면 좋을 것 같아요.3. 인프런 워밍업을 통해 수강생들의 작업 파일을 보고 코멘트를 남기며 피드백을 통해 서로 수정하고 올바르게 배울 수 있었어요. 셋째, 특별 강의를 준비했어요. 세 가지 주제로 구성하고, 강의 준비 과정은 쉽지 않았어요. 밤에 미션을 체크하고 남는 시간에 강의를 만들었어요. 특별 강의는 주로 새벽 5시에 일어나서 준비했고, 다음과 같은 주제로 구성되었어요.- 가장 많이 나오는 질문: 아이콘- 컴포넌트 네이밍 컨벤션- 멀티에딧 베리언츠인터랙티브한 강의를 만들기 위해 네이밍 컨벤션을 공유할 때는 혼동되는 용어에 대한 각 개인의 생각을 물어봤어요. 특별 강의는 기본 1시간을 넘어 20분 더 진행되었고, 많은 수강생이 마지막까지 남아 있었어요. 피드백을 부탁드렸는데, 마치고 나서 살펴보니 열심히 준비한 보람을 느꼈어요. (선정한 5개 수강평)  다음 주 월요일이 영국도 공휴일인이라 쉴 수 있어서 다행이에요. 그렇게 휴식을 취해야 회사 일과 인프런 코칭을 병행할 수 있을 것 같아요. 모두들 2주차도 파이팅입니다!

UX/UI인프런워밍업베리어블스터디디자인시스템

윤대

[인프런 워밍업 0기 Day2] 한 걸음 더! 메서드로 코드 재사용해보기!

!! 해당 글은 독자가 인프런 워밍업 0기를 수강하고 있다는 전제 하에 작성되었습니다 !!과제 수행에 있어 스프링부트 3.2.2 버전을 사용하고 있다는 점을 미리 알려드립니다! 안녕하세요🙌! 인프런 워밍업 2일차 과제입니다!2일차에는 API를 작성하는 방법에 대해서 배우고 그에 대한 과제를 받았습니다😎과제를 자세히 살펴보는 도중, 문제 1번과 3번 모두 덧셈을 수행하는 공통로직이 있다는 사실을 발견했습니다!따라서! 오늘은 제가 한 걸음 더 성장하기 위해 메서드를 통해 공통로직을 처리한 과정을 공유할 예정입니다~ ⚙️메서드 설계하기메서드를 만들 때, 제가 중요하다고 생각하는 것은 3가지입니다!메서드가 무엇을 할 것인가 (메서드 명)메서드가 무엇을 반환할 것인가 (리턴 타입)메서드가 무엇을 필요로 하는가 (파라미터)여기서, 중요한 점은 어떻게는 생각하지 않는다는 것입니다! 🙅‍♂️위의 3가지만 만족한다면 공통로직으로 볼 수 있기 때문에 메소드의 내부 로직은 추후에 생각해도 무방합니다! 자, 그렇다면 지금부터 문제 1번과 3번에서 각 절차를 수행해보겠습니다.첫째, 무엇을 할 것인가?문제 1번과 3번 모두 2개 이상의 숫자를 더해야 하는 상황입니다! 따라서, 저는 메서드 명을 addNumbers로 정했습니다.둘째, 무엇을 반환할 것인가?우리는 두 수를 더 한 값을 반환 받아야 합니다! int와 Inteager 등 다양한 숫자가 가능하겠지만, 저는 Inteager를 택했습니다!셋째, 무엇을 필요로 하는가?우리는 숫자를 더하기 위해, 2개 이상의 숫자를 필요로 합니다! 또한, 문제 3번의 경우 몇 개의 숫자가 입력될 지 알 수가 없습니다! 따라서 저는 List<Integer> numbers로 파라미터 값을 설정했습니다.이제 위의 세 부분을 합치면 제가 만들 메서드는 아래와 같은 형식이 될 것입니다!public Integer addNumbers(List<Integer> numbers);💡 int 타입의 경우 List로 받을 수가 없어 Integer를 반환 값으로 설정하였습니다! ⚙메서드 구현하기이제 설계가 끝났으니, 메서드를 구현할 시간입니다! for each문으로 List에 담긴 값을 하나씩 꺼내 더하여 값을 반환만 해주면 구현은 어렵지 않게 끝이 납니다!😎 public Integer addNumbers(List<Integer> numbers) { Integer result = 0; for (Integer number : numbers) { result += number; } return result; }자~ 이제 구현이 끝났으니 메서드를 적용해봐야겠죠? ⚙메서드 적용하기문제 3번먼저, 문제 3번입니다! 3번부터 풀이하는 이유는 1번 문제를 풀며 발생하는 문제 때문입니다!DTO (데이터를 전송 받고 보내는 객체)@Getter @Setter public class NumbersRequest { private List<Integer> numbers; }Controller @PostMapping("/api/v1/calc") public Integer addNumbers(@RequestBody NumbersRequest numbersRequest) { return addNumbers(numbersRequest.getNumbers()); }List<Integer>를 필드 값으로 갖는 NumberRequest를 입력받아 addNumbers()에 필드값을 전달했습니다!입력받은 숫자가 몇 개던지 메서드 내부에서 값이 잘 합산되어 반환될 것입니다! 문제 1번이번엔, 문제 1번을 해결해보죠! 😎DTO@Getter @Setter public class CalcResponse { private int add; private int minus; private int multiply; }Controller @GetMapping("/api/v1/calc") public CalcResponse calc(Integer num1, Integer num2) { List<Integer> numbers = new ArrayList<>(); numbers.add(num1); numbers.add(num2); CalcResponse response = new CalcResponse(); response.setAdd(addNumbers(numbers)); // minus와 multiply도 메서드로 구현해주었습니다! response.setMinus(minusNumbers(numbers)); response.setMultiply(multiplyNumbers(numbers)); return response; }값을 Integer num1과 Integer num2를 입력받기 때문에 입력 값들을 List로 변환해줘야 합니다.이렇게 하여도 문제는 없겠지만, 코드가 지저분한 게 영 마음에 들지 않습니다!그래서, 다음과 같이 코드를 변경해보았습니다!DTO (Request) 추가@Getter @Setter public class CalcRequest { private Integer num1; private Integer num2; public List<Integer> getNumbers() { List<Integer> numbers = new ArrayList<>(); numbers.add(this.num1); numbers.add(this.num2); return numbers; } }입력 값을 각각의 값이 아닌 하나의 객체로 변환하여 받고, 내부에 getNumbers()를 구현하여 입력받은 값을 바로 List<Integer>로 변환하여 받도록 하였습니다!이 DTO를 적용하면 Controller의 코드가 다음과 같이 바뀌게 됩니다! @GetMapping("/api/v1/calc") public CalcResponse calc(@ModelAttribute CalcRequest calcRequest) { CalcResponse response = new CalcResponse(); response.setAdd(addNumbers(calcRequest.getNumbers())); response.setMinus(minusNumbers(calcRequest.getNumbers())); response.setMultiply(multiplyNumbers(calcRequest.getNumbers())); return response; }훨씬 간결해졌죠? 참고로 @ModelAttribute는 쿼리 스트링으로 입력받은 값들을 확인하여 파라미터 타입으로 지정한 타입의 필드 값과 일치하면 자동으로 객체로 변환해주는 Annotation입니다!이렇게, 메서드를 사용하면 공통로직을 단일 메서드 내부에서 관리할 수 있게 되고, 코드의 반복을 줄일 수 있게 됩니다! 여러분도 코드의 중복이 보인다면 메서드로 한 번 만들어보는 것은 어떨까요? 지금 까지의 내용을 정리하면서 2일차 포스팅을 마치도록 하겠습니다! 💡정리 💡메서드를 설계할 때 중요한 것!메서드를 설계할 때는 어떻게는 생각하지 말자!무엇을 하고, 반환하고, 필요한 지 3가지만 충족된다면 공통로직으로 만들 수 있다!객체 내부에서 변환로직 만들기!여러 개의 Integer를 Controller에서 List로 직접 변환할 시 코드가 지저분해진다! @ModelAttribute를 활용하여 객체 내부에서 값을 변환하여 반환하자!

백엔드Spring인프런워밍업메서드API인프런SpringBoot

유원준

[인프런 워밍업 클럽(백엔드, 0기)] - 개별 정리 : 자바 어노테이션

스프링으로 프로젝트를 하면서 자바 어노테이션을 항상 사용해 왔지만 아직 잘 모르는 부분이 많은 것 같아서 1일 차에 대한 과제 제출 기간은 지났지만, 추가적으로 인프런 블로그를 통해 다시 한 번 정리해 보고자 한다. (1) https://twojun-space.tistory.com/178본인 블로그에 내용을 별도로 정리했지만 한 번 더 리마인드해 보고자 한다.   1. 자바 어노테이션(Java Annotation)1-1. 정의(1) 어노테이션은 사전적 정의로는 "주석"이라는 의미를 가지고 있지만 자바에서의 어노테이션은 소스 코드에 추가할 수 있는 일종의 메타 데이터라고 볼 수 있다.(2) 애플리케이션 레벨에서 처리되어야 하는 대상이 아닌, 컴파일, 런타임 시점에 코드를 어떻게 처리해야 할지 알려주기 위한 정보로 볼 수 있겠다.  1-2. 장점(1) 코드 가독성, 컴파일 시점에서의 오류 체크코드 레벨에서 동일하게 작성되기 때문에 코드의 가독성이 좋고, 일부 어노테이션의 경우 컴파일 시점에 문법 에러(아래에서 설명할 @Override, @FunctionalInterface)를 잡아주기도 한다. (2) 중복 코드 제거중복되는 어노테이션의 경우 공통화시킬 수 있고 재사용이 가능하기 때문에 코드의 중복을 줄이고 효율적인 코드 작성이 가능하다. (3) 커스텀 어노테이션 (사용자 정의 어노테이션) 사용 가능직접 용도에 맞게 커스텀 어노테이션을 작성할 수 있다. 프로젝트를 진행함에 따라 각각 필요한 제약사항들을 별도로 정리해서 커스텀 어노테이션 구성이 가능하다.  1-3. 단점(1) 런타임 시 발생할 수 있는 오버헤드만약 런타임 시점에 자바의 리플렉션(Reflection) 등을 사용해서 처리되는 어노테이션이라면 이 부분을 처리하기 위한 별도의 오버헤드가 발생할 수 있다 (성능 상 문제)    2. 어노테이션의 종류살펴볼 어노테이션의 종류로 총 2가지가 있다.(1) 표준 어노테이션(빌트 인 어노테이션)(2) 메타 어노테이션    3. 표준 어노테이션(1) 표준 어노테이션의 경우 자바에서 기본적으로 제공하고 있는 어노테이션이다. 대표적으로 아래와 같이 3가지가 있다. 3-1. @Override(1) 현재 메서드가 부모 타입 클래스 또는 인터페이스의 메서드를 오버라이딩했음을 컴파일러에게 명시하는 역할을 수행한다. 만약 형식에 맞지 않게 오버라이딩되었다면, 컴파일러가 이를 인지하고 오류를 발생시킨다.  3-2. @Deprecated(1) 현재 메서드를 사용하지 않도록 유도한다. 만약 해당 어노테이션이 붙은 메서드를 사용하면 컴파일러가 오류를 발생시킨다.  3-3. @FunctionalInterface(1) 해당 인터페이스가 함수형 인터페이스임을 명시한다. 함수형 인터페이스의 경우 추상 메서드가 반드시 1개 존재해야 한다. 추상 메서드가 존재하지 않거나 2개 이상이라면 컴파일러가 오류를 발생시킨다.    4. 메타 어노테이션(Meta Annotation)(1) 메타 어노테이션이란 다른 어노테이션에서 사용될 수 있는 어노테이션을 의미하며 아래에서 작성할 커스텀 어노테이션(사용자 정의 어노테이션)을 생성할 때 주로 사용되는 어노테이션이다.   4-1. @Target(1) 어노테이션을 적용할 위치를 알려주는 어노테이션이다. (2) 예를 들어 @Target(ElementType.TYPE)의 경우 해당 어노테이션을 다른 어노테이션의 대상으로 사용할 수 있다는 의미이다. (3) 메타 어노테이션을 선언해 줄 때 사용되는 일반적인 방법 중 하나다.@Target({ ElementType.PACKAGE, // 패키지 선언 ElementType.TYPE, // 타입 선언 ElementType.CONSTRUCTOR, // 생성자 선언 ElementType.FIELD, // 멤버 변수 선언 ElementType.METHOD, // 메소드 선언 ElementType.ANNOTATION_TYPE, // 어노테이션 타입 선언 ElementType.LOCAL_VARIABLE, // 지역 변수 선언 ElementType.PARAMETER, // 매개 변수 선언 ElementType.TYPE_PARAMETER, // 매개 변수 타입 선언 ElementType.TYPE_USE // 타입 사용 })  4-2. @Retention(1) @Retention의 경우 어노테이션이 적용되고 유지되는 범위를 설정하기 위해 사용되는 메타 어노테이션이다.@Retention(RetentionPolicy.RUNTIME) // 컴파일 이후에도 JVM에 의해서 참조가 가능하다. @Retention(RetentionPolicy.CLASS) // 컴파일러가 클래스를 참조할 때까지 유효하다. @Retention(RetentionPolicy.SOURCE) // 어노테이션 정보는 컴파일 이후 없어진다.  4-3. @Inherited(1) 해당 어노테이션이 적용된 경우 자식 클래스가 해당 어노테이션을 상속받을 수 있게 된다.(2) 따라서 부모 클래스에 선언된 @Inherited 어노테이션은 하위 클래스에서 자동으로 상속받는다.  4-4. @Repeatable(1) 반복 가능한 어노테이션을 정의할 때 사용될 수 있는 어노테이션이다.    5. 커스텀 어노테이션(Custom Annotation, 사용자 정의 어노테이션) 5-1. 정의, 사용 방법public @interface SimpleAnnotation { }(1) 자바에서는 위와 같이 @interface 키워드를 통해 커스텀 어노테이션을 정의할 수 있다.   5-2. 실제로 커스텀 어노테이션 적용해 보기@Retention(RetentionPolicy.RUNTIME) @Inherited @Target(ElementType.TYPE) @RestController @RequestMapping("/new") public @interface CustomMyAnnotation { String name() default "MemberController"; String value(); } @CustomMyAnnotation(name = "MemberController", value = "MemberController") @RequiredArgsConstructor public class MemberController { private final MemberService memberService; @GetMapping("/list") public List<MemberListResponseDto> getAllMemberList() { List<Member> allMemberList = memberService.findAllMembersList(); return allMemberList.stream() .map(member -> new MemberListResponseDto(member)) .collect(Collectors.toList()); } }  5-3. 자바의 리플렉션(Reflection)(1) 현재 어노테이션을 사용해서 코드의 가독성이 좋아짐은 물론 어노테이션 자체가 되게 많은 일을 대신 해주고 있는 것을 확인해 볼 수 있다. 이 부분은 자바의 리플렉션 기술들이 해결해 주고 있는데 추후에 리플렉션에 관한 내용을 블로그에 다시 한 번 정리해 볼 예정이다.  마지막으로 부족하지만 글을 읽어주신 분들께 감사드립니다!!  

백엔드백엔드인프런워밍업자바어노테이션스프링

김주민

[인프런 워밍업 클럽] 3주차 발자국

강의수강10일객체지향적 설계를 위한 연관관계에 대해서 다음과 같은 어노테이션을 배웠습니다.@ManyToOne내가 다수고 네가 1이라는 의미이다!도메인간의 관계를 맺기 위한 어노테이션이다.@OneToMany내가 1이고, 네가 다수이다!(mappedBy = "domain")관계의 주도권이 없는 쪽에다가 넣어야 한다!연관관계를 통해 코드를 효과적으로 작성 할 수 있다는 것 배웠습니다.!하지만 조금 복잡하고 어렵다보니 다시 재학습이 필요할 거같습니다!11일profile을 통해 어떨때는 MySql을 사용하고 어떨때는 H2DB를 사용하는 방법에 대해 배웠습니다.상황에 따라 여러가지 설정을 하는 방법은 매우 유용한것 같습니다.git은 버전관리툴, github는 git으로 관리되는 프로젝트 저장소!여러 git명령어를 간단하게 배웠습니다.아마 실무를 생각한다면 더욱 깊게 배워야 겠다고 생각을 하게 되었습니다.AWS 가입과 EC2생성을 배웠습니다.12일간단한 리룩스 명령어에 대해 배웠습니다.이 역시 더욱 깊이있게 배움이 필요하다고 생각합니다.EC2에 JDK, MySql을 설치하였습니다.'git에 올라가있는 프로젝트를 리눅스에서 바로 받아올수 있다는게 신기했습니다.스프링부트는 톰캣이 내장되어있어서 배포가 너무 편리합니다예전에 프로젝트할때는 Spring만 사용하여 Tomcat을 설치하는데 설정하는 것이 많이 어려웠습니다.foreground실행하는게 보이는 개념background실행하는게 보이지않는개념보이지 않지만 프로그램은 돌아가고있다!13일build.gradle는 프로젝트를 빌드하고 의존성 관리를 위한 파일로 groovy언어를 이용해 작성한 것이다!gradle에 대해 간단하게나마 개념을 잡을수 있었습니다.Spring과 Spring Boot의 역사와 등장 이유에 대해 알게 되었습니다.인간은 점점 기술을 발전시키면서 편의성을 높이는 것은 본능이지 않을까 라는 생각을 하였습니다.특히 Boot는 간편한 설정, 의존성 관리, 확장성등 강력한 기능을 제공하여 필수적이지 않나 생각합니다.Boot 버전업 application 등 간단한 개념을 알게 되었습니다.저는 기반 실무 스킬이 많이 부족하다고 생각합니다. 앞으로 git이나 리눅스에 대해 깊이있게 공부를 할 예정입니다.14일학원을 다닐때에는 프로젝트에 MyBatis만 이용하였습니다. JDBC템플릿보다 편의성과 기능성에 있어서 많이 놀랐는데 이번 강의를 통해 JPA에 대해 알게 되었고 JPA만의 장점이 많이 놀라웠습니다. 현재는 MyBatis가 많이 저물어 가고있는게 추세이기에 앞으로도 JPA에 대해 깊이있는 공부를 할 예정입니다.[미니 프로젝트]현재 미니프로젝트는 3단계까지 완성하였습니다.앞으로 4단계 까지 완성하고 배포 및 CI/CD를 공부하여 배포 자동화를 할 예정입니다.https://wise-elderberry-605.notion.site/0-b20f1518e96d45eda3b1775dfbc56acb정리우연찮은 기회로 인프런 워밍업클럽에서 3주간 함께 하게 되었습니다. 처음에는 당연히 '우수러너가 되야지' 라는 마음가짐이 있었지만 역시 뛰어난 실력자분들이 있기에 '나는 힘들겠구나' 라는 생각을 하였습니다.많이 아쉽지만 뛰어난분들의 코드를 보면서 오히려 더 많이 배우는 자리이도 하였습니다. 성격상 넉살이 없기에 소통을 하는게 많이 어려웠지만 별도의 커뮤니티가 있어서 다른분들이 질문하신것에서 많이 배우는 시간이기도 하였습니다.3주간 고생하신 강사님, 셰리님, 그리고 러너분들 앞으로도 더욱 열심히 공부해서 훌륭한 개발자가 되길 바랍니다. 감사합니다.

웹 개발워밍업클럽인프런워밍업워밍업클럽study

유원준

[인프런 워밍업 클럽 0기 백엔드] 3주차(최종) 발자국 (내용 정리)

인프런 워밍업 스터디의 마지막 주차가 마무리되어 가고 있습니다.3주차에 학습했던 내용들을 전체적으로 정리해 보고자 합니다.미니 프로젝트 수행은 하단의 깃허브 주소를 남겨두도록 하겠습니다.이전과 동일하게 학습한 내용, 미니 프로젝트 관련 내용들을 개인 블로그, 깃허브에 모두 정리하고 있습니다.하단은 학습 내용을 정리한 제 블로그 주소입니다.https://twojun-space.tistory.com/category/%EA%B8%B0%EB%A1%9D%2C%20%ED%9A%8C%EA%B3%A0/InFlearn%20Warming-up%200%EA%B8%B0%20BE (1) GitHub (Mini project)https://github.com/twojun/inflearn_warmingup_be_project   1. [11일 차] - 배포(Deployment), H2 DB를 통한 Profile 적용, Git & GitHub, AWS EC2(1) 11일 차 관련 학습 내용 개인 블로그 정리https://twojun-space.tistory.com/194 1-1. 배포의 뜻, 스프링 Profile(1) 애플리케이션에서의 배포의 뜻, 배포의 특징에 대해 알아보았다.(2) 사용자가 최종적으로 서비스를 이용할 수 있게 진행하는 일련의 작업으로 보면 된다.(3) 그리고 profile에 대해서도 알아보았는데 우리는 개발을 하면서 자연스럽게 profile 기능을 사용하고 있었다.(4) 이처럼 profile의 경우 똑같은 서버 코드를 실행시키지만 실행환경과 장소에 따라 각 다른 프로그램과 자원을 사용할 수 있도록 하는 것을 의미하게 된다.  1-2. Profile 적용(1) 간단하게 인메모리 DB인 H2 Database에 대해 알아보고, application.properties 또는 application.yml에서 DB profile을 설정하기 위한 옵션 적용이 가능함을 학습했다. (2) Run/Debug Configurations 메뉴에서 Active profiles를 yml 또는 properties에서 설정한 값으로 채워두고 서버를 실행시킨다.  1-3. Git & GitHub(1) Git, GitHub의 특징과 차이점을 알아보고 GitHub를 왜 많은 개발자들이 사용하고 있는지 그 장점과 특징에 대해 중점적으로 알아보았다. (2) git init, git remote, git status 등 Git의 기본적인 명령어 학습  1-4. AWS EC2(Amazon Web Service Elastic Computer Cloud)(1) 아마존에서 웹 서비스의 배포와 운영을 위해 제공하는 클라우드 서비스인 AWS EC2와 특징에 대해 학습했다.(2) AWS EC2를 통해 개발한 서비스의 배포와 운영을 위해 가상 서버 인스턴스를 생성할 수 있으며 애플리케이션의 트래픽, 규모 등을 고려하여 생성한 서버 인스턴스의 리소스를 확장할 수도 있다.  1-5. 11일 차 학습 내용 개인 회고(1) 개발만큼 배포와 운영 단계도 백엔드 개발에서 가장 중요한 부분이다. 이 부분에 대해 학습하고 실제 프로젝트에도 적용할 수 있는 능력을 기르고자 한다.   2. [12일 차] - AWS EC2 접속, 기본적인 Linux command, AWS Computing 환경에서 서버 배포를 위한 환경 구성, & 배포, 종료되지 않는 실행(foreground & background)(1) 12일 차 관련 학습 내용 개인 블로그 정리https://twojun-space.tistory.com/195  2-1. AWS EC2의 두 가지 접속 방법(1) key pair를 통한 접속 (Mac os의 경우 Iterm을 통해 접속 가능)(2) AWS Console을 통한 접속  2-2. 기본적인 리눅스 커맨드 학습(1) 디렉토리 생성 및 삭제, 경로 이동 등 기초적인 리눅스 명령에 대해 학습  2-3. AWS Linux에서 서버 배포 준비(1) 우선 Console에서 Git을 별도로 설치한다. (2) 서버 코드의 실행을 위한 JDK를 설치한다. (3) DBMS 설치(RDB : MySQL)  2-4. EC2 환경에서도 동일하게 데이터베이스 구성, 빌드와 배포(1) EC2 환경에서도 동일한 테이블 구조를 세팅한다. (2) Remote repository에서 Git Clone으로 기존 서버 코드를 모두 가져온다. (3) AWS EC2 Free tier의 경우 성능이 좋지 않다. 요즘은 가벼운 애플리케이션이더라도 서버 리소스를 많이 잡아먹기 때문에 Swap Setting을 통해 저사양의 인스턴스를 대상으로 메모리와 함께 추가적으로 스토리지도 함께 사용할 수 있도록 설정한다. (4) gradlew를 통해 빌드를 진행한다. 무료 서버를 사용하는만큼 테스트는 돌리지 않는 것이 성능상 유리하다. (5) 빌드 성공 시 빌드 디렉토리가 생성되고 내부로 이동하면 .jar 파일이 생성되어 있다. 이제 빌드된 .jar 파일을 통해 서버 실행이 가능한 상태이다. java -jar 명령으로 서버를 실행한다.  2-5. 종료되지 않는 실행(1) foreground & background의 차이에 대해 알아보았다. (2) nohup 명령어를 알아보고, 파일 내부를 확인할 수 있는 cat, tail 등 명령어에 대해 추가 학습했다.  2-6. 12일 차 학습 내용 개인 회고(1) 배포에 대한 전반적인 내용을 빠르게 학습해볼 수 있는 파트였던 것 같다. 서버 애플리케이션의 경우 대부분 리눅스 환경에서 다루어지기 때문에 리눅스에 대한 이해와 커맨드를 빠르게 체화시키는 부분이 중요할 것 같다.      3. [13일 차] - build.gradle, Spring & Spring Boot(1) 13일 차 관련 학습 내용 개인 블로그 정리https://twojun-space.tistory.com/196  3-1. build.gradle(1) build.gradle이 무엇인지 빌드 도구인 gradle이 무엇인지 알아보고 프로젝트에 필요한 의존성을 관리할 수 있는 도구임을 학습했다. (2) build.gradle을 이루는 plug-in, repositories, dependencies, dependencies에 대해 학습했다.  3-2. Spring & Spring Boot(1) Spring, Spring Boot를 시기별로 출시된 버전, 버전이 갖는 의미에 대해 학습했다. (2) 기존 스프링과 스프링 부트의 차이에 대해 학습했다.스프링, 스프링 부트와의 차이점 : (1) 간편한 설정 제공스프링, 스프링 부트와의 차이점 : (2) 간단한 의존성(라이브러리, 프레임워크) 설정 관리스프링, 스프링 부트와의 차이점 : (3) 강력한 확장성, MSA(Micro-Service Architecture)에 적합한 모니터링 기준 제공 등  3-3. application.yml(properties), Lombok library(1) application.yml, application.properties 모두 스프링 프로젝트의 전반적인 설정 정보를 정의하기 위한 파일로 볼 수 있다. (2) yml은 계층 구조를 갖고 properties는 동일한 key, value 타입이지만 계층 구조가 존재하지 않는다. (3) Lombok 라이브러리는 개발자에게 많은 편리성을 제공해주는 라이브러리이다. Getter, Setter와 같이 반복되는 Boiler plate code를 제거할 수 있게 도와준다.  3-4. 13일 차 학습 내용 개인 회고(1) 스프링으로 개발을 진행하며 의존성을 관리하는 도구인 build.gradle과 스프링, 스프링 부트의 차이점, 설정 정보를 관리하는 application.yml에 대해 학습할 수 있었다. 무심하게 사용해오던 도구들이지만 의미를 다시 한 번 더 정리하고 제대로 알고 사용할 수 있으면 좋겠다는 생각을 하게 되었다.   4. 14일 차 마지막 마무리 영상, 스터디 마지막 최종 회고(1) 마무리 섹션에서는 코치님께서 백엔드 개발에 있어 전체적인 학습 방향성을 개인적으로 조언해 주시는 시간과, AWS 호스팅 서비스의 과금 계산, 강의에서 소개되지 않았던 SQLMapper인 MyBatis, ORM 기반 기술인 JPA의 비교, 클라이언트 사이드 렌더링, 서버 사이드 렌더링에 대해 간단하게 정리해 주셨다. (2) 약 3주 간 온라인 강의와 세션 외에도 수강생들의 끊임없는 질문에 항상 웃으며 친절하게 대답해 주셨던 열정이 가득한 최태현 코치님, 열심히 배우고 성장하기 위해 끊임없이 달리는 러너분들이 있어서 스터디를 잘 마무리할 수 있었던 것 같습니다. 짧았다면 짧고, 길었다면 긴 시간이었지만 스터디를 완주할 수 있게 되어서 기쁘고 이번 스터디 수료를 통해 많은 성장은 아니지만 개인적으로 어느 정도 성장하는 데 도움이 되었다고 생각합니다. 스터디를 참여하면서 많은 분들을 만났고, 꾸준히 배움을 멈추지 않는 수강생분들을 보며 저 자신도 많이 반성하게 되었던 기간이었던 것 같습니다 다시 한 번 코치님, 러너분들, 이 스터디 기회를 만들어주신 인프런 관계자 여러분들께 감사하다는 말씀을 드리고 싶습니다. 코치님, 0기 백엔드 러너분들, 인프런 관계자분들을 항상 응원하겠습니다!모두 화이팅입니다. 😁  

백엔드인프런워밍업백엔드스프링발자국회고

윤대

[인프런 워밍업 0기] JPA findById() vs getReferenceById()

다음은 JPA에서 연관관계 매핑이 되어있는 객체를 save하는 상황이다. @Transactional public void recordArrivalTime(Long memberId, LocalDate attendanceDate, LocalTime startTime) { Member member = memberRepository.findById(memberId); workTimeRecordService.recordArrivalTime(member, attendanceDate, startTime); }WorkTimeRecord를 save하기 위해서는 Member를 알아야만 했고,Member를 찾기 위해서 기존에는 Id값으로 Member를 찾아왔지만, 문득 이는 굉장히 '비효율적'이라는 생각이 들었다.WorkTimeRecord를 저장하기 위해 필요한 것은 Member의 Id 값이지, Member의 모든 정보를 찾아올 필요는 없었기 때문에 불필요한 select문이 발생하는 셈이다.그래서, 이리저리 알아보던 차, Proxy객체라는 존재와 getReferenceById()라는 JpaRepository의 메소드를 알게 되었다.Proxy는 여러 곳에서 쓰이는 용어이지만, JPA를 구현하고 있는 hibernate에서는 Proxy객체는 실제 Entity(여기서는 Member)를 상속 받은 껍데기 객체이다.Entity를 상속받았기 때문에 Entity의 모든 역할을 대신 수행할 수 있으나, 내부의 값은 모두 비어있는 상태가 된다.만일, 상태가 필요한 순간이 되면 그때 JPA의 영속성 컨텍스트를 통하여 실제 Entity를 조회하여 값을 찾아오게 된다.위와 같은 기술을 Lazy라고 한다.즉, 나의 처음의 고민은 이를 통해 해결할 수 있게 되었다. @Transactional public void recordArrivalTime(Long memberId, LocalDate attendanceDate, LocalTime startTime) { Member member = memberRepository.getReferneceById(memberId); workTimeRecordService.recordArrivalTime(member, attendanceDate, startTime); }이렇게, Proxy객체로 Member를 찾게 되면, 실제로 select문은 발생하지 않고 정상적으로 WorkTimeRecord에 Member값을 할당할 수 있게 된다. 

백엔드JPA인프런워밍업MVC

유원준

[인프런 워밍업 클럽 0기 백엔드] 2주차 발자국 (내용 정리 + 과제 + 미니 프로젝트)

인프런 워밍업 스터디의 2주차가 마무리되어 가고 있는 한 주입니다.2주차 동안 학습했던 내용들과 과제 수행 관련된 내용까지 한 번에 정리하고자 합니다.추가로 2주차 동안 학습한 내용, 과제 수행 부분은 개인 블로그에 항상 정리하고 있습니다.참고하실 분들은 참고해 주시면 좋을 것 같습니다 :)제 블로그 주소 링크 남겨드리겠습니다.(1~10일차 학습 및 과제 수행 내용)https://twojun-space.tistory.com/category/%ED%9A%8C%EA%B3%A0/InFlearn%20Warming-up%200%EA%B8%B0%20BE추가적으로 과제가 마무리 된 후 미니 프로젝트가 시작됩니다.미니 프로젝트는 제 GitHub에 소스 코드, 기능 설명을 남겨두고자 합니다.하단은 제 GitHub 주소입니다.https://github.com/twojun/inflearn_warmingup_be_project   1. [6일 차] - Spring Bean & Spring Container, Spring Container를 다루는 방법, Spring Bean 주입 받기, 스프링 빈의 우선 순위 설정1-1. Spring Bean?(1) 스프링 빈에 대한 정의, 스프링 빈이 사용되는 이유스프링 컨테이너와 연관지어 설명, 스프링 빈의 라이프 사이클 의존성 확인 및 주입을 담당하는 스프링 컨테이너 내부에 스프링 빈이 존재한다. 1-2. Spring Container(1) 스프링 컨테이너가 사용되는 이유(2) 스프링 컨테이너의 역할(3) 스프링 컨테이너를 사용할 때와 사용하지 않을 때의 Controller-Service-Repository, 사용 전 후로 달라지는 점1-3. 의존성 주입(Dependency Injection), 제어의 역전(Inversion of Control, IoC)스프링 프레임워크의 핵심 기능인 의존성 주입, 제어의 역전이 무엇인지 코드를 통해 직접 알아보며 스프링 프레임워크가 DI, IoC를 제공해 줌으로써 가져다 주는 이점에 대해 정리 생성자 주입, Setter 주입 등 스프링 컨테이너가 제공해주는 다양한 기능 정리  1-4. @Controller, @Service, @Repository를 계층형 아키텍처에 직접 적용(1) 관련 객체들이 스프링 빈으로 등록되어 컨테이너 내부에서 서로 간의 의존성, 라이프 사이클이 관리됨을 이해한다.  1-5. 스프링 컨테이너를 다루는 방법, @Configuration, @Bean, @Component, 스프링 빈을 주입받는 방법@Configuration, @Bean이 직접적으로 사용되는 시기에 대해 학습@Component의 효과스프링 빈 주입 시 Constructor injection 사용(불변 타입의 객체와 함께 사용)Constructor injection 사용 시 테스트 용이  1-6. @Qualifier, @Primary(1) 동일한 타입의 빈에 대해서 어떠한 빈을 주입 대상으로 설정할지 우선권을 부여하는 어노테이션직접 타겟을 텍스트로 지정하는 @Qualifier가 @Primary보다 우선권이 높다.  1-7. 6일 차 개인 회고(1) 스프링 빈, 스프링 컨테이너, DI(Dependency Injection), IoC(Inversion of Control) 등 스프링을 이루고 있는 주요 핵심 기능에 대해 학습할 수 있었다. (2) 스프링을 이루고 있는 핵심 기술인만큼 확실하게 이에 대해 인지하고 있어야 할 필요성을 느끼게 되었다.   2. [6일 차] - 과제 수행 : 계층 구조인 Controller - Service - Repository로 분리하기(1) 과제 수행 코드 : https://github.com/twojun/InFlearn_WarmingUp_Club_BE_0 (2) 6일차 과제수행 리뷰 : (개인 블로그)https://twojun-space.tistory.com/188 2-1. 문제 1번 : Fruit 서비스를 각각의 계층구조로 분리하기(1) 문제 접근 및 해결 방법기존에 스파게티처럼 얽혀 있던 코드를 각각의 역할에 맞게 수행할 수 있도록 코드를 분리했다.사용자의 요청을 받아 응답을 반환하는 Controller, 비즈니스 로직을 처리하는 Service, 데이터베이스와의 통신을 담당하는 Repository로 분리했다.기존 코드도 그렇고, 분리 과정에서 각 계층마다 역할이 뚜렷했기 때문에 분리하는 데 큰 어려움은 없었던 것 같다.  2-2. 정상 동작 확인(1) 기존 코드를 계층적으로만 분리해서 조금 더 유지보수성을 높였기 때문에 이전과 동일하게 API 반환, 데이터베이스에 데이터가 적재되는 등 정상적으로 동작하는 부분을 확인했다.  2-3. 문제 2번 : FruitRepository 코드를 FruitMysqlRepository, FruitMemoryRepository로 구분하고 리포지토리를 변경해가며 코드 실행하기(1) 문제 접근 및 해결 방법우선 동일한 타입을 갖는 객체에 대해 FruitMysqlRepository, FruitMemoryRepository 두 개 중, FruitMysqlRepository 클래스에 @Primary 어노테이션을 적용하여 코드를 실행해보니 정상적으로 코드가 동작하는 것을 확인할 수 있었다. 기능은 동일하고 어떤 빈을 주입받을지만 선택하면 되는 부분이었기에 큰 어려움 없이 해결할 수 있는 과제였다.  2-4. 6일차 과제 개인 회고(1) 기존의 코드를 Controller - Service - Repository로 분리하며 각 계층이 가져야 하는 역할, 책임에 대해 생각해 볼 수 있었다. (2) 조금 더 좋은 코드를 위해 지켜야 되는 부분은 무엇인지, 공부해야 되는 부분은 무엇인지 찾아볼 수 있었다.     3. [7일 차] - 지금까지 코드를 작성하며 Repository에 대해 개선할 점, JPA 도입, 추상화 레벨을 높인 Spring Data JPA 3-1. Repository 영역에서 지금까지 작성된 코드의 아쉬운 점(1) 문자열 기반으로 직접 쿼리를 작성하고 있다.(2) 이 부분에 대한 심각한 문제 : 컴파일 타임이 아닌 런타임 시점에 오류가 발생한 것을 인지하게 된다.(3) 특정 DB에 대한 종속적 쿼리 발생(4) 기본적인 CRUD에 대한 반복 작업 등등...  3-2. 객체와 DB 테이블의 패러다임 불일치 문제(1) 객체와 데이터베이스 테이블은 서로 간의 패러다임이 완전히 불일치한다.(대표적으로 연관 관계 문제, 상속구조를 표현할 수 없는 문제, 서로 참조할 수 있는 매커니즘이 아예 다른 문제 등) (2) 대부분의 애플리케이션이 객체지향적 설계를 지향한다. 객체와 관계형 데이터베이스를 같이 사용하기 위해서는 이 부분을 어떻게 해결할까? -> JPA 도입   3-2. JPA(Java Persistence API)(1) JPA의 정의, ORM 기술이 어떠한 기술인지 학습(2) JPA의 구현체인 하이버네이트의 등장  3-4. 객체와 테이블을 매핑하기 위한 여러 가지 어노테이션, 기타 옵션(1) @Id, @GeneratedValue(2) @Column 등 ...(3) JPA에 대한 여러 가지 설정 및 옵션 설정 : application.yml(4) spring.jpa.hibernate.ddl-auto 옵션 : create, create-drop, validate, update, none 존재(5) spring.jpa.properties.hibernate.show_sql(6) spring.jpa.properties.hibernate.format_sql(3) spring.jpa.properties.hibernate.dialect   3-5. Spring Data JPA를 통한 CRUD 작업 공통화, Repository 작성(1) Spring Data JPA의 대한 개념, 정의 학습(2) Spring Data JPA는 높은 추상화 레벨을 가진 라이브러리로 스프링에서 데이터베이스에 대한 접근을 단순화하고 효율적으로 처리하며 반복적인 CRUD 작업 또한 추상화하여 개발자가 직접 코드를 작성하지 않고 간단한 CRUD 기능을 수행할 수 있도록 설계되어 있다.(3) 회원 도메인에 직접 Spring Data JPA 적용해 보기 (4) 인터페이스를 사용하는 데 구현체를 생성하지 않았음에도 불구하고 해당 인터페이스를 사용할 수 있는 이유 학습(5) 스프링 데이터 JPA 쿼리 메서드 작성 방법, 여러 가지 옵션 확인   3-6. 7일 차 학습 내용 개인 회고(1) Spring Data JPA가 갖는 편리함 덕분에 개발 생산성이 높아졌지만 내부적으로 동작하는 매커니즘을 알기 위해선 JPA에 대한 기초적인 이해가 선행되어야 한다고 생각했다. (2) JPA를 이루는 기초적인 개념을 다시 한 번 정리할 수 있었고 헷갈렸던 부분에 대해 제대로 학습해 볼 수 있었다.    4. [7일 차] : 과제 수행 - Spring Data JPA 적용(1) 과제 수행 GitHub 주소 : https://github.com/twojun/InFlearn_WarmingUp_Club_BE_0  (2) 7일 차 과제 정리 블로그 주소 : https://twojun-space.tistory.com/190  4-1. 과제 수행 : 문제 1번(1) 기존 Fruit 서비스가 Spring Data JPA Repository를 사용할 수 있도록 FruitRepository 인터페이스를 생성한다. (2) 이후 서비스 계층에서 새롭게 생성된 FruitRepository (Interface)를 의존할 수 있도록 설정한다.(3) 접근법은 매우 간단하다. 인터페이스를 생성하고 서비스 계층에서 해당 인터페이스를 의존할 수 있도록 의존 관계를 변경해 주기만 하면 된다.   4-2. 과제 수행 : 문제 2번(1) 문제 요구사항 : 특정 과일을 기준으로 판매된(거쳐간) 과일의 개수를 출력하는 API 설계 (2) 접근 방법 및 문제 해결 과정서비스 계층에 로직이 모두 몰리는 것을 막기 위해 과일 상태 변경에 관한 구현 로직을 도메인 계층에서 구현한다.판매 전 과일 판매 상태는 false, 판매 이후 true로 변경한다.// 판매 상태 변경 public void changeSalesStatus(boolean salesStatus) { this.salesStatus = salesStatus; }또한 Setter를 사용하는 것은 좋지 않다. 의미 있는 비즈니스 메서드(changeSalesStatus) 등을 생성하는 것이 좋다.@Repository public interface FruitRepository extends JpaRepository<Fruit, Long> { // select * from fruit where name = ? and salesStatus = true; long countByNameAndSalesStatusIsTrue(String name); }Repository 영역에 쿼리 메서드를 통해 판매된 과일의 개수를 계산하는 코드를 작성한다.(3) 기능 테스트본인은 매번 데이터 로우를 넣는 부분이 번거로워서 별도의 InitDbService를 만들어서 서버가 재시동될 때마다 해당 데이터들을 추가하도록 설정했다.@Component @Transactional @RequiredArgsConstructor static class InitDbService { private final EntityManager em; public void initFruitDb() { Fruit fruit1 = createFruit("사과", 4000L, LocalDate.of(2024, 02, 01)); Fruit fruit2 = createFruit("바나나", 2000L, LocalDate.of(2024, 02, 01)); Fruit fruit3 = createFruit("사과", 6500L, LocalDate.of(2024, 02, 01)); Fruit fruit4 = createFruit("사과", 7000L, LocalDate.of(2024, 02, 01)); Fruit fruit5 = createFruit("사과", 3000L, LocalDate.of(2024, 02, 01)); Fruit fruit6 = createFruit("포도", 12000L, LocalDate.of(2024, 02, 01)); Fruit fruit7 = createFruit("사과", 2500, LocalDate.of(2024, 02, 01)); Fruit fruit8 = createFruit("사과", 5000L, LocalDate.of(2024, 02, 01)); em.persist(fruit1); em.persist(fruit2); em.persist(fruit3); em.persist(fruit4); em.persist(fruit5); em.persist(fruit6); em.persist(fruit7); em.persist(fruit8); } private static Fruit createFruit(String name, long price, LocalDate warehousingDate) { return new Fruit(name, price, warehousingDate); } }테스트 진행 시 판매된 과일의 개수가 정상적으로 출력됨을 확인했다.4-3. 과제 수행 : 문제 3번(1) 문제 요구사항아직 판매되지 않은 특정 금액 이상, 금액 이하의 과일 리스트를 출력하는 API 설계 (2) 문제 접근 및 해결 방법 / 테스트Controller에 판매되지 않은 특정 금액, 이상, 이하 과일들, 결과 반환 개수까지 반환하는 메서드를 만든다.응답 DTO에 판매되지 않은 과일 개수를 나타내기 위해 별도의 resultSize 필드를 추가한다.이후에 과일의 판매 상태 컬럼을 활용해 판매되지 않은 과일의 리스트를 반환하는 로직을 각각 짜고 결과를 테스트 해 봤을 때 정상적으로 API 반환값이 확인된다.4-4. 과제 개인 회고(1) 높은 추상화 덕분에 우리의 개발 생산성이 올라갔지만, 그 뒤에는 우리가 편리한 기술을 사용하기 위해서 뒷받침되는 기술들이 많다는 것을 다시 한 번 느껴볼 수 있었다.(2) 지금 작성한 코드들도 문제없이 작동하지만 코드를 더 좋은 방향으로 짤 수 있지 않을까라는 생각이 계속 들었다.5. [8일 차] - 트랜잭션의 정의, 커밋과 롤백(Commit & Rollback), JPA의 Persistence Context, Persistence Context의 여러 가지 기능 살펴보기(1) 관련 내용 정리 (개인 블로그) : https://twojun-space.tistory.com/191  5-1. 트랜잭션의 정의와 트랜잭션의 커밋과 롤백(1) 예시와 함께 트랜잭션의 정의, 성공적인 트랜잭션 후 데이터베이스와의 동기화를 진행하는 커밋 옵션, 트랜잭션 실패 시 작업 이전으로 되돌아가는 롤백 옵션에 대해 확인해 보았다.5-2. 실제 코드에 선언적 트랜잭션(Declarative transaction) 적용하기(1) 코드에 @Transaction 어노테이션(선언적 트랜잭션 방법)을 적용하여 서비스 계층에서 메서드가 실행될 때 트랜잭션이 적용될 수 있도록 하고 작업 성공 시 커밋, 실패 시(예외 발생 시) 롤백하게 된다.5-3. JPA의 Persistence Context, Persistence Context의 여러 가지 기능(1) Persistence context(영속성 컨텍스트)의 정의에 대해 학습했다.(2) 첫 번째 기능 : 변경 감지트랜잭션 커밋 시점에 엔티티에 대한 변경사항을 감지하여 이에 대한 쿼리가 실제 데이터베이스로 전송되는 것을 말함(3) 두 번째 기능 : 쓰기 지연 저장소엔티티를 관리하며 발생한 관련 쿼리들을 쓰기 지연 저장소에 두고 트랜잭션 커밋 시점에 모든 쿼리를 데이터베이스로 전송한다.(4) 세 번째 기능 : 1차 캐시 기능 지원엔티티의 Identifier를 기준으로 영속성 컨텍스트에 영속화된 엔티티는 1차 캐시에 스냅샷(영속화 당시 엔티티의 정보)이 저장되어 있고 추후 해당 엔티티를 조회하는 경우라면 데이터베이스까지 조회 쿼리를 날리지 않고 1차 캐시에서 조회함에 따라 성능상 조금의 이점이 생긴다.5-4. 8일차 학습 회고(1) JPA의 기능들을 무심하게 사용해 오다가 JPA의 내부 매커니즘을 이해할 수 있는 영속성 컨텍스트에 대해 다시 한 번 리마인드 할 수 있었다. 관련 기반 기술의 이해가 선행되어야 해당 기술을 문제없이 잘 사용할 수 있다고 생각하기 때문에 이 부분에 대해 다시 한 번 정리해볼 생각이다.6. [9일 차]- 추가 기능에 대한 API 개발학습 내용 관련 블로그 정리 : https://twojun-space.tistory.com/1926-1. 도서 등록, 대출, 반납 요구사항 추가에 대한 API 개발, 개인 회고(1) 이전과 동일하게 요구사항을 확인하고 요청/응답 DTO의 스펙, Controller, Service, Repository를 개발했다.(2) 이를 통해 회원 관리, 도서 등록과 대출 반납에 대한 기능 구현이 모두 완료되었지만 한 가지 의문점이 남는다. 서비스 계층을 중심으로 모든 로직이 돌아가고 절차지향적인 코드라는 느낌이 많이 든다. 각 생성된 엔티티 간의 협력을 통해 개발할 수 없을까? 라는 의문점이 들고 JPA에서 제공하는 연관관계 기능을 사용해서 엔티티의 역할과 협력을 추가적으로 사용해서 조금 더 객체지향적으로 설계해 보는 것이 좋다고 생각했다.7. [10일 차] - JPA 연관관계와 지연 로딩(Lazy Loading), 객체지향적 설계, 도서 대출/반납 기능 Refactoring(1) 관련 학습 내용 블로그 정리 : https://twojun-space.tistory.com/1937-1. 연관관계란 무엇인가?(1) 연관관계의 정의에 대해 알아봤다. 데이터베이스 테이블과 객체 간 서로를 참조하는 방식에 대한 패러다임이 불일치하기 때문에 JPA의 연관관계를 통해 객체와 테이블을 정확하게 매핑하는 것이 중요하다.7-2. 연관관계의 주인(1) 일대일의 경우 핵심 비즈니스 로직이 존재하는 엔티티를 연관관계의 주인으로 둔다.(2) 다대일의 경우 외래 키가 존재하는 엔티티를 연관관계의 주인으로 설정한다.(3) 연관 관계의 주인으로 설정된 엔티티는 객체가 서로 연결될 수 있는 기준이 된다.(4) 일대일 관계에서는 @OneToOne 어노테이션을 사용한다.(5) 다대일 관계에서는 @ManyToOne, @OneToMany를 사용한다.(6) 양방향 연관관계를 가진다면, 한 쪽 엔티티에 대한 변경이 다른 쪽 엔티티에도 반영될 수 있도록 도와주는 메서드인 연관관계 편의 메서드를 만든다.(7) 양방향 연관관계를 사용하게 된다면, 신중하게 선택해야 한다.7-3. 실무에서 다대다 연관관계는 사용하지 않는다.따라서 중간에 별도의 테이블을 생성하여 처리하는 방법으로 매핑한다.7-4. @ManyToOne은 단방향으로만 사용한다,1쪽에서 @OneToMany로 참조하는 부분을 없애고 @ManyToOne 단방향으로만 남겨놓는다.  7-5. 연관관계의 주인이 사용할 수 있는 어노테이션@JoinColumn을 통해 연관관계의 주인이라는 부분을 명시한다.  7-6. 영속성 전이(Cascade)옵션과 orphanRemoval(1) cascade 옵션의 경우 연관관계와 관련은 없다.(2) 부모 엔티티가 자식 엔티티를 관리해야 할 때 사용한다.(3) orphanRemoval은 고아 객체를 제거할 때 사용하는 옵션으로 부모 엔티티와 자식 엔티티 간 연관관계가 제거된 경우 해당하는 자식 엔티티를 삭제하게 된다.  7-7. 도서 대출/반납 기능 리팩토링(1) 지금까지 학습한 내용을 바탕으로 각 엔티티가 협력할 수 있도록 모든 코드를 수정한다.(2) 엔티티에 도서 대출, 도서 반납 등의 핵심 로직을 설계한다.(3) 이를 통해 도메인 간 협업이 가능하도록 설계하여 서비스 계층의 로직이 단순해지고 특정 기능이 필요한 경우 엔티티의 기능을 직접 호출하도록 설계한 것을 확인할 수 있었다.7-8. 9일차에서 소개되지 않은 영속성 컨텍스트의 기능 : 지연 로딩(Lazy Loading)(1) 지연 로딩은 두 엔티티를 대상으로 특정 엔티티를 조회함에 있어서 연관된 엔티티는 바로 가져오지 않고, 해당 연관된 엔티티를 필요로 할 때(사용될 때) 로딩하는 기법을 의미한다.(2) 지연 로딩의 핵심 매커니즘은 프록시 기술과 연관되어 있다.7-9. 연관관계를 사용해서 도메인 중심으로 설계 시 얻는 장점?(1) 각자의 역할에 집중하게 된다 :계층별로 응집성이 강해진다. 도메인끼리의 협업 관계를 통해 서비스 계층에서는 외부 트랜잭션 관리, 의존성 관리 등의 역할만 맡게됨으로써 각자의 역할에 더 집중하는 코드가 완성된다.(2) 협업 시 코드 리딩이 쉬워진다.서비스 계층에 너무 많은 로직이 몰려있다 보면 코드를 리딩하는 입장에서 번거로울 수 있다. 하지만 도메인 중심으로 코드를 설계하면 계층이 어느 정도 분리됨을 가져가면서 도메인 계층이 각각 어떤 역할을 수행하는지 파악하기 수월해진다.(3) 테스트 코드 작성 시 용이하다.(4) 결론원론적인 이야기이지만 항상 연관관계를 사용하는 것이 정답은 아니기에 요구사항, 도메인 아키텍처 등 여러 가지 사항을 충분히 고민해서 연관관계 사용을 선택해야 한다.7-10. 학습 내용 개인 회고(1) 개인적으로는 이번 섹션이 가장 중요한 내용인 것 같다.(2) 영속성 컨텍스트(JPA 내부 동작 방식 이해)를 이해하는 것과 객체와 테이블을 매핑시킬 때 가장 중요한 연관관계에 대한 내용이라 더욱 그렇게 느꼈던 것 같다.(3) 연관관계를 조금 더 정확히 이해하고 항상 주의깊게 코드를 설계하도록 노력해야 할 것 같다.8. 2주 차 회고(1) 벌써 스터디에 참여한지 2주차가 마무리되는 시점이다.(2) 스터디 완주까지 최선을 다하고 싶고, 기회가 된다면 우수 러너도 도전해 보고 싶다. 많은 것을 경험하고 얻어갈 수 있는 시간이 되었으면 좋겠다.(3) 0기 스터디원분들 모두 화이팅입니다 :)

백엔드인프런워밍업스프링백엔드발자국

유원준

[인프런 워밍업 클럽 0기 백엔드] 1주차 발자국 (내용 정리 + 미션 수행 정리)

인프런 워밍업 스터디의 1주차가 마무리되어 가고 있는 한 주입니다.1주차 동안 학습했던 내용들과 미션 수행 관련된 내용까지 한 번에 정리하고자 합니다.추가로 1주차 동안 학습한 내용, 과제 수행은 개인 블로그에 별도로 상세하게 정리해 둔 부분이 있습니다.참고하실 분들은 참고해 주시면 좋을 것 같습니다😁제 블로그 주소 링크 남겨드리겠습니다.😁 (1~7일 차 학습 내용, 과제 수행)https://twojun-space.tistory.com/category/%ED%9A%8C%EA%B3%A0/InFlearn%20Warming-up%200%EA%B8%B0%20BE  1. [0일 차] - 인프런 워밍업 스터디 0기 Orientation1-1. 스터디 진행 방식, 일정, 완주 러너와 우수 러너 기준 정리 등(1) 스터디 진행에 있어 필요한 부분들을 코치님께서 모두 정리해 주셨습니다.(2) 또한 디스코드에 발자국 작성법, 완주, 우수러너의 기준 선정 등 다양한 내용들이 디스코드에 나와 있어서 과제 수행에 별 어려움은 없었습니다.  1-2. 코치님의 추가 강의 : 자바의 역사(1) 코치님께서 Orientation 이후 자바의 역사에 대해 간단하게 정리해 주셨는데, 이 부분에 대해 정리해 보겠습니다.  1-3. Java 7(1) 프로그래밍 언어 자바의 암흑기가 찾아온 버전으로, 다른 언어들보다 오래 되었고, 기능이 한참 부족하다는 의견들이 다수 존재한 상황 (2) 당시 사람들의 생각 : 데이터 타입, 조건문, 반복문, OOP, Generic 정도만 다루면 잘 다루는 거 아니야? 라는 생각들이 당시 대다수 사람들의 생각  1-4. Java 8 (2014년)(1) 자바 8을 기점으로 언어의 대격변이 발생했던 시기 (2) Functional Programming(FP), Lamba Expression, Stream API, Optional operation, 날짜, 시간을 다루는 방법 등 (LocalDateTime) 등 현재 시점에서도 가장 많이 사용되는 자바의 핵심 문법들이 등장하기 시작함  1-5. Java 9 (2017년)(1) 자바 9부터 자바의 버전업 주기가 대부분 6개월로 변경  1-6. Java 11(1) 2024년 현재 기준으로 서비스 기반 IT 기업들의 주력 프로그래밍 언어로 선정된 자바  1-7. Java 21 (2023년)(1) 자바의 현 시점 가장 최근 버전  2. 0주 차 개인 회고(1) 이번 스터디를 통해 지금까지 학습해 왔던 스프링, JPA와 관련된 내용을 적용해 보고 싶었다.(2) 자바 8에 등장하게 된 핵심 문법들은 지금도 많이 사용되고 있고 이 부분에 대해 따로 한 번 정리해야겠다는 생각을 하게 되었다.(3) 우수 러너로 선정되어 개인적인 성장에 한 걸음 더 다가가고 싶다는 생각을 할 수 있었다.(4) 파이팅😊    2. [1일 차] - 스프링 프로젝트 메타 데이터, 서버와 네트워크, HTTP, URL 등 기본 지식 등 학습 내용 정리2-1. 프로젝트 메타데이터(1) 스프링 부트 프로젝트 생성 시 메타데이터인 Group, Artifact, Description, Dependencies 추가 등 프로젝트를 구성함에 있어 설정할 수 있는 메타데이터들, 의존성을 추가하는 방법을 알아봤다.  2-2. 서버와 네트워크(1) 서버와 네트워크의 정의와 특징 HTTP 통신의 핵심이 되는 네트워크 지식, IP, DNS, 등에 대해 빠르게 요약 및 정리할 수 있었다.  2-3. 웹 기반 서비스에서의 통신 규약, HTTP(HyperText Transfer Protocol)(1) HTTP의 정의, 요청과 응답에 각각 사용되는 HTTP Request Message, HTTP Response Body, REST API를 정의할 때 자원과 행위를 명시하는 데, 이때 행위를 명시할 때 사용되는 HTTP Method(GET, POST...등)에 대해 학습했다.  2-4. API(Application Programming Interface)(1) API는 프론트엔드와 백엔드 간의 통신을 위한 규약, 규칙 수단을 의미, 추가적으로 REST API, RESTful API에 대해 개인적으로 따로 정리해 보았다.  2-5.API를 개발하기 위한 다양한 Annotation(1) API 명세의 중요성, @RestControler, @GetMapping, @PostMapping, @RequestParam 등 다양한 어노테이션에 대해 정리할 수 있었다.  2-6. 1주차 학습에 대한 회고(1) 백엔드를 공부하면서 지금까지 다양한 용어를 공부했었지만 무의식적으로 용어를 계속 사용하다보니 정의와 아예 어긋나게 알고 있었던 개념들이 조금 있었다. (2) 이번 학습을 통해 잘못 이해하고 있던 부분을 바로 잡긴 했지만 조금 더 빨리 알았으면 좋았을 것 같다는 생각을 해보며 과거에 공부했던 부분을 다시 정리해 보고 잘못 알고 있는 부분은 바로 잡을 필요가 있다고 생각했다.   3. [1일 차] - 과제 수행 : 자바의 어노테이션(1) 인프런 블로그에 별도로 정리한 내용 : https://www.inflearn.com/blogs/6610 3-1. 자바의 어노테이션이란?, 어노테이션을 활용하면서 생기는 장점(1) 코드 가독성 향상, 반복되는 어노테이션의 공통화(2) 커스텀 어노테이션 생성 가능(3) 컴파일 시점에서의 오류 체크 가능 등어노테이션을 활용하면 다양한 장점이 존재한다. 3-2. 어노테이션의 종류(1) 표준 어노테이션(빌트 인 어노테이션), 메타 어노테이션(2) 표준 어노테이션 : @Override, @FunctionalInterface, @Deprecated 등...(3) 메타 어노테이션 : @Target, @Retention, @Inherited, @Repeatable  3-3. 커스텀 어노테이션 정의 방법public @interface SimpleAnnotation { }(1) 별도의 커스텀 어노테이션 생성 가능 @Retention(RetentionPolicy.RUNTIME) @Inherited @Target(ElementType.TYPE) @RestController @RequestMapping("/new") public @interface CustomMyAnnotation { String name() default "MemberController"; String value(); }@CustomMyAnnotation(name = "MemberController", value = "MemberController") @RequiredArgsConstructor public class MemberController { private final MemberService memberService; @GetMapping("/list") public List<MemberListResponseDto> getAllMemberList() { List<Member> allMemberList = memberService.findAllMembersList(); return allMemberList.stream() .map(member -> new MemberListResponseDto(member)) .collect(Collectors.toList()); } }  3-4. 과제 접근 방법, 회고(1) 접근 방법코드 공통화 등 여러 이점을 챙기기 위해 커스텀 어노테이션을 사용해야 하는데, 이 부분에 대해서는 메타 어노테이션에 대한 이해가 필요하다고 생각하여 우선 커스텀 어노테이션을 정의하기 위한 메타 어노테이션을 별도로 공부했다. 이후 위의 코드에서 공통으로 묶을 수 있는 어노테이션을 확인하고 이 부분에 대해 별도로 메타 어노테이션까지 적용해 봄으로써 커스텀 어노테이션을 생성해 볼 수 있었다. (2) 과제 회고개발을 해 보면서 별도로 커스텀 어노테이션을 사용해 본 적이 없어서 이 부분이 조금 낯설게 느껴졌지만 계속 반복해서 학습하다 보니 커스텀 어노테이션의 필요성, 언제 사용되는지 등에 대해 조금 인사이트가 생긴 것 같다.     4. [2일 차] - JSON, HTTP API 코드 작성, 배운 내용을 기반으로 도메인(회원) Entity 개발, 데이터베이스에 대한 기본 개념 4-1. POST 방식에서 데이터를 주고받는 방법, JSON의 구조(1) POST 방식에서 요청 데이터를 서로 주고받는 데 사용되는 데이터 형식 : JSON(2) 자바스크립트 객체 문법으로 구조화된 데이터들을 담을 수 있는 구조 : JSON(3) Key=value의 타입 구성  4-2. HTTP API 코드 작성, @RequestBody(1) 실제 코드를 작성해 보고 Postman을 이용해 API 응답 결과가 반환되는 것을 확인(2) @RequestBody : POST, PUT 방식에서 요청 바디에 적재한 데이터를 자바의 컨트롤러 메서드의 파라미터 객체와 매핑하는 어노테이션  4-3. 회원 도메인 개발(1) @RestController 어노테이션의 경우 응답 결과의 형식이 JSON으로 반환되도록 설계되어 있다.  4-4. Section 1 정리(1) 스프링 프로젝트의 구조, 실행 방법(2) 네트워크, IP 주소, 도메인 네임, 포트 번호, HTTP Request/Response 구조, 클라이언트-서버 구조, 기본적인 API 개념들 학습 (3) Spring Boot 기반으로 기본적인 GET, POST API 설계 방법4-5. 지금까지 설계한 API의 문제점(1) 데이터베이스의 부재 - 영속성을 관리하기 위한 수단이 존재하지 않는다.4-6. 데이터베이스의 개념(1) RDBMS(Relational Database Management System)의 개념과 정의, SQL(Structured Query Language)4-7. 2일 차 학습 내용 개인 회고(1) 위의 회원 API를 개발할 때 데이터베이스를 전혀 사용하지 않고 메모리에서 동작하도록 자바 컬렉션을 사용해서 데이터를 저장하고 조회했는데 평소 데이터베이스에서 CRUD를 하다 보니 자바 컬렉션에서 처리하는 코드들이 조금 낯설게 느껴진 것 같다.5. [2일 차] - 과제 수행 : GET, POST API 설계소스 코드 : https://github.com/twojun/InFlearn_WarmingUp_Club_BE_0  5-1. 문제 1번(1) 두 수를 입력하면 다음과 같은 결과가 반환되는 GET API를 설계한다.(2) URL Path : /api/v1/calc(3) Query parameter : num1, num25-2. 접근 및 해결 방법(1) 쿼리 파라미터가 사용되므로 @RequestParam을 통해 매핑시킬 수 있도록 한다.(2) DTO를 제외한 순수 엔티티 계층에는 @Setter를 열지 않는다.(3) 응답을 위한 별도의 DTO를 만들어서 클라이언트 측으로 반환한다.5-3. 문제 2번(1) 날짜를 입력하면 무슨 요일인지 알려주는 GET 조회 API를 설계한다.(2) URL Path, Query parameter의 경우 임의로 설계해도 상관없다.(3) 본인은 문제에서 기재된 URL과 쿼리 파라미터를 동일하게 설계했다.5-4. 접근 및 해결 방법(1) 날짜를 원하는 형식으로 포맷팅하기 위해, getDayOfWeek(), getDisplayName(TextStyle.SHORT, Locale.ENGLISH등의 날짜와 관련된 메서드를 별도로 찾아보고 문제에 적용시켰다.5-5. 문제 3번(1) 요청 메시지 바디에 리스트 형태로 여러 수를 입력하고 해당 수들의 모든 합을 계산하는  POST 조회 API를 설계한다.(2) API에서 받게 되는 요청 바디의 예시는 아래와 같다.5-6. 접근 및 해결 방법(1) 클라이언트에서 리스트 형태로 바디를 전송하기 때문에 이를 받아서 객체로 파싱하기 위해 위와 같이 List 컬렉션을 내부에 선언해 주었다.(2) 해당 과정에서 자바의 기본 생성자가 필요하다.(2) 반환 결과에서 기본 생성자가 추가적으로 필요한데 이유는 다음과 같다.위의 예외는 스프링의 Jackson 라이브러리의InvalidDefinitionException 예외이며, jackson 라이브러리가 JSON 내부에 객체 형태로 넘어온 값을 실제 객체로 변환하기 위해 역직렬화 과정을 거치는데, 이 과정에서 기본 생성자가 없어서 역직렬화가 실패했기 때문에 위와 같은 예외가 발생하는 것. 따라서 관련 클래스에 기본 생성자를 추가해 줘야 한다.5-7. 과제 수행 회고 (1) 과제를 수행하면서 날짜 정보를 나타낼 수 있는 LocalDate, 날짜와 시간 정보를 모두 나타내는 LocalDateTime에 대해 한 번씩 정리해 볼 수 있었다. 날짜 + 시간 정보가 함께 필요한 환경에서 LocalDateTime은 거의 필수로 사용되는 것 같다. (2) 또한 API 반환 관련 부분을 많이 찾아보면서 Jackson 라이브러리의 역직렬화에 대해 조금 더 자세히 찾아볼 수 있었는데,  JSON ↔ 객체 사이의 데이터를 변환해야 하는 일이 있을 때 주체 클래스에서 기본 생성자가 변환 과정에서 반드시 필요하다는 것을 인지했고 이런 부분을 설계할 때는 기본 생성자를 조금 더 신경쓰도록 주의해야 할 것 같다.6. [3일 차] - 데이터베이스 기본적인 DDL, DML, MySQL 데이터 타입, 데이터베이스 도입에 따른 도메인 코드 수정6-1. 데이터베이스 DDL(Database Definition Language) (1) 기본적인 데이터베이스 및 테이블 생성, 및 목록 확인  6-2. MySQL의 대표적 데이터 타입(1) 숫자형 타입(정수형, 실수형 타입)(2) 문자열 타입(3) 날짜, 시간 타입  6-3. 데이터베이스 CRUD(DML : Database Manipulation Language)(1) INSERT INTO~ VALUES(2) SELECT ~ FROM ~ WHERE(3) BETWEEN ~ AND ~(4) IN, NOT IN,(5) UPDATE ~ SET ~ WHERE (조건절 명시 유의)(6) DELETE FROM ~ WHERE ~ (조건절 명시 유의)  6-4. 회원 도메인 Controller 코드 수정(1) 코드 : https://github.com/twojun/InFlearn_WarmingUp_Club_BE_0 (2) jdbcTemplate.update() : 쿼리를 통해 데이터베이스에 대한 갱신(update, delete insert) 발생 시 사용 가능한 메서드로 파라미터로 넘어온 값들을 실제 SQL의 ?(와일드 카드) 부분과 매핑시키는 역할을 수행한다. (3) jdbcTemplate.query(sql, new RowMapper<UserListDto>()RowMapper의 경우 쿼리의 결과를 받아서 원하는 결과 객체를 반환하는 역할을 수행한다.이후 결과 반환을 위해 UserListDto가 필요하므로 생성자에 원하는 결과값을 파라미터로 넣어서 해당 객체를 생성 후 반환한다.(4) 또한 람다식을 이용해 코드를 좀 더 간결하게 작성할 수 있었다.  6-5. 3일 차 학습 내용 개인 회고(1) 스프링에서 Repository를 다룰 때 거의 하이버네이트와 같은 ORM 기반 기술만 쓰다 보니 직접적으로 JdbcTemplate을 통해 데이터베이스에 접근하는 것은 코드가 손에 익숙하지 않았던 것 같다. 이 부분이 조금 아쉬웠다. (2) 람다와 스트림에 대한 추가 정리가 필요하다고 생각했다.    7. [3일 차] - 함수형 프로그래밍, 람다식, Stream API, Method Reference (1) 과제 수행 GitHub : https://github.com/twojun/java8_core_study  7-1. 익명 클래스의 정의, 특징 정리(1) 익명 클래스의 의미, 익명 클래스가 갖는 주요 특징과 함께 코드를 작성하면서 익명 클래스를 실제로 사용하는 이유(함수형 인터페이스와 람다식과 연계)  7-2. 함수형 프로그래밍(Functional Programming) & 람다 표현식(Lambda expression) 정리(1) 함수형 프로그래밍의 뜻, FP가 자바에서 가지게 되는 의미(2) 람다 표현식 정의와 특징, 일급 객체(3) 함수형 인터페이스의 뜻과 사용될 수 있는 데이터 타입(4) 람다 표현식 작성 방법과 람다식을 더 줄일 수 있는 메서드 참조(Method Reference)(5) Method Reference : 실행하려는 람다식의 메서드를 참조해서 파라미터의 정보, 반환 타입을 추론한 뒤 람다식에서 선언이 불필요한 부분을 제거  7-3. 자바에서 기본적으로 제공하는 함수형 인터페이스Predicate<T> , Consumer<T>, Function<T, R>, Supplier<T>  7-4. Stream API(1) 스트림의 정의와 주로 사용되는 곳(2) 스트림 파이프라인 : 중간 연산과 최종 연산 정리(3) 중간 연산과 최종 연산의 주요 메서드들, 주의사항   7-5. 과제 수행 회고(1) 하이버네이트와 같은 ORM 기술을 사용하면서 람다와 스트림이 자주 사용되고, 코드의 가독성을 올려주는 데 효과적이라고 생각했었으며 이번 계기로 이 부분을 다시 한 번 정리해 볼 수 있었다. (2) 람다식, 스트림의 코드 스타일을 외우기 보다는 많이 사용해보면서 체화시키는 부분이 중요하다고 생각했다.    8. [4일 차] - 회원 도메인 수정, 삭제 API (1) 4일차 관련 내용은 도메인에 대한 코드 수정 위주이다.(2) 관련 내용 수행 코드 : https://github.com/twojun/InFlearn_WarmingUp_Club_BE_0  8-1. 회원 수정, 삭제 API를 직접 작성해 보면서 생각해 보아야 할 것?(1) 현재 회원 도메인만 봐도 컨트롤러 레벨에서 문제점이 하나 있다.(2) 하나의 컨트롤러가 너무 많은 책임과 역할을 갖고 있다.조회, 예외 처리(비즈니스 로직), 데이터베이스 통신 등 많은 역할을 수행하고 있다.지금은 요구사항이 예제 수준으로 작지만 요구사항이 10가지만 되어도 컨트롤러에서 모든 코드를 감당하기 어려울 것이다.따라서 이 부분을 해결해야 한다.  8-2. 학습 내용 개인 회고(1) 좋은 컨트롤러는 들어온 요청에 대해 적절한 처리를 다른 계층에서 수행해 주고 응답만을 돌려받아 다시 클라이언트측으로 반환하는 역할을 수행해야 하는데 좋은 컨트롤러란 무엇인가? 라는 부분에 대해 다시 한 번 생각해 봤다. (2) 너무 많은 기능을 담당하는 코드가 컨트롤러에 존재하면 가독성은 물론 유지보수가 매우 어려워진다. 이 부분을 빠르게 개선해야 할 것 같다고 생각했다.   9. [4일 차] - 과제 수행 : API 개발9-1. 문제 1번(1) 과일 가게에 입고된 과일 정보를 저장하는 API를 설계하자.(2) HTTP Method : POST(3) HTTP Path : /api/v1/fruit 9-2. 문제 접근 및 해결 방법(1) 이후 문제의 요구사항에 맞추기 위해 미리 테이블 컬럼에 판매 여부를 저장하는 is_sale 컬럼을 생성한다.(2) 이후 코드는 과일 정보를 저장하기 위한 SQL 문자열을 별도로 작성하고 jdbcTemplate.udpate() 메서드를 사용해서 실제 과일 상품의 정보를 저장하도록 한다. (3) 이후 정상적으로 테이블에 로우가 적재된 것을 확인 (4) int보다 long 타입을 사용해 보도록 하자.본인이 생각하고 있는 이유가 정확하진 않을 수도 있지만, 수의 표현 범위에서의 차이이지 않을까 싶다. int의 경우 약 21억 정도의 크기를 갖는 수를 저장할 수 있는데 해당 자료형이 담는 수도 매우 커보이지만, 이 부분이 실무를 넘어가면 21억보다 큰 수를 받아야 하는 상황이 종종 생길 수도 있기 때문에 long 타입을 사용하는 것으로 알고 있다  9-3. 문제 2번(1) 과일이 판매되면 판매된 과일 정보를 기록하는 API를 설계하자.(2) HTTP Method : PUT(3) HTTP Path : /api/v1/fruit9-4. 문제 접근 방식 및 해결 방법(1) 입고된 과일의 컬럼 정보 is_sale을 1로 변경해야 입고된 과일로 간주한다.(2) 입고되지 않은 과일의 정보를 바꾸는 것 자체가 모순이기에 이 부분에 대해선 IllegalStateException 예외를 던지도록 한다.(3) 코드를 작성해서 정상 결과 반환을 확인했다.9-5. 문제 3번(1) 특정한 과일을 대상으로 판매된 금액, 판매되지 않은 금액의 총합을 계산해보는 API를 설계하자.(2) HTTP Method : GET(3) HTTP Path : /api/v1/fruit/stat(4) HTTP Query parameter : name  9-6. 문제 접근 방법 및 해결 방법(1) 위에서 정의한 판매 상태를 기준으로 각각의 총합 금액을 계산하는 쿼리를 작성한다.(2) 이후 각각 조회된 결과를 받고 별도의 결과 반환 DTO를 만들어서 해당 값들을 DTO로 반환할 수 있도록 코드를 작성했다.(3) 정상적으로 문제에서 요구된 특정 과일에 대한 판매, 미판매 금액이 조회되는 것을 확인할 수 있었다.  9-7. 과제 수행 개인 회고(1)  저번 과제에 이어서 API를 추가적으로 설계해 보면서 REST API 설계에 대해 익숙해 질 수 있었다.(2) 이번 스터디를 계기로 더 많은 API를 반환하는 것을 연습해 보면 더 좋을 것 같다고 생각했다.   10. [5일 차] - 클린 코드, Controller-Service-Repository로 계층 분리하기(계층형 아키텍처) (1) 관련 내용 수행 코드 : https://github.com/twojun/InFlearn_WarmingUp_Club_BE_0 10-1. 클린 코드(1) 클린 코드가 무엇인지 이를 통해 얻을 수 있는 장점(2) 안 좋은 코드가 쌓여가면 프로덕트의 생산성이 낮아지는 점을 인지할 수 있었다.  10-2. 계층형 아키텍처(1) Controller-Service-Repository 형태와 같이 각 계층이 서로에 맞게 분리되어 있는 설계 구조를 의미(2) 각 계층에서 수행되는 역할 정리  10-3. 회원 도메인에 대해서 계층형 구조로 개선 (1) 단순 사용자 정보 수정만이 아닌, 생성, 조회, 삭제 등 모든 비즈니스 포인트를 Controller-Service-Repository 계층 구조로 분리하는 작업 진행  10-4. 5일 차 학습 내용 개인 회고(1) 이번 학습을 통해 클린 코드의 중요성, 모든 역할을 하나의 계층에서 정의하는 것이 아닌 각각의 역할에 따라 계층을 나누고 코드를 분리하는 것이 가독성도 좋고 협업하기 좋은 코드라고 생각할 수 있었다. (2) 앞으로도 코드를 작성하면서 더 좋은 계층구조를 갖는 코드가 무엇인지 생각하고 코드를 작성할 필요성을 느끼며 반성할 수 있는 기회였다.   11. [5일 차] - 클린 코드 적용하기11-1. 주사위 게임 코드 리팩토링(1) 과제 수행 코드 : https://github.com/twojun/java8_core_study(2) 기존 주사위 게임 코드를 클린 코드로 변경해보는 과제였다.  11-2. 문제 접근 및 해결 방법 & 개인 회고(1) 아래의 코드가 만약 주사위의 눈의 수가 30 또는 100까지 늘어난다면? 요구사항 수정에 의한 코드 변경 파급력이 급격하게 커지게 된다. 변경에 의한 파급력이 최대한 작아지게, 또한 읽기 좋게 코드를 수정하려면 어떻게 해야 할까? 라는 생각을 가지고 코드를 작성했던 것 같다. 아래의 코드를 개선된 클린 코드로 리팩토링해 봐야겠다고 생각했다. (2) 본인은 Scanner보다는 BufferedReader를 사용하는 것이 더 익숙해서 코드에 BufferedReader를 적용시켰다. (3) 메서드, 클래스 단위로 나누어서 코드를 작성해도 좋지만 사용자로부터 최대 나올 수 있는 주사위 눈의 수, 게임 반복 횟수를 입력받고 관련 주사위 수가 몇 번 나왔는지 출력하면 되는 문제이기 때문에 별도의 클래스나 메서드로 나누지 않고 간단하게 자료구조(배열)을 확인해 문제를 풀었다. (4) 과제가 끝난 후 다른 분들 코드를 보면 메서드, 클래스 단위로 대부분 나누어 코딩하신 것 같아서 나만 너무 이상하게 코딩했나라는 생각을 했지만, 클린 코드의 의미를 되돌아 보면 읽기 쉬운 코드도 특징 중 하나이기에 최대한 간결하고 눈에 들어올 수 있도록 자료구조를 활용해 표현했지만 뭔가 부족한 느낌이 든다.    12. 1주차 총 회고(1) 스터디가 시작된지 1주일이 경과했다. 디스코드에서 보니 다들 열심히 하시는 분들이 많으신 것 같고 항상 열정적이신 코치님, 동료분들이 있어서 스터디하기 좋은 환경인 것 같다. (2) 열심히 참여해서 개인적인 성장에 한 걸음 더 다가서려고 한다.😄 

백엔드인프런워밍업발자국회고스프링

kamser

서버와 스프링 부트 시작하기 1주차

강의 출처 : https://inf.run/Hywa 최태현 강사님의 자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지] 1주차(1강부터 18강) 워밍업을 정리해보았습니다. 1주차 학습 학습 목표스프링 부트 프로젝트를 설정하고 시작하는 방법서버란 무엇인지, 네트워크와 HTTP, API는 무엇인지, JSON은 무엇인지 등 서버 개발에 필요한 다양한 개념을 이해한다.스프링 부트를 이용해 간단한 GET/POST API를 만든다.디스크와 메모리의 차이를 이해하고 Database의 필요성을 이해한다.MySQL Database를 SQL과 함께 조작할 수 있다.스프링 서버를 이용해 Database에 접근하고 데이터를 조회,저장,수정,삭제할 수 있다.API의 예외 상황을 알아보고 예외를 처리할 수 있다.좋은 코드가 왜 중요한지 이해하기 스프링 부트 프로젝트를 설정하고 시작하는 방법기존 프로젝트 파일을 IDE를 통해서 build.gradle을 선택하여 시작합니다.스프링 https://start.spring.io/로 들어가서 스프링 환경 설정과 의존성을 추가하여 생성한뒤 1번 방식으로 실행한다. 서버란 무엇인지 서버 개발에 필요한 다양한 개념을 이해한다.서버는 serve + er 를 말하며 제공하다 단어와 er이 합쳐져 " 제공하는 것"을 의미합니다. 제공한다는 의미는 목적어가 붙게 되면, 기능을 제공하는 것을 서버라고 합니다. 것이라는 건 물건을 의미하고, 웹 서비스를 제공하기 위한 서버에서는 컴퓨터를 말합니다.서버가 기능을 제공하려면 누군가 원하는 기능을 요청을 해야 기능을 제공할 수 있습니다.요청하는 역할을 우리는 클라이언트라고 하며, 클라이언트 - 서버 관계는 요청-응답 관계로 이루어지게됩니다. 서버와 클라이언트가 서로 요청과 응답을 하기 위해서 통신 매개체가 필요한데 우리는 인터넷이라는 네트워크를 사용합니다. 인터넷을 통해서 요구사항을 서버에 전송을 하려면, 서버에 위치를 알아야합니다.인터넷 네트워크 환경에서 서버(컴퓨터)는 인터넷 회선마다 고유번호를 갖게되며 그걸 주소로 사용합니다.우리는 그걸 IP라고 합니다. 인터넷이 연결된 서버는 IP를 통해서 접근할 수 있으며, 기능을 제공하는 역할은 컴퓨터가 실행중인프로세스에게 요청을 해야하며, 프로세스는 고유의 번호인 포트를 받아 사용합니다.그래서 클라이언트가 특정 위치에 있는 컴퓨터가 실행하고 있는 특정 기능을 제공하는 프로세스에 접근하려면IP와 PORT 번호를 알고 있어야 접근하고 요청할 수 있습니다. HTTP인터넷 네트워크 환경에서 클라이언트와 서버가 안전하고 빠르게 요청과 응답을 하기 위해서 규칙이 필요한데그중 한가지 방법을 HTTP라고 합니다.요청 HTTP와 응답 HTTP는 차이가 있습니다.요청 HTTP는 HTTP Method,Path,query 또는 body 를 통해서 데이터를 전송하고응답 HTTP는 HTTP Status,body를 통해서 요청에 대한 응답을 전송합니다. APIAPI는 클라이언트와 서버가 원하는 기능을 제공하고 응답하기 위해 규칙을 정의합니다.서버가 정해진 기능을 제공하기 위해 인터페이스를 만들고,클라이언트는 해당 인터페이스 규격에 맞게 데이터를 전송하도록 하는것을 말합니다.이러한 규칙은 데이터를 교환하고 상호작용 하는데 필요한 명세서로 서버와 클라이언트 간의통신을 표준화하여 서로 다른 시스템 간의 통합을 용의하게 합니다. 스프링 부트를 이용해 간단한 GET/POST API를 만든다.GET @GetMapping("/add") // HTTP Method public int addTwoNumbers(@ModelAttribute CalculatorAddRequest request) { return request.getNumber1()+ request.getNumber2(); }POST @PostMapping("/multiply") // HTTP Method public int multiplyNumbers(@RequestBody CalculatorMultiplyRequest request) { return request.getNum1() * request.getNum2(); }요청 HTTP를 만들 때 HTTP Method가 꼭 필요하다고 했습니다.HTTP Method는 클라이언트가 원하는 동작을 서버에게 전송하기 위해 필요합니다.GET = 조회, POST = 등록 처럼 서버에게 원하는 기능을 전달하기 위해 필요합니다. 디스크와 메모리의 차이를 이해하고 Database의 필요성을 이해한다.클라이언트가 데이터 저장을 요청하여 저장했습니다.private final List<User> memory = new ArrayList<>();해당 방식으로 저장할 경우, 서버가 재시작되는 상황이 되면 기존에 있는 데이터는 사라집니다. 서버를 재시작하면 기존 데이터가 초기화가 되는 이유는 컴퓨터 구조때문입니다.컴퓨터는 CPU, RAM, SSD/HDD 하드웨어 구조로 되어있습니다.CPU는 연산을 하고, RAM은 CPU가 연산을 할때 필요한 데이터를 임시 보관하는 역할을 하며,SSD,HDD는 연산된 결과를 반 영구 저장하기 위해 필요합니다. 현재 방식은 데이터를 RAM에 저장하기 때문에 서버를 재시작하면 저장된 데이터는 사라집니다. 그래서 데이터를 반영구 저장하는 SSD나 HDD에 데이터를 저장해야하는데운영체제가 제공하는 기능을 프로그래밍 언어를 통해서 저장할 수 있지만,사용자가 원하는 구조로 데이터를 저장하고, 수정하기 위해서 데이터베이스 라는걸 사용합니다. MySQL Database를 SQL과 함께 조작할 수 있다.SQL에 대한 내용은 생략하겠습니다.MySQL에는 database라는 구조가 있습니다. 자바로 치면 최상위 패키지로 데이터를 저장할때 구분할 수 있는 폴더라고 생각하면 됩니다. 스프링 서버를 이용해 Database에 접근하고 데이터를 조회,저장,수정,삭제할 수 있다.자바 진영에서 데이터베이스에 접근하는 기술은 JDBC를 사용합니다.JDBC를 구체화한 클래스인 JDBCTemplate을 사용하여 데이터베이스를 사용할 수 있습니다. @PostMapping("/user") public void saveUser(@RequestBody UserCreateRequest request) { // users.add(new User(request.getName(), request.getAge())); String sql = "INSERT INTO user (name,age) VALUES (?,?)"; jdbcTemplate.update(sql, request.getName(), request.getAge()); }API의 예외 상황을 알아보고 예외를 처리할 수 있다.클라이언트가 요청한 기능과 필요한 데이터를 서버에서 검증을 하고 올바르지 않은 데이터가 들어온다면클라이언트에게 오류를 전달해야합니다. @PostMapping("/user") public void saveUser(@RequestBody UserCreateRequest request) { if (request.getAge() < 0) { throw new IllegalArgumentException("나이는 0살 이상만 가능합니다."); } String sql = "INSERT INTO user (name,age) VALUES (?,?)"; jdbcTemplate.update(sql, request.getName(), request.getAge()); } 좋은 코드가 왜 중요한지 이해하기백엔드 개발자는 클라이언트가 원하는 기능을 제공하기 위해 프로그래밍 언어를 통해서요구사항을 코드로 작성하는 역할을 합니다. 기술적인 요구사항이건, 비즈니스 요구사항 이건 결국 어떤 요구사항을 수행하기 위한 기능을 동작하기 위해서 코딩을 하게됩니다. 코드를 작성하는 일을 하지만, 코드를 작성하는 시간보다 코드를 읽는 시간이 더 많습니다.그리고 혼자서 일하는 개발자보다 팀으로 개발을 하게됩니다. 요구사항을 기능으로 동작하기 위해 작성된 코드를 다른 사람이 봐도 어떤 요구사항을 코드로 작성했는지 알 수 있어야합니다. 기존에 작성된 전체 코드를 확인해보면 @PostMapping("/user") public void saveUser(@RequestBody UserCreateRequest request) { // users.add(new User(request.getName(), request.getAge())); if (request.getAge() < 0) { throw new IllegalArgumentException("나이는 0살 이상만 가능합니다."); } String sql = "INSERT INTO user (name,age) VALUES (?,?)"; jdbcTemplate.update(sql, request.getName(), request.getAge()); }지금은 간단한 코드이지만, 수천줄이 된다면 해당 컨트롤러 기능인 saveUser를 수정하기 위해서는첫번째 줄부터 마지막 줄까지 읽어야합니다. 새로운 사람이 들어오거나 시간이 지나서 작성된 코드를 이해하기 위해서 소요되는 시간이 점점 늘어납니다.함수의 어느 부분을 수정할 경우, 전체 코드중 어디까지 영향을 미칠지 모릅니다.여러명이서 하나의 컨트롤러를 수정하기 위한 리소스가 많이 필요합니다.너무 큰 하나의 기능이 되어 테스트하기 어렵습니다.1~4번까지 맞물려 유지보수성이 떨어집니다.따라서 최대한 클린코드로 작성해야 생산성이 높아지게 됩니다. 1주차 간단 회고코드를 작성할때 우선 순위를 정하게 되었습니다.회사에서 저에게 주는 프로젝트는 프론트부터 백엔드까지 제가 만들기 때문에 시간에 쫒겨서 돌아기만 하는 코드 덩어리가 되었습니다.1주차 강의를 보고 직전에 작성된 프로젝트를 보니 돌아가기는 하는데 해당 함수가 무슨 기능을 하는지 알 수가 없어서처음부터 끝까지 코드를 읽어야했습니다.강사님이 말씀하신 코드는 요구사항을 표현하는 언어다 , 그리고 다른 사람이 코드를 봤을 때 요구사항을 한 눈에 파악할 수 있어야 한다는 걸 보고 반성을 많이 했습니다. 클린코드가 변수명, 하나의 기능, 하나의 책임은 알고 있어서 최대한 지키려고 했지만 이걸 하는 이유를 이해하지 못해서무작정 변수명 길게하고, 하나의 기능으로 나누고 , 하나의 책임으로 나누기만 하다보니 오히려 코드가 복잡해지고유지보수하기가 어려웠습니다. 앞으로 학습을 할 때도 새로나온 라이브러리니까, 빠르다고 하니까 , 좋다고 하니까 사용해야지라는 생각보다이걸 왜 사용하는지에 대한 이해를 먼저 하도록 하겠습니다. 2주차 학습 방법에 대한 목표2주차는 스프링 컨테이너와 트랜잭션 , JPA에 대한 강의인데이미 알고 있는 내용이지만, 왜 사용하는지에 대해 초점을 맞춰서 학습하도록 하겠습니다. 미션1일차:https://kamser0415.tistory.com/7어노테이션을 사용하는 이유 (효과) 는 무엇일까?나만의 어노테이션은 어떻게 만들 수 있을까? 어노테이션을 사용하는 이유를 찾기위해서 먼저 믿을 수 있는 공식 문서와 토비님의 강의를 참고했습니다.블로그에도 글이 많지만 공식 문서에서 작성된 내용은 만든 사람의 목적을 확인할 수 있다고 생각했고,토비님의 강의를 참고한 이유는 실무에서 오래 사용하신 개발자 분의 생각을 확인 하는 방법이라 생각했습니다.2일차: https://kamser0415.tistory.com/8간단한 GET 요청과 응답, POST 요청에 대한 문제입니다.주어진 두 수를 컨트롤어에서 받아서 덧셈,뺄셈,곱샙에 대한 결과를 응답의 결과로 내려주는게 문제입니다.연산만 책임지는 클래스를 만들어보자.연산의 결과를 반환하는 용도의 클래스를 만들자.연산만 책임지는 클래스를 만든 이유는 DTO에 연산 로직을 넣을까 생각을 했지만,단순한 값이 있다 없다, 특정 조건에 만족하는지 확인하는 것과 다른 연산이라는 로직이 들어가면다른 컨트롤러에서 사용하게 된다면 해당 로직이 필요하지 않을 수 있고, 거기서도 연산이 필요한데 연산 방식이 조금 차이가 있다면 그 DTO에 또 추가가 되면 DTO의 책임이 점점 커질수 있다고 생각했습니다.그래서 별도의 연산을 하는 클래스를 만드는게 좋다고 생각하여 만들게 되었습니다. 연산 클래스는 두 수를 인수로 받아 생성하고, 함수를 호출하면 받은 인수로 연산 결과를 반환합니다.여기서 실수한게 만약 요구사항이 변경되어 덧셈한 결과를 가지고 곱셈을 해달라고 한다면새로운 연산 클래스를 만들어야합니다. 그래서 다시 한다면 함수마다 연산할 인수를 전달받아 결과를 반환하는 순수 함수로 만들겠습니다.3일차:https://kamser0415.tistory.com/9람다가 등장한 이유람다와 익명 클래스 관계람다 간단한 사용 방법람다가 등장한 이유를 작성하기 위해서 익명 클래스가 등장한 이유익명 클래스의 단점1,2번을 먼저 찾아봤습니다. 익명 클래스를 보완하기 위해서 람다가 등장했다는건 알고 있었습니다.처음에는 익명 클래스와 람다의 관계는 제대로 찾아보기 전에는 익명 클래스 내에 람다가 포함된줄 알았습니다.자바는 1급 객체가 클래스이기 때문에 함수가 별도로 사용할 수 없기 때문에 결국 람다는 추상 메서드가 한개인 함수형 인터페이스를 익명클래스 방식에서 람다 표현식으로 만든거라 생각을 했습니다. 아직도 동일한 생각이지만, 함수형 인터페이스와 순수 함수에 대해서 한번 더 생각하게 되는 계기가 되었습니다. 4일차:https://kamser0415.tistory.com/10API를 통해서 과일 정보를 받아 저장한다.API를 통해서 판매된 과일 정보를 받고 결과를 반환한다.API를 통해서 받은 과일 이름으로 판매 완료금액과 판매되지 않은 금액의 합계를 반환한다.강사님께서 말씀하신 요청 HTTP를 서버에서 받기 위해 API 명세서를 확인하고 HTTP Method,Path,Body or Query에 맞는 컨트롤러 메서드를 만들고 매핑했습니다. API에서 숫자를 표현하는 방법은 int와 long이 있는데 long을 사용한 이유를 찾아봤습니다.제 생각에는 21억까지 표현할 수 있는 int 타입도 충분히 모든 과일의 금액을 표현할 수 있다고 생각을 했습니다. 검색을 해보니 가장 와닿은 말은 호환성이더라구요현재 데이터를 저장할 때 지금 스프링 부트를 사용하고 있지만, 다른 프레임워크나 프로그래밍언 언어에서도 사용하게 된다면 long이 더 적합하다는 것을 알게되었습니다. 회사마다 다르겠지만, 확장될 가능성이나 다른 프레임워크로 넘어가는 환경이 아니라면 int를 사용하는것도 나쁘지 않다고 생각됩니다. 5일차:https://kamser0415.tistory.com/11 클린 코드에 대해서 고민을 했습니다.전체 로직을 보면 주사위 크기는 6 이라고 지정되어있고, 밑에 추가 질문은 변경될 수 있다고 했습니다. 변수명 변경하기먼저 변수의 이름을 변경해서 해당 변수에는 어떤 데이터가 들어가는지 알 수 있도록 변경했습니다.각 기능을 함수 단위로 나누기주사위 보드판을 만드는 행위주사위를 던지는 행위주사위의 무작위 숫자가 나오는 행위나온 주사위 숫자를 기록하는 행위각 기능을 나누어보니 이걸 따로 따로 하는 것보다 주사위에 대한 놀이를 하나의 책임으로 생각하고 클래스로 만들면코드를 보기에 더 간편할거같다는 생각을 했습니다 주사위 머신 클래스 만들기그리고 주사위 머신에서 모든 일을 하는게 아니라 주사위 머신에 주사위 크기와 던지는 횟수를 입력하면내부에서 알아서 주사위를 만들고 주사위 기록을 저장하는 보드판을 만드는 책임을 가지게 합니다. 주사위를 던지는건 주사위 스스로 하도록 지정하여 숫자가 나오는건 주사위 클래스에게 책임을 위임했습니다. 코드로 작성할 때는 잘 작성했다고 생각을 했습니다. 이걸 글로 작성하다보니 책임을 어디까지 줄 것인지에 대해 한 번더 생각을 해보게 되었습니다.주사위 머신은 주사위를 만들고, 주사위 보드판을 만든다.주사위 머신은 주사위를 돌릴수 있는 기능이 있다.주사위를 돌리는건 주사위 객체가 한다.주사위 보드판은 주사위가 돌려진 숫자를 기록하는 기능이 있다.이렇게 코드를 작성하는게 더 나았을 거라는 생각이 들었습니다. 미션 회고지금까지 회사 일을 하면서 기능에 대해 집중하다보니 간단한 기능이라도 어디서 작업을 할지 고민을 하지 않고관습처럼 작성하는 습관이 있었습니다. 4일차때부터 강사님이 말씀해준 내용을 회사 프로젝트에 적용해보니 제가 생각하기에 코드를 좀 더 요구사항이 코드로 한 눈에 보이게 작성하려고 노력하였고,5일차때는 단순한 코드지만 리팩토링을 하면서 코드 작성하는게 재밌다는걸 느꼈습니다.

인프런워밍업최태현강사발자국

채널톡 아이콘