본문 바로가기
Archives/인프런 워밍업 클럽 스터디 BE 1기

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

by 잇택잇 2024. 5. 12.

들어가기 전에

2주차를 마무리하였다.

 

나름대로 1주차를 충실히 보낸건지,

2주차는 조금 더 수월하게 따라갈 수 있었다.

 

2주차에는 아래의 내용을 학습했다.

  • 스프링 컨테이너
  • 스프링 빈
  • Spring Data JPA
  • 트랜잭션

1주차의 내용에 깊이를 더했고,

조금 더 프레임워크스러운 내용을 배웠다.

 

Day 06 : 스프링 컨테이너의 의미와 사용 방법

여섯째 날,

드디어 스프링의 동작 원리에 대해 기본적인 내용을 학습할 수 있었다.

 

코드를 프로그래머가 직접 제어하는 라이브러리와 달리

프레임워크는 프로그래머의 코드가 사용되는 입장이다보니,

그 안에서 돌아가는 방식이 정말 궁금했다.

 

Spring Container

스프링 컨테이너는 스프링 프레임워크의 핵심 중 하나로 다음의 역할을 수행한다.

  1. 스프링 빈 관리
  2. 의존성 주입
  3. AOP
  4. 트랜잭션 관리

DI, IoC

DI(Dependency Injection)은 '의존성 주입'으로,

의존성이 발생하는 클래스에 대해 스프링 빈으로 등록되어있는 경우 스프링에 의해 자동 주입된다.

 

IoC(Inversion Of Control)은 '제어 역전'으로,

사용되는 대상을 프로그래머가 아닌 프레임워크가 결정하는 개념이다.

Spring Bean

스프링 컨테이너에 의해 생성되고 관리되는 객체를 의미한다.

 

Spring Bean 등록 방법

스프링 빈으로 등록하기 위해서는 아래의 방법 중 하나를 선택한다.

 

@RestController, @Service, @Repository

이전까지 사용하던 방법으로 사용자가 정의한 클래스에 직접 붙여 스프링 빈으로 등록한다.

 

@Configuration, @Bean

@Configuration과 @Bean은 세트다.

 

주로 외부 라이브러리, 프레임워크에서 사용하는 방법이다.

 

@Component

스프링 빈이 되기 위해서는 반.드.시. 가져야하는 어노테이션

특정 클래스를 컴포넌트(스프링 빈)로 취급하기 위한 어노테이션으로,

컴포넌트는 스프링 컨테이너의 감지 대상이 된다.

 

@RestController, @Service, @Repository, @Configuration 모두 내부적으로

@Component를 가지고 있다.

 

컨트롤러, 서비스, 레포지토리 이외의 클래스를 추가적으로 스프링 빈으로 등록하기 위해 사용하는 방법이다.

 

Spring Bean 주입 방법

스프링 빈에 대한 의존성을 갖는 경우,

스프링 컨테이너에 의해 자동으로 DI된다.

 

DI를 처리하기 위해서는 다음과 같은 방법 중 하나를 선택할 수 있다.

 

생성자를 이용한 주입 (권장)

근본

가장 권장되는 방법으로,

특정 스프링 빈을 필드로 갖게 하고 생성자를 작성한다.

 

참고로 스프링 3이전에는 생성자 위에 @Autowired를 명시해야 했다.

 

setter + @Autowried를 이용한 주입

벌써 불편

@Autowired는 스프링 빈을 찾아 연결해야 함을 전달한다.

 

setter를 이용하는 경우,

누군가가 setter를 사용할 수 있어 나도 모르는 사이에 문제가 발생할 수 있는 코드다.

 

필드에 @Autowired를 이용한 주입

작성하기 편해도 나중에 ㅅ

필드에 직접 주입하는 방법으로

테스트가 어려워져 권장하지 않는다.

 

@Qualifier

@Qualifier(Spring Bean 이름)

스프링 빈을 매핑하여 사용해야하는 경우 사용하는 어노테이션

정상적인 IoC를 위해 사용된다.

 

과제 리뷰

첫번째는,

지난 과제에 대해 Layered Architecture에 맞게 리팩토링하는 과제였다.

 

Layerd Architecture로 구조를 잡으니,

확실히 코드의 역할이 분명해졌고 유연하게 확장할 수 있게됐다.

 

두번째는,

하나의 인터페이스를 구현하고 있는 여러개의 레포지토리 클래스 중 특정 레포지토리를 사용하기 위한 방법을 묻는 과제였다.

 

오늘 배운 @Qualifire로 매핑할 수도 있고,

@Primary로 지정할 수도 있다.

 

짧은 회고

조금씩 로우레벨로 들어가다보니 확실히 재밌다.

그동안 궁금했던 내용에 대해 조금씩 알게 되니 속이 다 시원!

 

그러나 알아야 할 것들이 너무나 많다는 사실이 조금 섭섭하다.

 

아직 스프링 빈도 몇 개 안되고,

각 레이어에서도 클래스가 한 개 씩 있다보니 아키텍쳐 관점에서의 힘을 충분하게 체감하지 못한 것 같다.

 

Day 07 : Spring Data JPA를 이용한 DB 조작

이전까지는 레포지토리 스프링 빈으로 DB와 통신했다.

직접 SQL문을 작성했다.

 

과연 이것이 좋은 코드일까?

 

Java는 객체지향 언어로 절차지향의 코드에서 벗어나야한다.

그러나 SQL문을 그대로 작성하는 것 역시 절차지향 관점에 더 가깝다고 볼 수 있다.

 

직접 SQL을 사용할 때 단점

  1. 쿼리를 문자열로 작성하게 되어 런타임에서만 오류를 알 수 있음
  2. 특정 DBMS에 종속적인 코드를 짜게 됨
  3. DB의 Table과 코드의 Object는 서로 다른 패러다임으로 이루어져 있어 객체지향 활용이 어려움

 

JPA (Java Persistence API)

Java 진영의 ORM(Object-Relational Mapping)으로 Hibernate를 구현체로 한다.

 

참고로,

Hibernate의 내부는 JDBC로 동작한다.

 

Spring Data JPA는 복잡한 JPA를 한번 더 Wrapping한 라이브러리다.

 

Entity

DB의 User table
User Entity

JPA의 객체로 간주되는 클래스를 일컫는다.

DB Table과 완벽 호환되어 사용된다.

 

Spring Data JPA를 이용한 쿼리 날리기

JPA를 도입한 이유는,

코드 레벨에서 DB와 스프링을 객체지향 관점으로 작성하기 위함이다.

 

JPA를 통해 더이상 SQL문을 직접 작성하지 않고도,

동일한 기능을 수행할 수 있게 된다.

 

JpaRepository를 상속하는 Repository 생성

@Repository를 붙이지 않아도 스프링 빈으로 등록되는 마법

해당 레포지토리 인터페이스는 스프링에 의해 빈으로 등록되어 객체화된다.

프로그래머는 추상화된 인터페이스를 갖고 활용만하면 된다.

아아... Spring Data JPA 너란 녀석은...(1)

기본적으로 다양한 SQL문에 대응하는 여러 연산을 지원한다.

 

아아... Spring Data JPA 너란 녀석은...(2)

필요에 따라 인터페이스 안에 추상메서드로 선언하는 것으로 기능을 구현할 수 있다.

 

과제 리뷰

역시 바로 이전 과제의 연장선이다.

 

MySQL로 직접 연결하여 사용한 코드를

JPA로 리팩토링하는 문제였다.

 

사실 SQL에도 자신이 있어 크게 불편하지는 않았지만

JPA가 손에 익으면 더 편해질 것 같았다.

 

특히 레포지토리 인터페이스에 새로운 메서드를 작성하는 것으로 손쉽게 SQL문을 그대로 구현할 수 있었다.

조금 더 객체지향 코드에 가까워졌다.

 

그러나,

과연 JPA로 복잡한 SQL문까지 완벽히 대체하는걸까? 라는 의문이 들기도 했다.

 

나중에 알게 되겠지.

 

짧은 회고

처음엔 분명 겁을 먹었다.

 

JPA...?

ORM...?

Hibernate...?

 

익숙하지 않아서,

들어본 적 없어서 지레 겁을 먹고 배우기를 미뤘던 내용들이었다.

 

결국에는 일맥상통하는 개념이었다.

 

아마도,

새로운 것을 배워나감에 있어 이런 기분은 계속 이어질 것 같다.

 

무엇을 배우더라도

열린 마음으로 적극적으로 배워나가다보면,

결국 익숙해지고

다 알게 되는 것 같다.

 

 

 

Day 08 : 트랜잭션과 영속성 컨텍스트

SQLD를 취득한 내게 트랜잭션은 꽤 익숙한 개념이다.

트랜잭션에 대한 개념을 다시금 확인하고,

스프링에서는 트랜잭션을 어떻게 구현하는지 알아보자.

 

Transaction

트랜잭션은 쪼갤 수 없는 업무의 최소 단위를 의미한다.

 

예를 들어,

A 계좌에서 B 계좌로 송금이 되었다.

그러나 전산 오류로 B 계좌는 돈이 들어오지 않았다.

 

어쨌거나 돈은 보냈으니,

이는 정상적으로 동작했다고 볼 수 있는가?

 

당연히 아니다.

본래 송금이라는 것은 상대방 계좌에 돈이 안전하게 들어가는 것 까지 모든 동작이 이뤄져야 한다.

 

이렇게 쪼갤 수 없는 업무의 단위를 트랜잭션이라고 한다.

 

@Transactional

점점 프레임워크의 매력에 빠져간다...이렇게 쉽게 해주다니...

스프링은 트랜잭션을 허무할만큼 간단하게 구현할 수 있다.

트랜잭션으로 처리할 메서드에 @Transactional을 붙이는 것으로 구현한다.

 

메서드의 모든 로직이 성공적으로 수행되면 commit 처리되며,

동작 중 예외가 발생하는 경우 rollback처리된다.

 

영속성 컨텍스트 (Persistence Context)

트랜잭션 수행 중 Entity 객체를 관리, 보관하는 역할을 수행한다.

트랜잭션이 수행될 때 자동으로 생성되며,

트랜잭션이 종료되면 함께 종료된다.

 

영속성 컨텍스트의 특징

  1. Dirty Check : Entity 변경 사항을 자동으로 감지하여 저장 (별도의 save가 필요없음)
  2. 쓰기 지연 : 모든 SQL 요청을 한번에 묶어서 전송하여 DB 통신으로 발생하는 오버헤드를 줄임
  3. 1차 캐싱 : id를 기준으로 DB로부터 읽어들인 Entity 객체를 캐싱하여 효율적인 입출력 처리

 

짧은 회고

실제 서비스를 위한 재료를 많이 얻어간 날이다.

어렵지 않으나 유익한 시간이기도했다.

 

단순 API 작성에서,

JPA를 사용한 DB 처리와 트랜잭션을 고려한 API 작성이 가능하게 됐다.

 

프레임워크의 강력함에 대해 나날이 느끼고 있다.

프레임워크의 내부 동작에 대해서는 여전히 많은 공부가 필요한 것도 사실이다.

 

사용법만 아는 코더가 되기보다,

원리와 해결법 모두 이해한 엔지니어가 되도록 노력하자!

 

Day 09 : 조금 더 복잡한 기능을 API로 구성하기

새롭게 배운 내용 없어 정리는 생략! (개꿀)

 

짧은 회고

아홉번째 날은 이제껏 배운 모든 내용을 활용하여 API를 작성하는 연습을 가졌다.

 

역시 프로그래밍은 내가 직접 만들어갈 때가 제일 재밌다.

 

세번째 Online Session : Test Code, Refactoring

세번째 온라인 미팅은 정기 미팅이 아닌 깜짝 미팅이었다.

참여자는 적었지만 배운 내용은 그 어느 때 보다 많았다.

 

테스트 코드 작성하는 방법

많은 채용공고 우대사항 중 "TDD를 사랑하는 사람"이라는 내용을 많이 봤는데

아직 내겐 먼 내용이라 생각해 배울 생각도 하지 못한 개념에 대해 맛 볼 수 있었다.

 

너무나 당연하지만,

테스트 코드란 실제 작성한 코드의 구현을 테스트 하는 코드이다.

 

테스트 코드를 작성함으로써 얻을 수 있는 이점은,

나중에 실제 코드를 변경하게 되더라도 동일한 결과를 내는 동일한 로직인지를 쉽게 알아낼 수 있다는 점이다.

 

작성하는 방법은,

필요한 의존성을 설치하고 @Test를 붙이는 것으로 끝이다...

public class CalculatorTest {
	@Test
	public void addTest() {
		// given : 데이터 준비
		Calculator calculator = new Calculator();
		
		// when : 테스트 메서드 호출
		int result = calculator.operate(1, 5, '+');
		
		// then : 값 검증 (예외 테스트 경우 when과 then 통합)
		assertThat(result).isEqualTo(8);
	}
}

 

물론 좋은 테스트 코드를 작성하는 것은 지금 수준에서는 벽처럼 느껴졌으나

그렇게 어렵지만은 않은 내용이겠구나라고 느낌을 가질 수 있던 것 만으로도 큰 수확이었다.

 

리팩토링

리팩토링이라 하면 이전의 코드와 동일한 기능을 수행하되

코드의 가독성을 개선하는 작업이다.

 

좋은 리팩토링을 하기 위해서는

좋은 테스트 코드를 작성함으로써 준비할 수 있다고 한다. (아직 와닿지 않음)

 

2주차 후기

스프링 부트에 대해 익었다고 표현할 수 있을 것 같다.

 

처음부터 프로젝트 설정에 대해 반복 연습을 하다보니,

설정 관련 문제로 막히지 않아 낯설게만 느껴진 프레임워크가 점점 익숙해져간다.

 

API 작성은 계속 연습하고 있고,

그동안 배웠지만 흩어졌던 지식들이 하나로 합쳐지면서,

"배운 건 어떻게든 돌아오는구나" 라고 느꼈다.

 

과제도 미리 다 끝내 놓으니 부담도 없다!

우수 러너에 선정될지는 모르겠지만...

 

이미 너무나 많은 것을 배워가고 있단 생각에 이 과정에 참여한 것이 정말 잘한 선택이라고 생각한다.

 

 

멘토님 말씀으로,

오늘까지 기본적인 재료들은 다 배웠고,

앞으로는 조금 더 객체지향스러운 코드를 짜는 법을 배운다고 하신다.

 

'좋은 코드'에 대한 고민을 게을리하지말자.

지금부터 확실하게 연습해두자!