블로그

고승조

spring 과 springBoot의 차이점

Spring과 Spring Boot는 모두 스프링 프레임워크를 기반으로 한 자바 웹 개발 프레임워크입니다. 둘 간에는 몇 가지 차이점이 있습니다.Spring은 스프링 프레임워크의 핵심 모듈을 모아서 만든 프레임워크입니다. Spring에서는 개발자가 직접 설정 파일을 작성하여 스프링 컨테이너를 구성하고, 필요한 빈 객체를 등록하고, 빈 객체 간의 의존성을 설정해야 합니다. Spring은 특정한 구성을 위해 추가적인 라이브러리와 설정이 필요합니다.반면, Spring Boot는 스프링 프레임워크를 보다 쉽게 사용할 수 있도록 만든 프레임워크입니다. Spring Boot에서는 개발자가 설정 파일을 작성할 필요 없이, 프로젝트의 설정과 라이브러리 의존성을 자동으로 처리해주는 기능을 제공합니다. 또한, Spring Boot는 실행 가능한 JAR 파일을 만들 수 있습니다.Spring Boot는 Spring에서 제공하는 여러 기능들을 자동으로 설정하여 개발자가 보다 쉽게 사용할 수 있도록 해줍니다. 예를 들어, Spring Boot는 스프링 MVC, 스프링 Data JPA, 스프링 Security 등의 기능을 자동으로 설정하며, 개발자가 별도로 설정 파일을 작성하지 않아도 사용할 수 있습니다. 또한, Spring Boot는 Actuator라는 모니터링과 관리를 위한 기능을 제공하여, 애플리케이션의 상태를 모니터링하고, 필요한 조치를 취할 수 있도록 해줍니다.이러한 차이점들은 Spring과 Spring Boot의 사용 목적과 방식을 크게 달리 합니다. Spring은 개발자가 직접 설정 파일을 작성하고, 빈 객체를 등록하고, 빈 객체 간의 의존성을 설정하는 것을 요구합니다. 반면, Spring Boot는 개발자가 보다 쉽게 스프링을 사용할 수 있도록 설정과 의존성 처리 등을 자동으로 처리합니다. Spring은 스프링 프레임워크를 보다 세밀하게 제어하고자 하는 경우에, Spring Boot는 빠르고 간단하게 스프링 애플리케이션을 개발하고자 하는 경우에 사용됩니다.간단 요약 : 스프링(Spring)은 프레임워크이며, 스프링 부트(Spring Boot)는 스프링 프레임워크를 기반으로 한 도구입니다. 스프링은 설정 파일을 작성해야 하지만, 스프링 부트는 자동 설정을 제공하여 간편하게 개발할 수 있습니다. 또한, 스프링 부트는 내장 서버를 제공하여 쉽게 웹 애플리케이션을 실행할 수 있습니다. Spring은 스프링 프레임워크를 보다 세밀하게 제어하고자 하는 경우에, Spring Boot는 빠르고 간단하게 스프링 애플리케이션을 개발하고자 하는 경우에 사용됩니다.

스프링

왜 자바 백엔드 실무에선 스프링 부트가 중요할까?

한국은 물론, 세계적으로도 가장 인기 있는 서버 개발 스택은 자바(Java) 언어 기반의 스프링(Spring) 프레임워크를 이용한 백엔드 기술입니다. 스프링은 불필요하거나 반복적인 코드를 줄임으로써 코드의 복잡성을 낮추고, 개발자가 핵심 비즈니스 로직에 집중할 수 있도록 돕는 역할을 합니다.하지만 스프링을 사용하려면 초기 환경을 일일이 설정해야 하는 등 번거롭고 어려운 면이 있었는데요. 이런 스프링의 복잡한 부분을 개선하고 보다 손쉬운 웹 애플리케이션 개발을 가능하게 한 게 바로 스프링 부트(Spring Boot)입니다. 스프링 부트를 통해 XML 구성을 할 필요도 없고, Tomcat 등의 기본 HTTP 서버가 내장되어 있어 편의성은 높으면서도 더 빠른 개발이 가능하게 되었죠.이러한 스프링 부트를 통해 자바/스프링 개발자들은 초기 설정처럼 핵심적인 부분은 아니지만 빼놓을 수 없는 공정의 부담을 덜어내고, 프로그램 및 시스템 운용이라는 관점에 집중하여 개발할 수 있게 된 셈입니다.•••베테랑 시니어 개발자들이 알려주는 스프링 부트 노하우가 궁금하신가요?지금 인프런 프리즘 [스프링 부트 로드맵]을 통해 학습해보세요. https://www.inflearn.com/roadmaps/649•••인프런 프리즘 브랜드 스토리 읽어보기 >>

백엔드SpringSpringBootJava스프링스프링부트백엔드Back-End인프런프리즘InflearnPrism

요즘 백엔드 취업 시장에서 코프링이 핫하다던데?

코틀린(Kotlin)은 젯브레인즈(JetBrains)에서 개발한 크로스 플랫폼 범용 프로그래밍 언어입니다. JVM 기반의 언어이면서 자바(Java)와 100% 호환되도록 설계되었습니다. 구글은 2019년부터 코틀린을 안드로이드 개발 공식 언어로 지정했어요. 간결한 문법, 안정성, 다양한 기능이 있다는 장점과 함께 전 세계적으로 사랑받고 있는 언어입니다.그동안 백엔드에선 자바 언어와 스프링 프레임워크의 조합이 가장 압도적인 점유율을 차지하고 있었는데요. 최근엔 코틀린을 도입하거나 자바를 코틀린으로 대체하려는 기업이 늘면서 코틀린 언어와 스프링 프레임워크의 조합, 일명 '코프링'이 주목받기 시작했습니다. 실제로 현재 취업 시장을 살펴보면 코틀린 언어를 다루는 능력을 자격이나 우대 사항으로 기재해 두는 기업을 어렵지 않게 찾아볼 수 있어요. 하지만 비교적 최근에 주목받고 있는 만큼 백엔드 현업에서의 코틀린 혹은 코프링 관련 사례나 자료를 찾는 건 쉽지 않죠.앞으로 사용이 더 늘어날 것으로 전망되는 코틀린, 코틀린과 코프링의 세계에 발 빠르게 뛰어들고 싶다면 지금 시도해 보는 건 어떨까요?•••Java 개발자를 위한실무밀착형 코프링을 배우고 싶다면?지금 인프런 프리즘 [자바 개발자를 위한 실전 코프링 입문 (Kotlin + Spring)]을 통해 학습해보세요.https://www.inflearn.com/roadmaps/703•••인프런 프리즘 브랜드 스토리 읽어보기 >>

백엔드코틀린Kotlin스프링SpringSpringBoot스프링부트코프링백엔드인프런프리즘InflearnPrism

저니

스프링 가이드 목록 2022

* page : https://spring.io/guides     클릭하시면 해당 페이지로 넘어갑니다. 🍃 Building a RESTful Web Service Scheduling Tasks Consuming a RESTful Web Service Building Java Projects with Gradle Building Java Projects with Maven Accessing Relational Data using JDBC with Spring Uploading Files Authenticating a User with LDAP Messaging with Redis Messaging with RabbitMQ Accessing Data with Neo4j Validating Form Input Building a RESTful Web Service with Spring Boot Actuator Messaging with JMS Creating a Batch Service Securing a Web Application Building a Hypermedia-Driven RESTful Web Service Accessing Data in Pivotal GemFire Integrating Data Caching Data with Pivotal GemFire Managing Transactions Accessing Data with JPA Accessing Data with MongoDB Serving Web Content with Spring MVC Converting a Spring Boot JAR Application to a WAR Creating Asynchronous Methods Handling Form Submission Building an Application with Spring Boot Using WebSocket to build an interactive web application Working a Getting Started guide with STS Consuming a RESTful Web Service with AngularJS Consuming a RESTful Web Service with jQuery Enabling Cross Origin Requests for a RESTful Web Service Consuming a SOAP web service Accessing JPA Data with REST Accessing Neo4j Data with REST Accessing MongoDB Data with REST Accessing Data in Pivotal GemFire with REST Producing a SOAP web service Caching Data with Spring Deploying to Cloud Foundry from STS Spring Boot with Docker Working a Getting Started guide with IntelliJ IDEA Creating CRUD UI with Vaadin Service Registration and Discovery Centralized Configuration Testing the Web Layer Accessing data with MySQL Creating a Multi Module Project Creating API Documentation with Restdocs Messaging with Google Cloud Pub/Sub Building a Reactive RESTful Web Service Consumer Driven Contracts Accessing Vault Vault Configuration Accessing Data Reactively with Redis Deploying a Spring Boot app to Azure Building a Gateway Client-Side Load-Balancing with Spring Cloud LoadBalancer Spring Cloud Stream Spring Cloud Data Flow Spring Cloud Task Spring Boot Kubernetes Accessing data with R2DBC Spring Cloud Circuit Breaker Guide Observability with Spring Building a Guide with VS Code Accessing Data with Cassandra Spring Security Architecture Spring Boot Docker Spring on Kubernetes Building REST services with Spring Spring Security and Angular React.js and Spring Data REST Spring Boot and OAuth2 Building web applications with Spring Boot and Kotlin Spring Boot with Kotlin Coroutines and RSocket Metrics and Tracing with Spring     var list = Array.from(document.getElementsByClassName('guide-link')); list.forEach((e) => { console.log('* [' + e.innerHTML + '](http://spring.io' + e.getAttribute('href') + ')'); }); 출처 : https://okky.kr/article/1209730

백엔드스프링프레임워크가이드springframeworkbackendguides

스프링 AOP

AOP(Aspect-Oriented Programming)는 객체 지향 프로그래밍의 한계를 보완하기 위해 등장한 프로그래밍 패러다임입니다. 스프링 AOP는 스프링 프레임워크에서 AOP를 구현한 것으로, 코드의 횡단 관심사(cross-cutting concerns)를 분리하여 모듈화하고, 공통 로직을 재사용하는 기능을 제공합니다.AOP에서 횡단 관심사란, 애플리케이션의 여러 부분에서 공통으로 사용되는 로직입니다. 예를 들어, 로깅, 보안, 트랜잭션 관리 등이 있습니다. 이러한 로직은 애플리케이션 전반에 걸쳐 중복되어 사용될 수 있습니다. 이때 AOP를 이용하면 공통 로직을 모듈화하여 각 부분에서 코드의 재사용성과 가독성을 높일 수 있습니다.스프링 AOP는 프록시 패턴과 런타임 코드 생성을 이용하여, 메서드 호출 시점에 공통 로직을 삽입하는 방식으로 동작합니다. 메서드 호출을 가로채어 공통 로직을 수행하고, 호출한 메서드의 결과를 반환하는 방식입니다. 이를 위해 스프링은 Join Point, Pointcut, Advice, Aspect 등의 개념을 제공합니다.Join Point는 공통 로직이 삽입될 수 있는 지점으로, 스프링은 메서드 호출을 기준으로 Join Point를 정의합니다. Pointcut은 Join Point 중에서 실제로 공통 로직이 적용될 메서드를 선택하는 기능을 수행합니다. Advice는 실제로 삽입될 공통 로직을 의미합니다. Aspect는 Pointcut과 Advice의 조합으로, 특정한 기능을 담당하는 AOP 모듈을 의미합니다.스프링 AOP는 프로그램 전반에서 중복되는 로직을 간편하게 모듈화할 수 있는 기능을 제공하여, 코드의 가독성과 재사용성을 높입니다. 또한, 스프링의 다양한 기능과 연동하여, 보안, 로깅, 트랜잭션 처리 등 다양한 영역에서 활용됩니다.예시@Aspect public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("Before executing " + methodName + " method"); } @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result") public void afterReturningMethod(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.println("After executing " + methodName + " method"); } }위 코드는 LoggingAspect라는 이름의 클래스를 정의하고, @Aspect 어노테이션을 사용하여 스프링 AOP에서 Aspect로 등록합니다. @Before, @AfterReturning 등의 어노테이션을 이용하여 메서드 실행 전/후에 로그를 출력하는 Advice를 정의합니다.@Before 어노테이션은 execution 패턴을 이용하여, com.example.service 패키지의 모든 메서드가 실행되기 전에 공통 로직을 수행하도록 설정합니다. JoinPoint 인터페이스를 이용하여 현재 실행되는 메서드의 정보를 추출하고, 메서드 이름을 출력합니다.@AfterReturning 어노테이션은 실행된 메서드가 정상적으로 반환될 때 공통 로직을 수행하도록 설정합니다. returning 속성을 이용하여 반환된 값을 추출하고, 메서드 이름을 출력합니다.위와 같이 스프링 AOP를 이용하면 메서드 실행 전/후에 공통 로직을 간단하게 삽입할 수 있습니다.

스프링

Rojojun

[워밍업 클럽 스터디 2기::백엔드] 후기

스터디 회고4주간 스터디를 쉼없이 달려왔다.여러가지 일이 있었고, 재미있는 지점도 지루한 지점도 존재하였다.하지만 중요한 건 포기하지 않고 계속 한다 라는 가장 원론적이고 근본적인 자세다! 이미 지나간 말인데 중요한 건 꺾이지 않는 마음이라는 것 같다! 감상적인 이야기는 여기서 끝내고, 회고답게 이 스터디에서 얻어간거 추천하는 것 등등 모든 것을 빠짐 없이 기록하여 3기를 참여하고자 하는 사람들에게 도움을 주고자한다. 스터디 추천도무조건 추천한다! 다만, 끝까지 완주할 의지가 있을 경우에만 추천한다.완주라는게 어떤 사람들은 4주의 진도를 막힘없이 따라가는 것이고, 어떤 사람들은 진도가 중요한게 아니라 4주안에 어떻게든 끝내는 것이 될 수 있다.인프런에서는 4주의 진도를 막힘없이 따라가면 완주러너, 그리고 거기서 더 잘하면 우수러너라는게 있다.즉, 동기부여가 될게 두 가지가 있다는 것이다. 완주러너 & 우수러너하지만 가장 큰 동기부여는 무언가를 뛰어넘어 성장한 자기자신이지 않을까?약간 나는 애니덕후 기질이 있어서 나의 히어로 아카데미아를 좋아하는데 한계를 뛰어넘어라는 이야기를 이야기를 좋아한다.각자 외부에서 주는 동기부여가 아닌 내부에서 주는 동기부여로 한계를 뛰어넘는데 의의가 있는 것이다. 커리큘럼의 난이도또 하나 중요한거 나는 클린코드 & 테스트코드 스터디를 진행하게 되었는데, 시원하게 오픈하면 나는 2년차 백엔드 개발자다 (이번주에 진짜 2년이 되요~~!! 🥳)혹자가 봤을 땐 아닐 수도 있는데, 아직 나는 응애 아가 개발자 중 하나라는 것이다.그런 내가 보았을 때 난이도는 적절한편이다. 중립적인 단어인거 같은데, 어려운 부분은 어려웠다.쉬운부분은 쉬웠고, 그니깐 난도 조절을 정말 잘했다는 것이다... 이것은 강사님의 강의의 퀄리티가 좋다! 라는 것과 일맥상통하는데, 나는 강의에 금액 투자를 신중하게 한다.강사님들에게는 죄송한 이야기지만 어찌되었든간에 나는 소비자니깐! 소비하려는 제품이 얼마나 좋은지 봐야하는데, 확실한 제품아니면 잘 안 구매한다ㅋㅋ...그렇지만! 이번 강의는 진짜 좋다! 더 나은 백엔드 개발자를 고민하였다면 구매를 추천한다! 정리하자면Readable Code 강의는 클린코드를 읽어만 본 사람들, 혹은 적용을 하는데 많이 못하는 사람들에게 추천하는 난이도다.근데, 기본적으로 자바에 대해서 혹은 OOP에 대해서 잘 모른다하면 권장하지 않는다.https://www.inflearn.com/course/practical-testing-%EC%8B%A4%EC%9A%A9%EC%A0%81%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9D%B4%EB%93%9C/dashboardTest Code 강의는 아이러니한 부분이긴 한데, 클린코드를 읽어 보거나 회사 실무내에서 테스트코드가 없이 테스트 하는 것에 대해 한계를 느낀 개발자들에게 추천하는 난이도이다.근데, 기본적으로 다양한 테스트를 경험해보지 않는다면... 테스트코드가 얼마나 좋은지 모를지도 모른다.그냥 내 발목을 붙잡는 쓸모없는 거라고 생각할 수도?https://www.inflearn.com/course/readable-code-%EC%9D%BD%EA%B8%B0%EC%A2%8B%EC%9D%80%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%EC%82%AC%EA%B3%A0%EB%B2%95/dashboard 이건 좋아요첫번째, 강사님의 빠른 피드백과 코드 리뷰 너무 좋았다.코드 리뷰도 신청하면 대부분 다 해줘서, 진짜 너무 좋았다.이게 참 강사님 입장에서도 시간적으로 비용일텐데 이렇게 우리 수강생들에게 엄청난 투자를 해줬다는 것에 대해 압도적으로 감사를 가진다!두번째, 전반적인 운영이 매끄러웠다.'인프런에서 진행해서...' 라는 이야기를 안하고, 여타 다른 운영과 비교해 보았을 때 꽤나 괜찮은 운영이라고 느껴졌다.특히나, 디스코드 내에서 직원분들이 이것저것 질문에 대해서 답변을 빠르게 해주거나 아니면 수강생들끼리 채널을 열 수 있게 하는 그런 것들을 하나의 시스템 제도로 만들어서 참 잘 활용하는 것 같다.세번째, 동료들이 자극을 준다.물론 나는 회사동료들하고 같이해서 서로가 서로에게 자극을 주었지만, 이 스터디는 디스코드로 진행되어 자유롭게 이야기를 할 수 있다.여기서 자유롭게 이야기를 할 때 많은 사람들이 스터디 관련해서 이야기 하고 어떤 분은 공부시간 체크, 오늘 한 것 체크 등등 엄청난 분들이 있다 (이름도 외웠다 ㅋㅋㅋㅋ)사실 그 분들을 보면서 엄청 자극이 되서 나도 열심히 공부하게 되는 경우가 있었다. 이건 나빠요좋은 말만 쓰는 것은 싫다 ㅋㅋ 억까라해도 스터디의 단점으로서 장점처럼 세가지를 정할 것이다.첫번째, 야생이다.자신이 진짜 누군가 케어를 해줘야만 공부를 하는 타입이라면, 중도 포기할 가능성이 높다.특히나, 이 스터디는 본인의 의지가 중요한 것이기 때문에, 중간에 '아 밀렸어 안해 포기!' 이렇게 되는 이상 돌이킬 수 없다...두번째, 짧은 네트워킹 타임일단 네트워킹 타임이 50분이라는게 좀 아쉽다... 사람에 따라 다를 수 있는데, 나는 좀 말이 많고 다른 사람들하고 이야기 하는 것을 좋아해서 다른 사람들 그리고 다른 회사에서 어떻게 일하는지 궁금하고 그게 나의 인사이트가 되고 싶은데... 뭔가 엔진이 과열될만 하면 끝나버린다!충분히 이해할 수 있는게 한정된 시간 속에서 진행하는 거고 다 나 같은 사람일거라 생각하지 않기 때문에 이해하는 부분이다.세번째, 낯가리는 우리들...문제는 우리다! 다들 낯을 너무 많이 가린다... 스터디를 함으로서 제2차 파생된 그룹이 나오거나 하는 선순환이 많이 나와야하는데 공개적으로는 두개? 밖에 못본거 같다! 물론, 나도 이건 할 말이 없는데!다음에 스터디를 하게 된다면, 나도 낯을 안가리고 조금 주도하는 역할로 롤을 변경해봐야하지 않나 싶다! 혼자 공부하는게 아니라 같이 공부해야만 내 공부와 내 가설이 맞는지 검증이 되기 때문이다. 진짜 마지막참 우여곡절이 많은 스터디다.뭐 잘하지도 않고, 글재주도 안좋고 마지막만 사진 좀 넣었는데 ㅋㅋㅋ 평소에는 사진도 안넣는다.비효율적인 것을 극도로 자제하는 스타일이라 이런 것을 싫어한다.그런 내게 우수러너라는 상을 준 것에 대해 진짜 너무 감사하고 함께 스터디를 한 내 동료들 진짜 항상 같이 스터디 하는 동료들을 보며 느낀게, 우리가 지금은 이 자리에 있지만 앞으로 더 나아가자는 이야기를 하는데 진짜 진심이다.믿고 의지할 수 있는 동료고 더 높은 자리에서 서로를 볼 수 있을거라고 확신한다. 마지막은 우수러너로 받은 잔, 근데 하이볼을 곁들인 ㅇ_< 

백엔드인프런인프런워밍업클럽스터디2기java자바스프링

유원준

[인프런 워밍업 클럽(백엔드, 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) 현재 어노테이션을 사용해서 코드의 가독성이 좋아짐은 물론 어노테이션 자체가 되게 많은 일을 대신 해주고 있는 것을 확인해 볼 수 있다. 이 부분은 자바의 리플렉션 기술들이 해결해 주고 있는데 추후에 리플렉션에 관한 내용을 블로그에 다시 한 번 정리해 볼 예정이다.  마지막으로 부족하지만 글을 읽어주신 분들께 감사드립니다!!  

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

wisehero

<인프런 워밍업 스터디 클럽 0기> - BE 발자국 1주차

사실 강의 수강은 워밍업 클럽이 열리기 전부터 듣고 있었어요. 이미 JPA로 전환하는 부분까지 다 넘어갔었습니다. 사실 이것때문에 30% 할인 쿠폰을 미리 받지 못한 것에 대해서는 조금 아쉽긴 했습니다 ㅋㅋㅋ. 강의를 수강하게 된 이유는 저는 국비교육을 수료한 이후로 다른 정량적 스펙이나 코딩테스트, 자기소개서에 시간을 너무 많이 쓰게 되었고 중간에 인턴이나 현재 재직중인 직장에서는 스프링 부트나 스프링 5이상 버전, JDK 11~21 버전을 사용하지 않는 환경에 있었어요. 그래서 최근 개발 트렌드나 버전에 따른 변화에 뒤쳐지지 않기 위해 강의를 수강하기 시작했습니다. 1주차 동안은 주로 강의를 다시 듣는 것은 아니었고 이미 들었던 강의, 강의를 들으면서 작성했던 코드들을 다시 한번 보게 되었어요. 이 과정에서 JPA를 주로 사용하는 바람에 JdbcTemplate을 잘 사용해본 적이 없어서 이에 다시 적응하는 시간이 되어서 좋았습니다. 그리고 정말 레이어드 아키텍처에 따른 모든 코드들을 오랜만에 작성하면서 예전에 국비 교육때 열심히 했던 시간들을 다시 한번 되새길 수 있었고, 취업 준비를 하면서 많이 꺾였던 마음을 다시 세울 이유와 동기를 얻는 과정이어서 좋았습니다. 아쉬웠던 점은 시간이 그렇게 많지 않아, 과제 수행 중에 발견한 문제점이나 궁금했던 점에 대해 따로 깊이 파볼 시간이 조금 부족했던 것이 있습니다. 아무래도 2월부터 회사에 다니게 되었고 이 루틴이 익숙치 않아 오는 문제점인것 같은데 어떻게든 해결책을 마련해서 극복해야겠습니다. 워밍업 클럽을 진행하면서, 혹은 강의를 수강하면서 스스로에게 그나마 좋았다고 말해줄 수 있는 점은 질문을 적극적으로 하는 자세였습니다. 아마도 태현님 강의에서 질문을 제일 많이 한 것 같아요. 그리고 그 질문들중 좋은 질문이라고 반응해주셔서 행복했고, 태현님이 제 질문에 답변을 주신 것을 다른 분들의 질문에 대한 답변으로 대신하시는 것을 보고 '내가 의미있는 질문을 했구나'하는 생각을 했습니다. 세상에 멍청한 질문은 없다지만, 그 질문들 가운데서도 핵심을 짚는, 가치가 높은 질문들은 있다고 생각을 하는데 그런 질문을 하는 사람이 되어간다는 느낌을 받았습니다. 앞으로도 그런 질문을 계속 던질 수 있는 개발자가 되어야겠다고 다짐했던 좋은 경험이었습니다. 미션 수행과 관련해서...미션 수행은 저 말고도 다른 분들도 크게 어렵지 않게 해결하셨을거 같아요. 다만 저의 경우엔 몇 가지 아쉬운점이 있었어요. 어노테이션 관련해서 딥다이브를 하는 과정에서 과연 '딥'하게 들어갔는지에 대해는 의문이었어요. 다른 분들은 어노테이션이 '마법'을 일으키는 과정을 따라들어가보면 '리플렉션'이라는 개념이 등장하는데 제가 이 리플렉션 코드를 직접 짜보거나 하지는 않았거든요. 반성해야할 지점이었습니다. 단순히 개념적인 것, 글만 읽고 끝내는 공부를 또 반복하게 된듯한 느낌이었거든요.  나머지 미션들이 크게.. 특별히 어려웠던 점은 없었는데 코치님께서 남겨주신 4일차 과제 피드백을 듣고 다음에 비슷한 동작을 수행하는 코드를 작성할 때 더 좋은 코드를 작성할 수 있는 법을 배웠어요. 코치님이 남기신 피드백 내용은 다음과 같습니다.제가 이 피드백에서 교훈을 얻은 이유는 코치님이 언급하신, 데이터베이스에서 데이터를 전달해주고, 서버에서 연산 작업을 처리하게 되어 네트워크 대역폭 증가와 서버 자원 사용량의 증가라는 효과를 불러일으키는 방식으로 코드를 작성했기 때문이에요. 그렇다면 왜 그런 코드를 작성했을까요?사실 그냥 이 과제가 SQL 문제로 주어졌다면, 저는 아무런 고민없이 데이터베이스에서 바로 연산을 하는 SQL문을 바로 짤 수 있었을 거에요. 하지만 서버 애플리케이션 프로그래밍을 배우면서 이런 얘기를 들었어요. '데이터베이스에서 비즈니스 로직을 처리하게 되면 DB 종속적으로 프로그래밍을 하게 되어 서버 애플리케이션의 존재 의미가 흐릿해진다.'실제로도 현재 근무하고 있는 회사에서는 비즈니스 로직이 오라클 데이터베이스의 프로시져에 몽땅 때려박혀있는 구조이고 저는 이것을 지금 개선하고 있기 때문에 DB라는 것에서 어떤 처리를 최소한으로 하려고 하는 습관이 생겼어요. 그리고 여기에 더해 강의를 통해 자바 스트림을 적극적으로 사용하는 것을 보고, 스트림 처리를 적극적으로 사용하는 것이 간결하고 명확하며 멋져보여서 이를 적극적으로 사용하는 것이 머리 속을 지배했습니다.하지만 저는 과제의 요구사항이 '통계성 데이터를 반환하는 것'이라는 것을 잊고 있었고 이에 따른 트레이드 오프를 고민하는 자세를 갖지 못하고 바로 서버에서 스트림으로 연산을 처리해야겠다는 사고에 지배를 당해 아래와 같이 코드를 작성했습니다.@Transactional(readOnly = true) public List<Long> fruitStat(String name) { fruitRepository.findFruitsByName(name); List<Fruit> findFruits = fruitRepository.findFruitsByName(name); if (findFruits.size() == 0) { throw new IllegalArgumentException("해당 이름을 갖고 있는 과일이 없습니다."); } Long salesAmount = findFruits.stream().filter(Fruit::getSold).mapToLong(Fruit::getPrice).sum(); Long notSalesAmount = findFruits.stream().filter(fruit -> !fruit.getSold()).mapToLong(Fruit::getPrice).sum(); return List.of(salesAmount, notSalesAmount); } 이름 하나를 넘겨받고 그 이름과 동일한 이름을 가진 과일을 모두 가져오고, 팔린 물건과 그렇지 않은 물건을 따로따로 계산해주고 있습니다. 하지만 저 코드는 Fruit 테이블에 엄청나게 많은 데이터가 있었다면, 합을 구하는데 오랜 시간이 걸릴 수 있음이 분명했습니다. 통계성 데이터 처리는 그냥 한꺼번에 디비에서 해서 넘겨주는 것이 더 컴퓨팅 자원을 덜 소모할 수 있는 방법이라는 것을 분명 공부했지만 하나의 문제를 해결할 수 있는 방법을 여러개 놓고 그 중에 고른다기보다 저는 기존에 배웠던 것을 새로 배운 것으로 덮어쓰기 해버리는 바람에 트레이드 오프를 고려하는 습관을 유지하지 못한 부끄러움이 있었습니다. 그래서 우선 오늘은 자고 내일 개선해보자라고 생각했으나 마침 6일차 과제에 JPA가 아닌 JdbcTemplate을 사용할 것을 가정하고 나온 과제 내용을 다시 보고 개선할 수 있는 기회를 얻었습니다. 그래서 작성한 코드는 아래와 같습니다.동일한 작업을 모두 SQL로 작성하고 이를 DB에서 처리하게 했습니다. 이렇게 하고 단순히 응답을 맵으로 감싸서 넘기는 방식을 취하고 있죠. 만약 통계 결과를 얻기 위한 데이터가 엄청 많다면 이러한 방식이 더 효율적일 것 같습니다. 다음엔 좀 더 많은 임의의 데이터를 넣고 코드를 시험해봐야겠습니다. 감사합니다.

백엔드워밍업클럽백엔드최태현스프링

유원준

[ 인프런 워밍업 클럽(백엔드, 0기)] - 0일 차 오리엔테이션 회고!

안녕하세요! 이번 인프런 워밍업 클럽 백엔드 스터디 0기에 참여하게 되었습니다.기존 Java, Spring, JPA로 백엔드를 공부했고, 그동안 배웠던 내용을 체화시켜야 할 기회가 필요했습니다.학습만 하고 체화시키지 않는다면 절대 본인의 지식이 될 수 없다고 생각하고 있기 때문입니다. 만약 학습한 내용을 바로 머릿속에 오래 남겨둘 수만 있다면 큰 행운인 것 같습니다. 하지만 저도 사람이기에 단순히 눈으로 보기만 한 내용은 기억에 오래 남지 못하는 것 같습니다. 저랑 비슷하신 분이 계실진 모르겠지만 배운 내용, 실습한 내용들을 본인의 GitHub나 개인 블로그에 잘 정리해 놓으면 상당히 기억에 오래 남고, 필요한 부분을 다시 찾아볼 수 있다는 점 때문에 저는 기록하는 것을 항상 좋아합니다! 제 루틴대로 배웠던 학습 내용들을 정리하고, 과제, 프로젝트 수행 부분 또한 별도로 블로그, GitHub에 정리할 예정입니다. 열정 가득한 코치님, 참가자분들과 함께 공부할 수 있게 되어 기쁜 마음입니다!백엔드 0기로 합류하시게 된 분들 모두 같이 파이팅했으면 좋겠습니다 😀 감사합니다 😀 

백엔드인프런워밍업백엔드스프링발자국0기화이팅!

TDD

TDD는 Test-Driven Development(테스트 주도 개발)의 약어로, 소프트웨어 개발 방법론 중 하나입니다. TDD는 개발자가 코드를 작성하기 전에 테스트 케이스를 먼저 작성하고, 이를 통해 개발된 코드의 품질을 보장하고자 합니다.TDD의 핵심 개념은 "Red-Green-Refactor"입니다. 개발자는 먼저 테스트를 작성하여 실패하는 테스트 케이스를 만듭니다. 이후 코드를 작성하여 테스트를 통과시킵니다. 마지막으로, 코드를 리팩토링하여 개선합니다.TDD를 통해 코드 품질을 향상시키는 이유는 다양합니다. 첫째로, 테스트 케이스를 먼저 작성함으로써 개발자는 코드의 기능을 명확하게 이해하고 설계할 수 있습니다. 둘째로, 테스트 케이스를 통해 코드의 동작을 검증함으로써 버그를 발견하고 수정할 수 있습니다. 셋째로, TDD는 코드의 유지보수를 용이하게 합니다. 테스트 케이스를 작성함으로써 코드 변경에 따른 부작용을 쉽게 파악할 수 있기 때문입니다.TDD는 또한 지속적인 통합과 배포에도 매우 유용합니다. TDD를 사용하면 변경 사항이 발생했을 때 자동화된 테스트 스위트를 실행하여 코드의 안정성을 검증할 수 있습니다. 이를 통해 빠른 시간 내에 안정적인 소프트웨어를 배포할 수 있습니다.하지만 TDD는 모든 상황에서 적용하기에는 적합하지 않을 수 있습니다. 특히, 복잡한 시스템에서는 TDD를 적용하기 어렵거나 시간이 많이 걸릴 수 있습니다. 따라서 TDD는 개발 방법론 중 하나일 뿐, 상황에 따라 적절히 선택하여 사용해야 합니다.간단 요약 : TDD는 코드 작성 전 테스트 케이스를 작성하여 개발자가 코드 품질을 보장하는 소프트웨어 개발 방법론이다. TDD를 사용하면 코드의 기능을 명확하게 이해하고 설계할 수 있으며, 버그를 발견하고 수정할 수 있다. 또한 지속적인 통합과 배포를 용이하게 한다.

스프링

REST API

REST(Representational State Transfer)는 분산 시스템에서 서버와 클라이언트 사이의 통신 방식을 규정한 아키텍처 스타일입니다. REST API는 이러한 아키텍처 스타일을 따르는 API입니다.REST API는 HTTP 프로토콜의 메서드(GET, POST, PUT, DELETE 등)를 이용하여 데이터를 주고받습니다. URI(Uniform Resource Identifier)를 이용하여 요청하는 리소스를 표시하고, HTTP 메시지의 헤더와 바디에 포함된 정보를 이용하여 요청 처리 결과를 반환합니다. REST API의 특징으로는, 각 리소스는 고유한 URI를 가지며, URI에 대한 요청은 의도를 명확하게 나타내야 한다는 것이 있습니다.REST API를 사용하면, 다양한 클라이언트에서 플랫폼에 독립적으로 데이터를 주고받을 수 있으며, API의 확장성과 유연성이 높아집니다. 또한, REST API를 사용하면 캐싱 등 다양한 웹 기술을 활용하여 성능을 최적화할 수 있습니다.스프링 프레임워크에서는 Spring MVC를 이용하여 REST API를 개발할 수 있으며, Jackson 라이브러리를 이용하여 JSON 데이터를 처리하는 등 다양한 기능을 제공합니다. 또한, Spring Boot를 이용하여 REST API를 쉽게 개발하고 배포할 수 있습니다.GET 메서드: 리소스의 정보를 요청할 때 사용합니다. 웹 브라우저에서 주소 창에 URL을 입력하여 웹 페이지를 요청할 때 사용되는 메서드입니다.POST 메서드: 서버에 데이터를 제출할 때 사용합니다. 대표적으로 회원가입, 로그인 등에서 사용됩니다.PUT 메서드: 서버에 데이터를 업데이트할 때 사용합니다. 대표적으로 게시물 수정, 파일 업로드 등에서 사용됩니다.DELETE 메서드: 서버에 있는 데이터를 삭제할 때 사용합니다. 대표적으로 게시물 삭제, 파일 삭제 등에서 사용됩니다.PATCH 메서드: PUT 메서드와 유사하게 데이터를 업데이트할 때 사용합니다. 하지만 PUT 메서드는 전체 데이터를 업데이트하고, PATCH 메서드는 일부 데이터만 업데이트합니다.

스프링

스프링 트랜잭션 처리

스프링에서 트랜잭션 관리란, 여러 개의 데이터베이스 작업을 한 덩어리로 묶어서 실행하고, 실행 결과가 모두 정상이면 데이터베이스 상태를 일관성 있게 유지하는 것입니다. 예를 들어, 계좌 이체를 처리하는 과정에서 첫 번째 계좌에서 출금을 하고, 두 번째 계좌로 입금을 하는데, 이 과정에서 한 번이라도 오류가 발생하면 둘 다 처리되지 않도록 하는 것입니다.스프링에서는 트랜잭션 관리를 위한 기능을 제공하며, 이를 사용하면 프로그래머가 직접 코드를 작성하지 않아도 데이터베이스 작업을 트랜잭션으로 묶어줄 수 있습니다. 이를 Declarative Transaction Management라고 부르며, 메서드에 @Transactional 어노테이션을 추가하면 해당 메서드에서 실행되는 데이터베이스 작업이 모두 트랜잭션으로 처리됩니다.이 방법을 사용하면, 데이터베이스 작업을 실행하는 코드에 트랜잭션 처리 코드를 추가하지 않아도 되므로 코드가 간결해집니다. 또한, 중복 코드를 제거하여 유지보수성을 높일 수 있습니다.예시@Service public class MyService { @Autowired private MyMapper myMapper; @Transactional public void transferMoney(String fromAccount, String toAccount, int amount) { // 출금 myMapper.withdraw(fromAccount, amount); // 입금 myMapper.deposit(toAccount, amount); } }위 코드에서 @Service 어노테이션을 사용하여 MyService 클래스를 스프링 빈으로 등록합니다. @Autowired 어노테이션을 이용하여 MyMapper 인터페이스를 구현한 클래스를 주입받습니다.@Transactional 어노테이션을 사용하여 transferMoney() 메서드에서 실행되는 데이터베이스 작업이 트랜잭션으로 처리되도록 설정합니다. 출금과 입금 작업이 모두 성공해야만 트랜잭션이 커밋되며, 그렇지 않으면 롤백됩니다. 이렇게 하면, 중간에 예외가 발생하더라도 출금과 입금 작업이 모두 취소되므로 데이터베이스 상태가 일관성 있게 유지됩니다.간단 요약 : 스프링에서 제공하는 트랜잭션 관리 기능을 이용하면, 여러 개의 데이터베이스 작업을 한 덩어리로 묶어서 실행하고, 실행 결과가 모두 정상이면 데이터베이스 상태를 일관성 있게 유지할 수 있습니다. @Transactional 어노테이션을 이용하여 메서드 단위로 트랜잭션을 설정하고, 이를 Declarative Transaction Management라고 부릅니다. 이 방법을 사용하면 코드가 간결해지고, 중복 코드를 제거할 수 있습니다.

스프링

spring IoC/DI

IoC(Inversion of Control)는 제어의 역전을 의미하며, 객체 생성과 생명주기 관리 등을 개발자가 아닌 프레임워크에 위임하여 의존성 관리를 단순화하고 유지보수성을 높입니다. 기존에는 객체 생성과 의존성 주입 등을 직접 구현하여 개발해야 했습니다. 하지만, IoC는 객체의 생성 및 관리를 프레임워크에 위임하고, 객체 간의 의존성 주입을 프레임워크가 자동으로 처리하므로 개발자는 코드 구현에 집중할 수 있습니다.DI(Dependency Injection)는 의존성 주입을 의미하며, 객체를 생성하고 이용하는 시점에서 필요한 의존 객체를 주입하는 방식입니다. 이를 통해 객체 간의 결합도를 낮추고 유지보수성을 높일 수 있습니다. 예를 들어, 객체 A가 객체 B에 의존하는 경우, 일반적으로는 객체 A가 객체 B를 직접 생성하고 의존성을 주입합니다. 하지만, DI를 이용하면 객체 A가 필요한 객체 B를 외부에서 주입받아 사용할 수 있으므로, 객체 간의 결합도를 낮출 수 있습니다.IoC와 DI를 함께 사용하여, 객체 생성 및 의존성 주입 등을 자동화하여 개발자의 부담을 줄이고 애플리케이션의 유연성과 확장성을 높일 수 있습니다. 스프링 프레임워크는 IoC와 DI를 중심으로 구성되어 있으며, BeanFactory와 ApplicationContext를 제공하여 객체의 라이프사이클을 관리하고, 객체 간의 의존성을 주입하는 기능을 제공합니다. 이를 통해 스프링은 유지보수성이 높은 애플리케이션을 쉽게 개발할 수 있습니다.간단 요약 : IoC(Inversion of Control)는 객체 생성 및 생명주기 관리 등을 프레임워크에 위임하여 의존성 관리를 단순화합니다. DI(Dependency Injection)는 객체 간의 의존성을 주입하는 방식으로, 객체 간의 결합도를 낮추고 유지보수성을 높입니다. 스프링 프레임워크는 IoC와 DI를 중심으로 구성되어 있으며, 객체의 라이프사이클을 관리하고, 객체 간의 의존성을 주입하는 기능을 제공합니다.

스프링

sdsd988

워밍업 클럽 2기 백엔드 클린코드&테스트 Day 18 미션

1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이 @Mock, @Spy 차이- '가짜'이냐 '진짜'이냐의 차이- @Spy' 진짜' 객체라면, 객체 내부의 메서드가 실행된다.- @Mock '가짜' 객체라면, 객체 내부의 메서드가 실행되지 않는다. @Mock과 @MockBean 차이@Mock은 Spring과 독립적으로, 단위 테스트에서 객체의 특정 메서드를 모킹할 때 사용!@MockBean은 Spring Boot 통합 테스트나 Spring의 의존성 주입이 필요한 상황에서 사용되며, Spring 컨텍스트에 Mock 객체를 주입하여 해당 객체를 사용!  @Spy: Mockito 스파이 객체를 테스트 클래스 내부에서만 사용하며, Spring 컨텍스트와는 무관합니다. 단위 테스트에서 사용됩니다.@SpyBean: Spring 애플리케이션 컨텍스트에 스파이 객체를 주입하여 Spring의 Bean과 상호작용할 수 있게 합니다. Spring 통합 테스트에서 사용됩니다. @InjectMocks@Mock 객체에 필요한 의존성을 주입해주는 역할을 수행한다. 2. 테스트 코드 문서화핵심은 중복 제거가 아닌, 도메인사용자, 게시물은 간접적이므로 setUp, 댓글은 직접적으로 given절@BeforeEach void setUp() { 1,2,3-1. 사용자 생성에 필요한 내용 준비 1,2,3-2. 사용자 생성 1,2,3-3. 게시물 생성에 필요한 내용 준비 1,2.3-4. 게시물 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }   

백엔드백엔드인프런워밍업클럽테스트코드스프링

sdsd988

Layered Architecture 구조의 테스트 작성 방법

인프런 워밍업 클럽 백엔드 2기 클린코드, 테스트 코드 참여 미션 수행 중 하나입니다!관련 강의 :Practical Testing: 실용적인 테스트 가이드( https://www.inflearn.com/course/practical-testing-%EC%8B%A4%EC%9A%A9%EC%A0%81%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9D%B4%EB%93%9C/dashboard)1. Layered Architecture ? 소프트웨어 개발 방법 중 하나로, 계층(Layer) 의 수에 따라 N-tier Architecture 부르기도 한다.계층은 어떻게 나누는 것인가? - 책임에 따라서 나눈다.강의에서는 3-tier Architecture 기준으로 나누었다. (Persistence, Business, Prsentation) 2. Layer(Persistence, Business, Prsentation) 1. Persistence Layer  책임 : 도메인(객체)의 생성과 검증 도메인의 생성과 관련된 책임을 가진 계층이다.애플리케이션에서 생성한 객체(Domain)이 데이터베이스에 올바르게 저장되는지 검증하는 과정이 필요하다. Persistent Layer 는 객체가 어떻게 저장되고, 어떤 파라미터를 필요로하는 지 이해할 수 있는 계층이다.테스트 코드 작성을 통해, Business 계층에서 사용될 객체들에 대해 이해를 가질 수 있는 계층이라 생각한다.뒤에 올 Business, Presentation 계층의 작성을 위한 기본적인 토대를 제공하는 계층이다.따라서, 이어질 계층에서 도메인에 대한 고민을 할 필요 없도록 테스트 코드를 작성해주는 것이 필요하다고 생각한다. 2. Business Layer 책임 : 도메인의 비지니스 로직 수행 객체의 생성과 검증이 완료된 토대에서, 서비스의 로직 을 수행하는 책임을 가진 계층이다.Persistent Layer에서 검증되고, 생성된 객체가 수행하는 책임을 검증하는 계층이라고 볼 수 있다.그렇기에, 코드의 양이 많고 테스트 코드 작성도 복잡해진다.Service(Business)은 Persistent(Repository) 의존한다. 즉 2개의 계층이 테스트에 필요해진다.중요하다고 생각하는 지점은, 이 계층은 비지니스 로직 에 집중해야 하는 계층이라는 점이다.객체의 생성과 관련된 코드는 감추고 , 로직과 관련된 코드는 표현되어야 한다.강의를 들으면서, 책임을 어떻게 분리할 것인가? 라는 의문이 생길 수 있다고 생각했다.비지니스 계층을 작성하면서, 도메인과 비지니스 그리고 로직과 로직 사이의 리팩토링이 많이 이루어 질 수 있다고 생각!  3. Presentation Layer책임 : 생성과 로직이 처리된 데이터의 출력 2 계층에서 생성되고, 처리된 데이터가 올바르게 생성되거나 프런트엔드에 올바르게 반환되는지 확인하는 책임을 가진 계층Business 계층에 의존한다. Business Layer 테스트에서 주의해야 할 점과 같이, Presentation Layer 검증에 집중해야 한다.하지만, Business Layer의 특징은 복잡하다는 것이 있었다. 대체(Mock)개념의 필요성Presentation Layer 계층의 테스트에 집중하기 위해 Mockito 를 활용하여, 가짜 객체를 생성하고 테스트에 도입한다.결국 데이터의 바인딩(Binding), 맵핑(Mapping) 에 집중해야 한다.API를 호출하면, 의도된 매개 변수를 받고 올바른 응답을 생성하는 과정을 검증할 수 있어야 한다.  

백엔드백엔드인프런워밍업클럽테스트스프링레이어드아키텍쳐

Rojojun

[워밍업 클럽 스터디 2기::백엔드] 3주차 발자국

1주일간의 학습 회고테스트코드의 강의를 완강하였다.이번 주 공부한 분량은 생각보다 많지는 않았다.중점적으로 관심있던 부분은 TestFixture와 RestDocs였다.TestFixture 강의 내에서 나온 TextFixture는 많은 내용이 없었지만, 실제로 프로젝트에서 이 강의를 보기전에 적용해 본 적이 있다.가장 도움이 되었던 내용은 토스의 기술 블로그였다. (하단 참조)https://toss.tech/article/how-to-manage-test-dependency-in-gradle예전에 프로젝트에서 적용하면서 느낀 장점과 단점에 대해 간단하게 기술해보면 다음과 같다.사실 적용법은 너무 많은 블로그에 나와 있기 때문에, 개인적인 장/단점을 공유하는게 옳다고 생각한다.장점Fixture관리가 편하다테스트 코드에서 Fixture를 파편화 시켜서 사용하지 않아도 된다.Gradle에서 지원한다단점Fixture도 관리 대상이 된다실제로 Entity나 DTO가 변경될 때 Fixture를 변경하지 않아서 빌드가 안되거나 하는 경우가 있었는데, 너무 번거롭다.모든 팀원들이 인지하지 않으면 꽤나 힘들다... (개인적인 생각이다)깊은 연관관계가 되어 있는 경우에는 결국 여러개의 Fixture와 Fixture 시나리오를 구성해야하기 때문에 꽤나 번거롭다.위와 같은 문제점을 해결하기 위해서, 고민을 덜기 위해 FixtureMonkey 라는 것도 고민을 해보았는데, 막상 생각보다 그렇게 와우 모먼트를 이끌만하지 않았기에 Fixture를 계속 사용하였다. RestDocs강사님이 이야기한것들 중에 정말 많은게 공감이 되었다.강사님은 RestDocs, Swagger 비교를 하셨지만 거기서 더 나아가서 PostMan과 같은 상용 API 문서화 툴까지 비교를 하자면, 회사 내 우리팀은 BFF 로서 백엔드 프론트가 나뉘어져 있다. 그렇기에 API 문서화가 중요한데 API 문서화 툴의 단점은 업데이트 주기가 사람한테 맞추어져있다는 점이다.그래서, Swagger를 도입하느냐 마느냐에 대한 이야기가 있었다. 개인적으로... Swagger를 반대하는 이유는 강의내용과 같다. Swagger가 프로덕션 코드에 침투하는게 너무 싫다!! 그러나... RestDocs를 사용하는 이야기는 하지 않았다... 왤까?이유는 다음과 같다. 아스키독스에 대한 학습이 싫다 -> 빠르게 도입을 해야할 때 발목을 잡을 수 있다TestCode에 대한 지식이 모든 팀원이 100%가 아니다 -> 사실 위 내용이 컸다....좋은 방안과 툴이여도 결국 회사의 상황과 역량에 따라 어쩔 수 없지만, 개인적인 프로젝트에서는 도입을 해볼 계획이다.해봐야 ㅋㅋ 이게 효율적인지 아닌지 알거 같다! 이번 주 학습에서 잘한 점사내에 개선점들이 있어서 개선에 도움을 주고자 간단한 프로젝트를 자체 개발하고 있었다...프로젝트를 하면서, 느리지만 개인적으로 한달정도를 예상하고 있어서 TDD를 통해서 그리고 읽기좋은 코드로 만들고 있다.향후 유지보수와 문서화를 위해서 내가 공부한 내용을 적용할 수 있게 했다. 아쉬웠던 점금요일에!! 깜짝 세션이 있었다... 참여를 못했다!!!같이 공부하는 팀원들과 함께 질문할것이 있었는데 ㅠㅠㅠ 하지를 못했다... 내 질문은 TDD의 영역이다...TDD의 영역이란 테스트 커버리지 퍼센트가 아닌 실용적인 이야기다...개인적으로 실용주의적인 개발자라 생각하여 나는 테스트코드가 100% 커버리지 혹은 90% 이상 커버리지를 좋다고 생각하지는 않는다.그래서 TDD의 영역에 대해 물어보려 했는데ㅠㅠ.... 회사 팀원들과의 협업TDD의 영역에 대해 같이 공부하고 있는 회사 동료들에게 물어봤다! 동료 중 한 명이 강사님에게 물어보라 했는데 ㅠㅠ 까먹었다... 또한 그 동료가! 물어본 것들 중 하나가... 인터페이스의 테스트 영역에 대해서 세명이서 토론하다가 이것도 물어보자! 해서 끝났다...좋은 동료와 좋은 스터디를 하고 이런 개념들을 발전해 나가서 너무 좋다!

백엔드테스트코드백엔드자바스프링

V_브이_v

[인프런 워밍업 클럽 스터디 2기]: JPA가 그래서 뭔데;;

인프런 스터디 2주차 발자국입니다.이번 주는 강의를 들으면서 진도를 수행하던 중에 PROJECT_SKILL 테이블이 h2 DB에서 조회되지않는 문제를 발견하고 왜 안되는지 찾아보았고 그과정에서 JPA: 영속성 콘텍스트 라는 녀석 때문에 테이블이 생성되지않았다는 점을 배웠습니다.그래서 이번주는 JPA와 영속성 콘텍스트에 대해서 혼자 자습을 조금 해보았는데,,,너무 혼자 시간을 허비한거 같습니다궁금한 내용들이 꼬리를 물고 계속 생겨서 🫤 차라리 쉽게 설명해주는 강의를 찾아서 배웠으면금방 지나갈 거 같은 개념에 시간을 많이 쓴거 같아 아쉬웠습니다.아무튼 아래는 이번주에 혼자 자습하면서 배워본 내용들을 정리한 것입니다.전부 다 외운건 아니고 어느정도? 얕게는 이해를 마쳤다고 생각합니다.혹시나 틀린 내용이 있다면 지적 부탁드립니다. 감사합니다.0. ORM이란 무엇인가ORM(Object-Relational Mapping)은 객체 지향 프로그래밍에서 데이터베이스와 상호작용하기 위한 기술로, 객체와 관계형 데이터베이스 간의 데이터를 매핑하여 변환하는 역할을 합니다. ORM은 데이터베이스의 테이블과 객체 지향 언어의 클래스를 연결해주어, 개발자가 SQL 쿼리 없이도 객체를 사용하여 데이터베이스 작업을 수행할 수 있게 합니다.ORM의 주요 개념객체 지향적인 접근: ORM을 사용하면 데이터베이스의 테이블을 객체로 다룰 수 있다.이는 데이터베이스의 행(row)을 객체의 인스턴스로 변환하고, 컬럼을 객체의 속성으로 변환하는 것을 의미한다.자동화된 매핑: ORM은 SQL 쿼리 생성과 데이터베이스와의 상호작용을 자동으로 처리하므로, 개발자가 비즈니스 로직에 집중할 수 있게 도와준다.대표적인 ORM 도구: Hibernate, JPA(Java Persistence API), MyBatis 등이 있다.   1. JPA란 무엇인가JPA(Java Persistence API)는 ORM 기술의 표준 인터페이스로, 자바 애플리케이션에서 데이터베이스와 상호작용하기 위한 명세를 제공한다. JPA는 직접적으로 ORM 기능을 제공하는 것이 아니라, ORM 기술을 위한 규칙과 표준을 정의하여, 다양한 구현체(Hibernate, EclipseLink 등)가 기능을 수행함.JPA의 정의 및 역할ORM 표준 인터페이스: JPA는 ORM 기술의 표준을 정의하여, 개발자가 특정 구현체에 의존하지 않고 일관된 방식으로 데이터를 처리할 수 있게 한다.구현체의 예시: JPA의 구현체로는 Hibernate, EclipseLink, OpenJPA 등이 있으며, 이들 구현체는 JPA의 인터페이스를 구현하여 실제 데이터베이스 작업을 수행한다.개발자들이 JPA를 사용하는 이유생산성 향상: JPA는 데이터베이스 작업을 객체 지향적으로 처리할 수 있게 함으로써, SQL 쿼리 작성의 부담을 줄이고 코드의 가독성을 높인다.유지보수 용이성: 엔티티 매핑을 통해 데이터베이스의 구조 변경에 따른 코드 변경을 최소화할 수 있다.데이터베이스 독립성: 특정 데이터베이스에 종속되지 않으며, 다양한 데이터베이스로 쉽게 이식할 수 있는 애플리케이션을 구축할 수 있다. JPA를 사용할 때 주의해야 할 사항성능 문제: 잘못된 엔티티 설계나 관계 매핑으로 인해 성능 문제가 발생할 수 있으므로, 캐시와 페치 전략을 적절히 사용해야 합니다.복잡한 설정: 영속성 컨텍스트, 트랜잭션 관리, Fetch 전략 등 복잡한 설정과 개념을 이해하지 않으면 예상치 못한 동작이 발생할 수 있습니다.자동 쿼리 생성 기능의 오해: Spring Data JPA에서 제공하는 기능과 JPA 자체의 기능을 혼동하지 않도록 주의해야 합니다. 2. JPA의 특징객체 지향적인 데이터베이스 접근: JPA는 데이터를 객체로 매핑하여 직접 조작할 수 있게 합니다. 이를 통해 SQL의 복잡한 문법 없이도 데이터를 처리할 수 있습니다.자동화된 데이터베이스 스키마 관리: JPA의 스키마 설정 옵션(create, update, validate 등)을 통해 데이터베이스 스키마를 자동으로 생성하거나 검증할 수 있습니다.1차 캐시: JPA 표준에서 지원하는 기능으로, 영속성 컨텍스트 내에서 관리되며 트랜잭션 범위 내에서 데이터를 캐시한다. 동일한 트랜잭션 내에서는 데이터베이스에 재접근하지 않고 메모리에 저장된 엔티티를 사용한다.2차 캐시: JPA 표준에는 포함되지 않고, JPA의 구현체(예: Hibernate)에서 지원하는 기능이다. 2차 캐시는 애플리케이션 범위에서 동작하며, 여러 영속성 컨텍스트 간에 데이터를 공유하여 성능을 최적화한다. 이를 사용하려면 Ehcache, Hazelcast, Infinispan 등과 같은 캐시 프로바이더를 통합해야 한다고 하는데 아직 무슨 말인지 잘 모르겠다...영속성 컨텍스트: 엔티티 매니저가 관리하는 영속성 컨텍스트는 엔티티의 상태를 추적하고, 동일한 트랜잭션 내에서 동일한 데이터를 캐싱하여 성능을 향상시킬 수 있다.Fetch 전략: 데이터 로딩 방식으로 즉시 로딩(EAGER)과 지연 로딩(LAZY)이 있으며, 성능과 자원 사용을 최적화할 수 있다.Cascading(영속성 전이): 부모 엔티티의 상태 변경이 자식 엔티티에도 자동으로 전이되도록 설정할 수 있다.영속성 콘텍스트에 대해서도 자습했는데 아직 내용이 정리되지않아서 다음번 블로그 글에서 작성해보도록 하겠습니다.  

스프링자바JPA

vin

[인프런 워밍업 클럽 BE 2기] 백엔드 프로젝트 - 2주차 발자국

1주차에는 간단한 엔티티와 프로젝트 구조 작성을 완료하고, 이번 주에는 리포지토리, DTO, 서비스 계층을 전반적으로 개발했으며, 그 과정에서 테스트 코드도 함께 작성했다. 이를 통해 프로젝트의 핵심 기능들을 구조화하고, 안정성을 높이는 데 중점을 두었다. 데이터를 다루는 리포지토리 개발하기리포지토리 개발을 하였으며 역시 1주차와 달리 혼동스러운 어노테이션 및 개념과 처음 접하는 어노테이션 및 개념들이 나왔었다. 하나하나 상세히 어떤 역할을 하는지 강의에서 알려주셔서 따라가는데 문제 없었으나, 중간에 오류가 한번 발생하여 찾아보니 JPA영속성 관련 부분이였다.Projectskill에 데이터가 들어가지 않아 확인을 해보니 project 엔티티에서 skill 부분에 cascade 부분을 빼먹어서 함께 저장이 되지 않았다.1. Spring Component와 Bean 등록Component Bean 등록:스프링에서는 @Component, @Controller, @Service, @Repository 어노테이션을 통해 클래스를 Bean으로 등록@Component: 기본적인 스프링 컴포넌트 등록 어노테이션.@Controller: 웹 컨트롤러 계층에 사용, 요청을 처리하는 클래스.@Service: 서비스 계층에 사용, 비즈니스 로직을 처리하는 클래스.@Repository: 데이터 접근 계층에 사용, 데이터베이스와 상호작용하는 클래스.이들은 모두 @Component를 상속한 어노테이션으로, 역할에 따라 더 구체적으로 분류@ComponentScan:스프링이 애플리케이션을 시작할 때, 이 어노테이션을 사용하여 해당 패키지나 하위 패키지에서 컴포넌트를 스캔하고, DI(의존성 주입)를 위해 Bean으로 등록2. 스프링 프로파일과 @Profile 어노테이션@Profile:스프링에서 다양한 환경 설정을 관리할 때, 특정 프로파일이 활성화된 경우에만 빈(Bean)을 활성화할 수 있도록 하는 어노테이션예를 들어, @Profile("dev")는 "dev" 프로파일이 활성화될 때만 해당 빈이 등록3. 생성자 주입과 Bean 관리생성자 주입 방식으로 의존성을 주입받아 사용하는 것이 권장. 생성자 내부에서 미리 정의된 Bean을 주입받아 사용하고, 이 과정에서 스프링이 의존성 관리를 담당.@PostConstruct:Bean이 스프링 컨테이너에 등록된 후 실행되는 메서드에 붙일 수 있는 어노테이션. Bean의 초기화를 마친 후 로직을 처리할 때 사용.4. 로그 사용 권장System.out.println()은 성능상 좋지 않으며, 멀티 쓰레드 환경에서 비효율적이기 때문에 로그 라이브러리를 사용하여 로그를 남기는 것이 좋다.5. JPA와 영속성 관리 (Cascade)Cascade: JPA에서 엔티티의 상태 변화에 따라 연관된 엔티티도 함께 변경되도록 하는 옵션.CascadeType.PERSIST: 엔티티를 저장할 때 연관된 엔티티도 함께 저장.CascadeType.MERGE: 엔티티를 병합할 때 연관된 엔티티도 함께 병합.CascadeType.REMOVE: 엔티티를 삭제할 때 연관된 엔티티도 함께 삭제.CascadeType.REFRESH: 엔티티를 새로고침할 때 연관된 엔티티도 함께 새로고침.CascadeType.DETACH: 엔티티가 영속성 컨텍스트에서 분리될 때 연관된 엔티티도 분리.CascadeType.ALL: 모든 작업(PERSIST, MERGE, REMOVE, REFRESH, DETACH)에 대해 적용.예를 들어, Project 클래스에서 ProjectSkill 엔티티와의 연관관계에 CascadeType.PERSIST를 설정하지 않으면, Project가 저장될 때 연관된 ProjectSkill이 함께 저장되지 않을 수 있다. 6. JPA 성능 개선 (findById 오버라이딩)JpaRepository의 findById 메서드를 오버라이드하여 성능을 최적화할 수 있습니다. 예를 들어, 특정 조건에 맞는 쿼리를 커스터마이징하여 데이터베이스 성능을 개선할 수 있습니다.이러한 요소들은 스프링 애플리케이션 개발에서 빈 관리, 의존성 주입, JPA를 통한 데이터베이스 영속성 관리를 포함한 다양한 개발 과정에서 중요한 역할을 합니다. 리포지토리 테스트 하고 성능 개선하기개발한 리포지토리가 제대로 작성 되는지 테스트코드를 작성하였으며, 또한 리포지토리의 성능을 개선하기 위해 JPQL을 따로 작성하여 fetch 전략으로 LAZY를 사용하여도 깔끔하게 출력되게 개선하였다.리포지토리 테스트 코드 작성@TestInstance.Lifecycle.PER_CLASS: 메서드 간 독립적인 실행이 가능하며, 메서드 간 의존성이 제거됨.의존성 주입: 테스트 시 필요한 리포지토리나 서비스 등을 주입받아 테스트를 진행. 테스트 데이터 초기화: @BeforeAll을 사용하여 테스트에 필요한 데이터를 사전 생성. 프록시 객체와 Fetch 전략프록시 객체: JPA에서 연관된 엔티티를 가짜 객체로 생성하여 필요할 때만 데이터베이스에서 불러옴.LAZY 로딩: 필요할 때마다 쿼리를 날려 데이터를 가져옴. 하지만, 반복문을 돌 때마다 SELECT 문이 나가 성능 저하가 발생할 수 있음.EAGER 로딩: 한 번에 모든 연관된 엔티티를 조회하지만, 불필요한 데이터를 미리 가져올 경우 성능에 영향을 미칠 수 있음.3. Fetch Join과 N+1 문제 해결Fetch Join: JPQL에서 사용하여 연관된 엔티티를 한 번의 쿼리로 모두 조회하는 방법.장점: 추가적인 쿼리가 발생하지 않아 성능 최적화가 가능.단점: 필요 없는 데이터를 미리 가져올 경우 메모리 낭비 가능.N+1 문제: Lazy 로딩 시 발생하는 성능 문제로, 하나의 엔티티를 조회할 때 연관된 엔티티를 각각 추가 쿼리로 조회하여 비효율이 발생. Fetch Join으로 이 문제를 해결 가능.  4.Assertions의 assertThatassertThat: 테스트 코드에서 검증을 위한 메서드로, 다양한 조건에 맞는 검증을 수행할 수 있음.isEqualTo(): 두 값이 같은지 비교.isTrue() / isFalse(): 조건이 참인지, 거짓인지 확인.hasSize(): 리스트나 배열의 크기를 검증.contains(): 리스트가 특정 값을 포함하는지 확인.데이터를 조회하고 변환하는 서비스 개발하기도메인 패키지와 연결된 presentation 패키지를 생성하였고, 해당 패키지 안에 클래스, DTO, 리포지토리, 서비스 개발을 완료하였다. 또한, 서비스에 대한 테스트 코드도 작성했다.이번에는 도메인에서 개발했던 리포지토리 테스트와 달리 단위 테스트가 아닌 방법으로 개발하였다. 기존까지 나는 개발 환경에서 페이지를 띄운 후 하나하나 수동으로 테스트를 진행했지만, 이러한 방식은 운영 서버에서 테스트하기 어렵다는 단점이 있었다.따라서 테스트 코드를 작성하여 자동화된 방식으로 테스트하는 것이 실무적으로 더 안정적이라고 한다.1. @RestController로 REST API 구현@RestController: 스프링에서 RESTful 웹 서비스를 만들 때 사용하는 어노테이션으로, 컨트롤러에서 반환하는 데이터를 자동으로 JSON 형식으로 변환해 클라이언트에 전달한다. 주로 API 응답에서 사용되며, HTML이 아닌 데이터를 반환한다.2. @GetMapping과 @RequestMapping@GetMapping: HTTP GET 요청을 처리하는 어노테이션으로, @RequestMapping(method = RequestMethod.GET)의 간편한 대체 방식이다. 이를 통해 서버는 클라이언트의 GET 요청에 대해 데이터를 조회하고 응답할 수 있다.3. DTO (Data Transfer Object)DTO: 데이터 전송 객체로, 서버와 클라이언트 간 데이터를 주고받기 위한 객체다. 비즈니스 로직을 포함하지 않고 데이터의 전송에만 집중되어 있으며, 데이터를 안전하고 일관되게 전달하는 데 사용된다.4. Mockito와 @InjectMocks로 의존성 주입Mockito: 단위 테스트에서 실제 객체 대신 Mock 객체를 사용하여 독립적인 테스트를 가능하게 해주는 테스트 라이브러리이다. 이를 통해 외부 의존성을 최소화한 테스트를 할 수 있다.@ExtendWith(MockitoExtension::class): JUnit5와 Mockito를 통합해, 테스트 환경에서 Mock 객체의 자동 주입을 제공하는 어노테이션이다. 테스트 클래스에서 의존성 주입을 자동으로 처리하며, 의존성을 가진 객체들을 쉽게 Mocking할 수 있다.@InjectMocks: Mock 객체를 주입받아 의존성을 가진 객체를 독립적으로 테스트할 수 있도록 하는 어노테이션이다. Mock 객체를 통해 실제 객체 없이도 테스트할 수 있어, 테스트의 독립성과 효율성을 높여준다.미션 3REST API 설계하기이번 미션에서는 설계한 테이블을 기반으로 REST API를 설계하는 작업을 진행했다. 상품 API, 분류 API, 브랜드 API, 재고 API를 설계했으며, 각 API의 기능을 세부적으로 구현하였다.분류와 브랜드 API에서는 삭제 대신 useYn 필드를 변경하여 비활성화하는 API를 설계했다. 즉, 데이터를 완전히 삭제하지 않고 비활성화 상태로 변경하는 방식이다.재고 API에서는 재고 삭제 API를 설계하지 않았고, 재고를 수정할 때 기존 데이터를 수정하는 대신 새로운 데이터를 생성하여 수정 이력을 로그처럼 남길 수 있도록 설계했다.또한, HTTP 메서드 중 PUT과 PATCH 메서드의 차이점에 대해 고민했는데, 두 메서드의 차이는 다음과 같다:PUT: 전체 리소스를 대체하거나 새로 생성하는 데 사용된다.PATCH: 리소스의 일부만 수정하는 데 사용되며, 부분적인 변경에 적합하다.https://github.com/Malvin222/mission-backoffice 

웹 개발백엔드웹개발워밍업클럽스프링나만의포트폴리오사이트만들기

vin 1개월 전
Rojojun

[워밍업 클럽 스터디 2기::백엔드] 2주차 발자국

1주일간의 학습 회고테스트코드의 강의를 듣기 시작하였다.80% 정도 듣게 되었고, 항상 회사에서 테스트 코드에 대한 필요성을 느끼며 팀원 몇 명과 함께 테스트 코드를 작성하고 있었는데, 팀원이 추천한 강의로 항상 이 강의의 개념에 대해서 적용하도록 도와주었다...그 때 보라할 때 볼걸 그랬다...ㅠㅠㅠ 코드 리뷰를 받다강의를 일찍 끝내서 숙제를 강사님에게 빨리 제출하였다.내가 잘해서 검사를 맡은게 아니라 코드가 형편 없어도 200명 앞에서 내 코드는 이래요~~!! 하는 자신감을 보여줘야한다고 생각해서, 코드 리뷰를 신청했다. 일단, 결론은 더 잘하기 위한 동기부여가 되었다.  동기부여가 왜 되었을까?일단 나의 지적사항은 두 가지 그리고 질문도 두 가지였다. 첫번째, 내가 잘해서 지적이 두 가지라고 생각하지 않는다.두번째, 나는 못하니깐 많은 사람들 앞에서 까이고 싶다. 그래야만 더 잘하려고 노력하기 때문이다.세번째, 질문... 내가 고민하는 것들은 많은 사람들이 고민하는 거라는 것을 느꼈다. 첫번째 지적 사항public enum StudyCafePassType { ... public static StudyCafePassType sendTypeBy(String userInput) { try { int inputCode = Integer.parseInt(userInput); return Arrays.stream(values()) .filter(type -> type.inputCode == inputCode) .findFirst() .orElseThrow(() -> new AppException("잘못된 입력입니다.")); } catch (NumberFormatException e) { throw new AppException("입력값은 숫자가 되어야합니다."); } } }이러한 코드를 enum에서 작성하였다.일단, 작성하면서도 코드 스멜을 느꼈다.'비즈니스 로직에 대해서 Enum이 너무 깊게 연관하는게 아닐까?'위의 고민을 가지면서, 만들었는데 아니나 다를까 강사님은 역할과 책임을 이야기 하면서 이 부분의 코드를 지적하였다. 참고로 ㅋㅋ 같이 워밍업 클럽 참여하는 동료도 회사내 클린코드 적용하면서 이런식으로 적용했는데... 그 날 당일에 나는 저 코드는 문제 있는거 같다고 계속해서 지적했다! 두번째 지적 사항은... 그냥 실수다... static 남발인데... 이게 가끔씩 ㅋㅋ 귀찮아서 static 쓰는 경우가 있는데... 이 부분은 진짜 화끈거렸다... 이번 주 학습에서 잘한 점이번 주 학습에서 내가 스스로 잘했다고 생각한 부분은 숙제를 하면서 나 스스로 생각을 많이 했다는 것이다.물론, 코드에서 좋은 것들을 가져와서 쓸 수 있지만, 내가 하는거고 나의 공부기 때문에 강사님의 코드 스타일 포맷을 그대로 따라가지 않으려고 노력했었다. 아쉬웠던 점: 리뷰를 하자성격이라 그런가... 숙제나 그런거를 낼 때는 그냥 리뷰를 안한다...그러다가 이번처럼 참 ㅋㅋ 어이없는 실수를 해서 지적할 받을 때가 있다... 이것을 그냥 '아, 이건 실수~' 하고 무시하는게 아니라 이게 실력이다 ㅠㅠ...  회사 팀원들과의 협업팀 동료 중 한 분이 이번에 인프런 워밍업 클럽을 들으면서 클린코드를 적용하였다.정말, 너무 좋았고 같이 듣는 동료와 함께 세명이서 그 코드에 대해서 토론하고 좋은 방향 등에 대해서 이야기를 하였다.배움이, 단지 배움이 아니라 실제적으로 적용되서 살아있는 공부가 되었다.앞으로도 이러한 스터디를 하고 이러한 문화를 팀동료들과 계속해서 이뤄가고 싶다.그러려면 더 잘해야겠지 ㅠㅠ...

백엔드백엔드클린코드자바스프링

vin

[인프런 워밍업 클럽 BE 2기] 백엔드 프로젝트 - 1주차 발자국

새로운 프로젝트 아이디어를 찾다가 인프런에서 위밍업클럽 2기를 시작한다는 소식을 듣고 신청하게 됐다. 강의 목록 중 특히 끌리는 강의가 있었고, 코틀린을 사용하는 점도 마음에 들었다. 그동안 코틀린을 접해본 적이 없어서 배우고 싶은 마음도 컸고, 새로운 기술들을 익히면서 동시에 다양한 사람들과 네트워킹을 할 수 있다는 부분이 마음에 들었다. 프로젝트 미리보기 + 웹 개발 기본 개념이번 강의에서는 웹 프레임워크, HTTP, 그리고 REST API와 같은 웹 개발의 기본 개념을 간략하게 학습했다.강의 시간이 짧아서 깊이 있는 설명은 없었지만, 웹 개발에서 필수적인 기초 개념을 알기 쉽게 설명해주었다. 덕분에 그동안 혼란스러웠던 부분들이 정리되었고, 전체적인 웹 개발의 기본 흐름을 이해할 수 있었다. 프로젝트 시작하기 + 데이터베이스 기본 개념데이터베이스와 JPA에 대해 이론적으로 학습하고, 실습으로 테이블 설계와 개발 환경을 구성하여 프로젝트를 시작했다.이전에는 주로 마이바티스(MyBatis)를 사용해 DB와 연결했지만, JPA에 대해서는 개념만 알고 있었다. 이번 강의를 통해 JPA의 기본 개념과 동작 방식을 명확히 이해하게 되었고, Spring Initializr 사이트를 통해 강의에서 사용할 개발 환경을 설정하고 프로젝트를 생성했다. 프로젝트 기초 설정하기코드 형상 관리를 위해 git과 GitHub를 사용하는 방법을 학습했다.또한, 생성된 프로젝트를 GitHub에 연결하고, 기본적인 상수 클래스, 리포지토리 클래스, 엔티티 클래스를 생성하였다.불필요한 파일들이 추적되지 않도록 .gitignore 파일을 설정하였고, 이 작업은 gitignore.io에서 현재 개발 환경에 맞는 설정을 자동으로 생성하여 적용했다.추가로, application.properties 설정 파일을 application-default.yml과 application-docker.yml로 나누어 개발 서버와 운영 서버에서 각각 다른 환경 설정을 적용하였다. H2와 MySQL 중 하나를 선택하여 각 서버에 맞게 설정했다. 프로젝트의 뼈대 엔티티 개발하기설계한 테이블을 바탕으로 엔티티(Entity)를 개발했다. 기본적으로 BaseEntity와 프로젝트에 필요한 여러 엔티티를 작성하였다.JPA와 코틀린을 처음 접해 생소한 부분도 있었지만, 자바에 대한 기본 지식 덕분에 비교적 빠르게 적응할 수 있었다. 연관관계가 있는 엔티티와 없는 엔티티를 나누어 개발하면서 새로운 어노테이션도 많이 사용했는데, 강의에서 해당 어노테이션에 대한 설명이 명확해서 어려움 없이 따라갈 수 있었다. 미션 1 + 21:N테이블 설계하기, 깃허브 리포지토리 만들기1주차에서 배운 내용을 바탕으로 서브 프로젝트의 GitHub 리포지토리를 만들고 테이블을 설계하는 미션을 수행했다.GitHub 리포지토리 생성은 문제없이 따라갔으나, 테이블 설계에서는 과연 내가 올바르게 하고 있는지 의구심이 들었다.적은 수의 테이블을 설계하는 것조차 여러 요인을 고려해야 했고, 설계한 테이블들이 적합한지 확신이 서지 않았다.우선 테이블을 설계하고, 프로젝트를 진행하면서 고려하지 못했던 부분이나 잘못 설계된 부분은 수정해나가기로 생각하였고, 이 과정에서 배운 점들을 기록하며 앞으로 개선해나갈 예정이다.https://github.com/Malvin222/mission-backoffice 

웹 개발백엔드웹개발워밍업클럽스프링

vin 1개월 전
구르밍

인프런 워밍업 클럽 BE 1기 - 3주차 발자국

조금 더 객체지향적으로 개발할 수 없을까?이전에는 User를 따로 가져와 BookService에서 UserLoanHistory를 만들어 저장하였다.조금 더 객체지향적으로 바꾸면 UserLoanHistory를 User에서 가져와 바로 대출을 처리하자!@ManyToOne : 내가 다수이고 너가 한개대출기록은 여러개이고 그 대출을 소유하고 있는 사용자는 한명이다 → N : 1 관계//private long userId; @ManyToOne private User user;@OneToMany : 나는 한개 너가 다수@OneToMany privateList<UserLoanHistory> userLoanHistoryList = new ArrayList<>();여러개의 대출기록 N개이기 때문에 List로 표현이로써 User와 UserLoanHistory는 서로 연관관계가 되었다. 그 중에 주인은 누구인가?누가 관계의 주도권을 가지고 있는가?현재는 user_loan_history가 user_id를 DB 컬럼으로 가지고 있기 때문에 주인이다.연관관계의 주인이 아닌 쪽에 mappedBy 옵션을 달아 주어야 한다.@OneToMany(mappedBy = "user") privateList<UserLoanHistory> userLoanHistoryList = new ArrayList<>(); 1:1 관계한 사람은 한 개의 실거주 주소 만을 가지고 있다.person 테이블이 address 테이블의 id를 가질 수도 있고, address테이블이 person 테이블의 id를 가질 수도 있다.@Entity public class Person{ ... @OneToOne private Address address; }@Entity public class Address{ ... @OneToOne private Person person; }이렇게 테이블을 생성한다고 가정할때 Person이 address id를 가지고 있다.create table person ( id bigint auto_increment, name varchar(255), address_id bigint, primary key (id) );create table address ( id bigint auto_increment, city varchar(255), street varchar(255), primary key (id) );→ Person이 address 주인이다! 1:1 관계지만..따라서 mappedBy 작성@Entity public class Address{ ... @OneToOne(mappedBy = "address") private Person person; }연관관계의 주인 효과 → 객체가 연결되는 기준이 된다.!@Transactional public void savePerson() { Person person = personRepository.save(new Person()); Address address = addressRepository.save(new Address()); person.setAddress(address); // setter는 임시 }person이 address의 주인이기때문에 이렇게 코드를 작성하고 실행하면 DB에서 정상으로 테이블이 연결된다. 하지만 반대로 1:1관계이더라도 address.setPerson(person);  이렇게 작성할 경우 DB에 저장되지 않는다. DB는 연결되었지만 !!! 객체끼리는 연결되지 않았다. address.getPerson(); --> 트랜잭션이 끝나기전에 get하면 Null 반환@Transactional public void savePerson() { Person person = personRepository.save(new Person()); Address address = addressRepository.save(new Address()); person.setAddress(address); // setter는 임시 address.getPerson(); --> 트랜잭션이 끝나기전에 get하면 Null 반환 }해결책으로 setter 한번에 둘을 같이 이어주면 된다.public void setAddress(Address address) { this.address = address; this.address.setPerson(this); --> 둘을 같이 이어주자 }N : 1 관계이 관계에서 주인은 무조건 숫자가 많은쪽이 주인이다.  @OneToMany를 작성하지 않고, @ManyToOne 하나만 작성해도 된다.(단방향)  @JoinColumn연관관계의 주인이 활용할 수 있는 어노테이션.필드의 이름이나 null 여부, 유일성 여부, 업데이트 여부 등을 지정@JoinColumn(nullable = false) @ManyToOne private User user; N : M 관계 - @ManyToMany학생과 동아리 관계를 생각하자학생은 여러 동아리를 가입할 수 있고, 한 동아리엔 여러 학생이 있다.→ But, 구조가 복잡하고, 테이블이 직관적으로 매핑되지 않아 사용하지 않는 것을 추천cascade 옵션 cascade : 폭포처럼 흐르다.  : 한 객체가 저장되거나 삭제될 때, 그 변경이 폭포처럼 플러 연결되어 있는 객체도 함께 저장되거나 삭제되는 기능유저가 삭제될때 유저가 연결되어 있는 UserLoanHistory도 삭제하고 싶을때 사용하면 된다.@OneToMany(mappedBy = "user", cascade = CascadeType.ALL) privateList<UserLoanHistory> userLoanHistoryList = new ArrayList<>(); orphanRemoval 옵션: 객체간의 관계가 끊어진 데이터를 자동으로 제거하는 옵션관계가 끊어진 데이터 = orphan(고아) removal (제거)한 유저가 빌린 책1, 책2가 있다고 가정할 때, userLoanHistory에서 책1만 리스트(자바단)에서 지웠다. → DB는 아무런 변화가 없다. 이렇게 리스트에서 지우는(연결을 끊는 것 만으로도) 것으로도 DB에서 삭제가 되길바라면 이 옵션을 쓸 수 있다.@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) privateList<UserLoanHistory> userLoanHistoryList = new ArrayList<>(); @Transactional public void deleteUserHistory() { User user = userRepository.findByName("ABC") .orElseThrow(IllegalArgumentException::new); user.removeOneHistory(); } public void removeOneHistory() { userLoanHistories.removeIf(history -> "책1".equals(history.getBookName())); }  책 대출/반납 기능 리팩토링과 지연로딩User와 UserLoanHistory가 직접적으로 연결되어 있다.대출기능 리팩토링public void loanBook(String bookName) { this.userLoanHistories.add(new UserLoanHistory(this, bookName)); } User.java에서 새로운 UserLoanHistory객체를 만들고 넣어주기 때문에 service단에서는 loanBook메소드를 호출해주기만 하면 된다.@Transactional public void loanBook(BookLoanRequest request) throws IllegalAccessException { Book book = bookRespository.findByName(request.getBookName()) .orElseThrow(IllegalAccessException::new); if (userLoanHistoryRepository.existsByBookNameAndIsReturn(book.getName(), false)) { throw new IllegalAccessException("이미 대출중인 책입니다."); } User user = userRepository.findByName(request.getUserName()); if(user == null) { throw new IllegalAccessException("사용자를 찾을 수 없습니다."); } //userLoanHistoryRepository.save(new UserLoanHistory(user, book.getName())); user.loanBook(book.getName()); }반납기능 리팩토링public void returnBook(String bookName) throws IllegalAccessException { UserLoanHistory targetHistory = this.userLoanHistories.stream() .filter(history -> history.getBookName().equals(bookName)) .findFirst() .orElseThrow(IllegalAccessException::new); targetHistory.doReturn(); }함수형 프로그래밍을 할 수 있게 .stream을 작성해주고.filter를 통해 들어오는 객체들 중에 다음 조건을 충족하는 것만 필터링 한다  ..findFirst()를 통해 첫번째로 해당하는 UserLoanHistory를 찾는다.  이 결과는 Optional이기에 Optional을 제거하기 위해 없으면 예외를 던진다.  orElseThrow그렇게 찾은 UserLoanHistory를 반납처리 한다.@Transactional public void returnBook(BookReturnRequest request) throws IllegalAccessException { User user = userRepository.findByName(request.getUserName()); if(user == null) { throw new IllegalAccessException("사용자를 찾을 수 없습니다."); } // UserLoanHistory history = userLoanHistoryRepository.findByUserIdAndBookName(user.getId(), request.getBookName()) // .orElseThrow(IllegalAccessException::new); // history.doReturn(); user.returnBook(request.getBookName()); }userLoanHistoryRepository.findByUserIdAndBookName()은 사용할 일이 없어져서 삭제해었다.→ Domain 계층에 비즈니스 로직이 들어갔다.영속성 컨텍스트의 4번째 능력 - 지연 로딩 (Lazy Loading)예시 - User를 가져오는 부분과, 도메인 로직 실행 중간에 Print 출력을 해보자@Transactional public void returnBook(BookReturnRequest request) throws IllegalAccessException { User user = userRepository.findByName(request.getUserName()); if(user == null) { throw new IllegalAccessException("사용자를 찾을 수 없습니다."); } Systme.out.println("Hello"); user.returnBook(request.getBookName()); }실행결과를 확인하면 user를 가져오는 쿼리, hello 출력 후 userLoanHistory 쿼리를 출력하는 것을 확인할 수 있다. → 시작하자마다 유저와 대출기록을 다 가져올 수 있지만 그러지 않고, 꼭 필요한 순간에 데이터를 가져온다.  이러한 것을 지연 로딩이라 한다.  @OneToMany에 fetch 옵션에 기본 디폴트 값이다 LAZY만약 한번에 가지고 오고 싶다면 LAZY → EAGER를 사용하면 된다.@OneToMany(mappedBy = “user”, cascade = CadcadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)연관관계를 사용하면 무엇이 좋을까?각자의 역할에 집중하게 된다. 계층별로 응집성이 높아진다.새로운 개발자가 코드를 읽을 때 이해하기 쉬워진다. (모두 다 service단에 있다면 ?)테스트 코드 작성이 쉬워진다.연관관계를 사용하는 것이 항상 좋을까?지나치게 사용하면 성능상 문제가 생길 수 있고, 도메인 간의 복잡한 연결로 인해 시스템을 파악하기 어려워질 수 있다.너무 얽혀 있으면 A를 수정했을 때 , B ~ D까지 고쳐야할 수 있다.→ 여러부분을 생각해서 구조를 짜자!배포란 무엇인가현재 우리 컴퓨터에서만 작동할 수 있는 환경..배포란 : 최종 사용자에게 SW를 전달하는 과정 → 전용 컴퓨터에 우리의 서버를 옮겨 실행시키는 것전용 컴퓨터가 없는데..? → AWS를 빌리자!!AWS에서 컴퓨터를 빌릴 때 한 가지 알아두어야 할점!서버용 컴퓨터는 보통 리눅스를 사용한다.profile과 H2 DB똑같은 서버 코드를 실행시키지만, 우리 컴퓨터에서 실행할 때는 우리 컴퓨터의 MySQL을 사용하고,전용 컴퓨터에서 실행할 때는 전용 컴퓨터의 MySQL을 사용하고 싶다→ profile 개념 똑같은 서버 코드를 실행시키지만, 실행될 때 설정을 다르게 하고 싶을 때(DB 이외에도 다른 API, 다른 기능 등 ..)Profile을 적용해보자똑같은 서버 코드를 실행시키지만, local이라는 Profile을 입력하면, H2 DB를 사용하고 dev라는 profile을 입력하면 MySQL DB를 사용하게 바꾸자  H2 DB란 : 경량 Database로, 개발 단계에서 많이 사용하며 디스크가 아닌 메모리에 데이터를 저장할 수 있다.  메모리에 데이터를 저장하면 휘발되지만, 개발 단계에서 테이블이 계속 변경 되기 때문에 데이터가 휘발해야하고 ddl-auto 옵션을 create로 주면 테이블을 신경쓰지 않고 코드에만 집중할 수 있다.profile 설정나는 인텔리제이 유료버전이라 강사님 처럼 active profile 부분이 안뜨기 때문에 다른방법으로 진행하였다.-Dspring.profiles.active=locallocal 또는 dev로 입력해주면 된다. AWS의 EC2 사용하기AWS 가입 후 지역을 서울로 변경EC2인스턴스 - 내가 빌린 컴퓨터 (현재 0)인스턴스 시작 버튼 클릭인스턴스 유형은 컴퓨터의 사양t2.micro 선택 !회고벌써 워밍업도 마지막을 향해 달려가는 중이다!!7번째 과제에서 아직 나는 JPA에 익숙하지않아서 뭔가 직접 쿼리를 쓰는게 더 편했던 것 같다. @Query를 통해 직접 작성해주었다가 어? 이렇게하면 JPA에서 알아서 해주는구나 하고 여러번 바꾸기도 했다!근데 만약 쿼리에 조건이 너무 많을 경우에는 이름이 너무 길어지지 않을까라는 생각도 했었다 ㅎ..중간에 자꾸 테이블에 해당 컬럼이 없다고 오류가 나길래 .. 그럴리가 없는데라고 생각했지만 그럴리 있었다. 역시 컴퓨터는 거짓말을 하지 않는다 하하확실히 강의만 보는 것보다 직접 내가 생각하고 타이핑하는 것이 내가 어느정도까지 실제적으로 이해했는지 확인할 수 있는 길인 것 같다.앞으로 남은 마지막 미니 프로젝트까지 잘 마무리하면서 개념 부분을 더 공부해보자!

백엔드워밍업백엔드스프링

최강현

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

Day 7. 스프링 컨테이너의 의미와 사용 방법 이 날 강의를 통해서 드디어 베일에 쌓인 의존성을 공부하는 기회가 되었다.의존성이란다음 코드를 보면 UserController의 생성자는 JdbcTemplate이라는 클래스를 필요로 하고 있다. @RestController public class UserController { private final UserService userService; public UserController(JdbcTemplate jdbcTemplate) { this.userService = new UserService(jdbcTemplate); } }이것을 어려운 말로 '의존한다'라고 한다. 스프링 빈이란스프링부트 서버를 시작할 때 자동으로 해주는 것 중 하나가 거대한 컨테이너(실제 컨테이너를 떠올리면 된다)를 만드는 것이다.이 컨테이너 안에는 클래스가 들어가게 되는데 이렇게 들어간 클래스를 스프링 빈이라고 부른다.클래스가 들어갈 때는 이 빈을 식별 할 수 있는 이름 및 타입과 다양한 정보가 들어가고 인스턴스화도 이루어진다. Day8. Spring Data JPA를 사용한 데이터베이스 조작 8일차 강의를 통해 SQL을 통해서 접근했던 DB를 자바 객체를 DB와 매핑 시켜서 사용하는 JPA를 학습하였다. JPA란객체와 관계형 데이터베이스의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙JPA는 API이기 때문에 말 그대로 규칙이고 (자바의 인터페이스와 같다) 이 규칙을 누군가는 실제로 구현을 해야한다그 구현체가 바로 Hibernate이다. Day9. 트랜잭션과 영속성 컨텍스트 9일차 강의는 서비스 계층의 남은 중요한 역할인 트랜잭션에 대해 배웠다.트랜잭션이란 쪼갤 수 없는 업무의 최소단위이다.실제로 예를 들면 인터넷 결제를 진행할 때 1. 주문 기록을 저장하고 2. 포인트를 적립해주고 3. 구매 기록을 저장해준다이 3가지의 과정을 쪼갤 수 없는 하나의 최소단위로 묶고 하나가 실패하면 다른 모든 과정도 실패해버리게 만드는게 트랜잭션이다. Start transaction -> 성공하면 COMMIT -> 실패하면 ROLLBACK 또한 영속성 컨텍스트에 관해서도 학습했는데 조금 어려워서 꼭 기억해야하는것스프링에서는 트랜잭션을 사용하면 영속성 컨택스트가 생기고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다. 영속성 컨텍스트의 특별한 능력변경 감지 : 영속성 컨텍스트 안에서 불러와진 Entity는 명시적으로 save를 해주지 않더라도 알아서 변경을 감지하여 저장할 수 있게 해준다.쓰기 지연 : 영속성 컨텍스트에 의해 트랜잭션이 Commit 되는 시점에 SQL을 모아서 한 번만 날리게 된다.1차 캐싱 : ID를 기준으로 Entity를 기억하는 기능이다. 조금 더 복잡한 기능을 API로 구성하기 10일차는 앞서 배운 것들로 JPA를 이용해서 책 생성, 대출, 반납 API를 개발해보았다. 과제 과제 4일차https://devnter.tistory.com/entry/%EC%9D%B8%ED%94%84%EB%9F%B0-%EC%9B%8C%EB%B0%8D%EC%97%85-%ED%81%B4%EB%9F%BD-1%EA%B8%B0BE-4%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9CqueryForObject() 에 대한 학습이 필요. 과제 5일차https://devnter.tistory.com/entry/%EC%9D%B8%ED%94%84%EB%9F%B0-%EC%9B%8C%EB%B0%8D%EC%97%85-%ED%81%B4%EB%9F%BD-1%EA%B8%B0BE-5%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C주어진 코드를 클린코드로 리팩토링하는 과제를 수행하였다.클래스를 나누기에는 너무 작은 기능이라 생각해서 읽기 좋은 코드로만 수정한다는 생각으로 수정했는데나중에 금요일에 코치님이 따로 열어주신 특강에서 테스트를 하기 위해 역할 별로 클래스를 쪼개고 테스트를 하는 강의를 진행 해 주셔서 새로운 내용에 대해 학습하는 기회가 되었다리팩토링 전에는 테스트를 작성하자! (Junit5, assertj)given / when / then 패턴전략 패턴 (= NumberGenerator의 인터페이스화 + 구현체 갈아끼우기)일급컬렉션MVC 패턴출처 https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%84%9C%EB%B2%84%EA%B0%9C%EB%B0%9C-%EC%98%AC%EC%9D%B8%EC%9B%90# 아쉬운점좀 더 추가적인 학습(모르는것에 대한 학습)을 하려고 했는데 나태해져서 진행하지 못했다. 다음 마지막 주차는 좀 더 내가 모르는 내용에 대해 민감하게 반응해서 학습 하거나 학습 하지 못한다면 따로 블로그나 노션에 기록해서 추후 공부할 수 있도록 하겠다. 

백엔드인프런워밍업클럽자바스프링javaspring

채널톡 아이콘