🤍 전 강의 25% 할인 중 🤍

2024년 상반기를 돌아보고 하반기에도 함께 성장해요!
인프런이 준비한 25% 할인 받으러 가기 >>

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

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

저번주에 호기롭게 다짐했던 이번주에는 공부를 미리 다해보자!라고 했는데

오히려 저번주보다 공부를 덜 했다...

분명 할 시간이 많을거라 생각했는데 이것저것 해보던 취준과 여행의 여파로 너무 피곤하기만 해서 뭘 제대로 해보지도 못하고 한 주가 지나갔다.

열심히 해보려던 과제도 결국 두 개 중 하나만 제출하고 너무 허무한 한 주이다.

그래서 그런지 더욱 머리에 내용이 안 남지만,, 낼부터는 진짜 열심히 해야겠다고 다시 한 번 다짐한다!!

 

이번주에는 나름의 복습으로 저번주에 공부하면서 정리했던 내용들을 다시 읽어보았다.

사실 자바도 익숙하지 않아서 스프링은 더 안 낯선 언어인데 그래도 한 번 쓰면서 공부해봤다고 조금 눈에 익은 것 같다.

섹션3 밖에 다 하지 못 했지만 다음주에는 얼른 진도에 맞춰 끝내놔야겠다.

 


Section3

역할의 분리와 스프링 컨테이너라는 제목이다.

역할의 분리가 얼마나 중요할까?에 대해서 생각하면서 코드를 짜본적은 없던 것 같다. 아무래도 급하게 프로젝트만 하니 아 그냥 분리하는게 좋구나 해서 분리했던 기억이 난다.

 

Layered Architecture

3단 분리를 해야하는 이유?!

💡 Controller에서 모든 기능을 구현하면 왜 안 될까?

=> 함수는 최대한 작게 만들고 한 가지 일만 수행하는 것이 좋다고 설명해주셨다. 클래스는 작아야 하며 하나의 책임만을 가져야 한다.

예를 들어, 만약 controller 함수 1개가 3000줄이 넘으면?

  1. 그 함수를 동시에 여러 명이 수정할 수 없음

  2. 그 함수를 읽고, 이해하는 것이 너무 어려움

  3. 그 함수의 어느 부분을 수정하더라도 함수 전체에 영향을 미칠 수 있기 때문에 함부로 건들 수 없게 됨

  4. 너무 큰 기능이기 때문에 테스트도 힘듦

  5. 종합적으로 유지보수성이 매우 떨어짐

결국 이런 이유로 Controller에 모든 기능을 넣기 보다는 Service와 Repository에 나누는 게 좋다!!

여태 작성했던 코드는

  1. API의 진입 지점으로써 HTTP Body를 객체로 반환

  2. 현재 유저가 있는지 없는지 확인하고 예외 처리함

  3. SQL을 사용해 실제 Database와의 통신을 담당

를 Controller에서 모두 하고 있었는데 1번은 Controller, 2번은 Service, 3번은 Repoitory로 나누는 작업을 한다.

 

3가지 역할을 나누는 것을 Layered Architecture 라고 하는데

Controller ← Service ← Repository (DTO는 계층 간의 정보 전달 역할) 로 나눠진다.

 

이 때 기능만 나눠서는 안 된다. 우리는 JdbcTemplate 를 파라미터로 계속 받고 있어 오류가 생긴다.

해결 방법은 UserRepositoryUsercontroller 처럼 JdbcTemplate 를 변수로 받으면 된다.

 


그럼 또 다음과 같은 의문점이 생긴다

💡Controller에 있는 JdbcTemplate 는 어디서 온 걸까? → Repository에서 바로 JdbcTemplate를 가져올 수는 없을까?

답은 @RestController이다.

@RestController어노테이션을 사용하면 UserController 클래스를 API의 진입 지점으로 만들 뿐 아니라 UserController 클래스를 스프링 빈으로 등록시키는 역할을 해준다.

 

스프링빈이란?

서버가 시작되면, 스프링 서버 내부에 거대한 컨테이너를 만들고, 컨테이너 안에는 클래스가 들어가게 됨

⇒ 이 때 다양한 정보도 함께 들어있고, 인스턴스화도 이루어짐

즉, 이때 스프링 컨테이너 안으로 들어간 클래스를 스프링 빈이라고 한다.

JdbcTemplate도 이미 스프링 빈으로 등록되어 있음

JdbcTemplate우리가 build.gradle에서 설정한 dependency(의존성)에서 등록해주고 있었다!

 

스프링 컨테이너는 필요한 클래스를 연결해준다

서버가 시작되면 다음과 같은 일이 일어나는데

  1. 스프링 컨테이너(클래스 저장소)가 시작

  2. 기본적으로 많은 스프링 빈들이 등록됨(JdbcTemplate)

  3. 우리가 설정해준 스프링 빈 등록(UserController)

  4. 이때 필요한 의존성이 자동으로 설정됨

💡 그렇다면 왜 UserRepositoryJdbcTemplate을 가져오지 못할까?

JdbcTemplate 을 바로 가져오려면 스프링 빈이어야 하는데 UserRepository는 스프링 빈이 아니다

UserRepository를 스프링 빈으로 등록해보자!!

여기서 Repostitory에는 @Repostitory Service에는 @Service 를 각각 등록해주면 스프링 빈으로 등록된 것이다.

 


 💡 좋아진 것 같긴 한데 왜 스프링 컨테이너를 사용하지? 그냥 new 연산자 쓰면 되는거 아닝가?? 라는 의문이 들 것이다.

책을 저장하는 api를 만든다고 가정해보자.

그럼 Controller, Service, Repository 이렇게 구성하고 만들 것이다.

이 때 db를 메모리에만 저장하는 코드로 구성했다가, MySql과 같은 db에 저장한다고 하면

repository가 수정될 때마다 새로 new BookMySqlRepository();  이런 식으로 계속 추가해야 한다.

자동으로 연결해주기 위해 스프링 컨테이너를 활용한다!

 

스프링 컨테이너란 컨테이너가 BookService를 대신 인스턴스화 하고 그 때 알아서 BookRepository를 결정해주는 건데 BookServiceBookRepository가 모두 스프링 빈이라면 스프링 컨테이너는 BookService를 알아서 인스턴스화 하고BookRepository를 결정해줄 것이다.

 

BookRepository

package com.group.libraryapp.repository.book;

import org.springframework.stereotype.Repository;

@Repository
public class BookMySqlRepository implements BookRepository{
    @Override
    public void saveBook() {

    }
}

 

BookController

public class BookController {

    // 2. BookService 연결 => 스프링 빈이 아닌 경우
    private final BookService bookService; // instance화 할 필요 X

    public BookController(BookService bookService) {
        this.bookService = bookService;
    } // 생성자 추가(constructor)

이렇게 하면 알아서 어떤 레포지토리를 불러올지 결정한다.

이때 레포지토리가 너무 많다면 @Primary 를 사용해 어떤 레포지토리를 우선순위에 둘지 레포지토리에 직접 설정해준다.

 


빈을 사용하는 방법

@Configuration@Bean 이 있는데 둘은 항상 같이 사용해야 한다.

@Configuration

  • class에 붙이는 어노테이션

  • @Bean 을 사용할 때 함께 사용해 주어야 함

@Bean

  • method에 붙이는 어노테이션

  • 메소드에 반환되는 개체를 스프링 빈에 등록

@Configuration 이라는 어노테이션은 보통 config 라는 패키지에 만든다.

@Component

  • 주어진 클래스를 컴포넌트로 간주

  • 컴포넌트로 간주된 클래스들은 스프링 서버가 뜰 때 자동으로 감지된다.

  • @RestController@Service@Repository@Configuration 어노테이션은 모두 @Component 어노테이션을 가지고 있음

 

스프링 빈을 주입 받는 방법

  • 생성자를 이용해 주입받는 방식 (가장 권장)

     

  • setter를 통해 주입받는 방식

  • 필드에 직접 주입하는 방법

    • 권장 X

    • setter를 통해 다른 인스턴스로 교체해 동작에 문제가 생길 수 있음

    • 필드에 바로 주입하게 되면 테스트가 어려움

 


과제5

클린 코드에 대해 배우고 클린 코드 직접 작성하기

https://velog.io/@dmsqls19/인프런-워밍업-클럽-1기-BE-과제5.-클린-코드Clean-Code

 


느낀 점

일단 이번주에 공부를 너무 안 해서,,, 조금 회고록이 짧은 것에 대해 반성해야겠다.

그리고 배우면서 느낀건 클린코드가 정말 중요하다는 걸 깨달았다.

내가 쓴 코드에 대해 설명할 때 이건 왜 이렇게 구성했는지에 잘 파악하면 된다고 생각했는데 줄일 수 있는 건 최대한 줄이면서 간결하게 하는 것도 중요하다는 걸 느꼈다. 코드가 왜이렇게 복잡하지? 했던 것도 다 줄일 수 있는 것들이었다.

배운 것보다 배울 게 더 많다 라는 생각과 함께 걱정은 되지만 새로운 걸 배우는 건 늘 재밌기 때문에 다음주도 기대가 된다.

댓글을 작성해보세요.

채널톡 아이콘