🤍 전 강의 25% 할인 중 🤍

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

[인프런 워밍업 클럽 Study] 백엔드 2주차 발자국

[인프런 워밍업 클럽 Study] 백엔드 2주차 발자국


학습 내용 요약

 

<클린 코드>

좋지 않은 코드를 작성할 때의 문제점

  • 협업에 어려움을 겪게 된다

  • 가독성이 떨어져 생산성이 낮아진다

  • 코드 수정 시 다른 코드에 끼칠 영향으로 인해 수정이 어려워진다

  • 테스트에 어려움을 겪게 된다

  • 종합적으로, 유지보수성이 매우 떨어지게 된다

 

<Layered Architecture>

  • 각 클래스가 각자의 역할을 가지고 겹겹이 쌓인 것을 의미한다

  • [ Repository ] → [ Service ] → [ Controller ] + ( DTO )

 

<Controller와 Spring Container>

@RestController
public class UserController {
	private final UserService userService;
	public UserController(JdbcTemplate jdbcTemplate) {
		this.userService = new UserService(jdbcTemplate);
	}
}
  • 위 코드에 대한 의문은 다음과 같다.

    • 클래스 안에 있는 함수를 사용하기 위해서는 인스턴스화가 필요하다. UserController에 있는 메소드를 API 진입 지점으로 사용하고 있으나 현재 UserController는 인스턴스화가 되어있지 않다.

    • UserController의 생성자는 JdbcTemplate에 의존하고 있으나 JdbcTemplate에 대한 처리 없이 UserController에서 JdbcTemplate를 가져오고 있다.

  • @RestController

    • UserController 클래스를 API의 진입 지점으로 설정해준다.

    • UserController 클래스를 스프링 빈으로 등록시킨다.

      • @SpringBootApplication이 다양한 설정들을 모두 자동으로 해준다. 이때 자동으로 해주는 것 중 하나가 스프링 서버 내부에 거대한 컨테이너를 만드는 것이다.

      • 컨테이너 안에 클래스가 들어가게 되며 이렇게 들어간 클래스를 스프링 빈이라고 한다. 클래스가 들어갈 때는 이 빈을 식별할 수 있는 이름 및 타입과 함께 다양한 정보들이 저장된다. 그리고 이때 인스턴스화도 함께 이뤄진다.

      • JdbcTemplate 역시 스프링 빈으로 등록되어 있다. build.gradle에 설정했던 spring-boot-starter-data-jpa 의존성이 JdbcTemplate 을 스프링 빈으로 미리 등록해 준 것이다.

      • 스프링 컨테이너는 UserController를 인스턴스화할 때, UserController가 필요로 하는JdbcTemplate 을 컨테이너 내부에서 찾아 인스턴스화를 진행해 준다. 만약 이때 JdbcTemplate이 없다면 에러가 발생한다.

  • 정리하자면, 서버를 시작하게 되면 다음과 같은 일이 순차적으로 일어난다.

    1. 컨테이너가 시작된다.

    2. 컨테이너에 기본적으로 많은 스프링 빈이 등록된다. (ex. JdbcTemplate)

    3. 스프링을 사용하는 개발자가 설정해 준 스프링 빈이 등록된다. (ex. UserController)

    4. 이때 필요한 의존성이 자동으로 설정된다. (ex. UserController를 만들 때 JdbcTemplate을 자동으로 넣어준다)

  • Repository와 Service 또한 각각 @Repository@Service 어노테이션으로 스프링 빈으로 등록시켜줄 수 있다.

 

<Spring Container를 사용하는 이유>

IoC (Inversion of Control, 제어의 역전)

  • 프로그래머가 작성한 프로그램이 재사용 라이브러리의 흐름 제어를 받게 되는 소프트웨어 디자인 패턴을 말한다.

  • IoC의 목적

    • 작업을 구현하는 방식과 작업 수행 자체를 분리한다.

    • 모듈을 제작할 때, 모듈과 외부 프로그램의 결합에 대해 고민할 필요 없이 모듈의 목적에 집중할 수 있다.

    • 다른 시스템이 어떻게 동작할지에 대해 고민할 필요 없이, 미리 정해진 협약대로만 동작하게 하면 된다.

    • 모듈을 바꾸어도 다른 시스템에 부작용을 일으키지 않는다.

  • 출처 : 위키백과 ( https://ko.wikipedia.org/wiki/제어_반전 )

 

DI (Dependency Injection : 의존성 주입)

  • 하나의 객체가 다른 객체의 의존성을 제공하는 것을 의미한다.

  • DI의 장점

    • 의존성 주입은 클라이언트의 구성 가능성을 유연하게 해준다. 클라이언트의 행위는 고정되어 있다. 클라이언트는 클라이언트가 기대하는 고유한 인터페이스를 지원하는 모든 것을 할 수 있다.

    • 의존성 주입을 통해 시스템의 구성 세부 사항을 외부의 구성 파일에서 사용하여 리컴파일 없이 시스템을 재구성할 수 있다. 분리된 구성은 컴포넌트의 여러 구현을 요구하는 다양한 상황을 위해 작성될 수 있다. 이는 국한되어 있지는 않지만 테스팅을 포함한다.

    • 의존성 주입은 코드의 동작에서의 어떠한 변경도 요구하지 않으므로 리팩터링으로써 레거시 코드에도 적용할 수 있다. 클라이언트는 더 독립적이며 테스트에 속하지 않은 다른 객체를 가장하는 stubs 또는 모의 객체를 사용해 독립된 유닛 테스트가 더 쉬워지는 결과를 얻는다.

    • 의존성 주입을 통해 클라이언트는 사용해야하는 모든 구체적인 구현에 대한 지식을 제거할 수 있다. 디자인 변경이나 결함의 영향으로부터 클라이언트를 독립하는데 도움을 주며, 이는 재사용성, 테스트가능성, 유지가능성을 향상시킨다.

  • 출처 : 위키백과 ( https://ko.wikipedia.org/wiki/의존성_주입 )

 

<Spring Container를 다루는 방법>

  • @Primary@Qualifier

    • @Primary : 여러 개의 Bean들 중 사용할 Bean에 붙이는 어노테이션.

    • @Qualifier : Bean에 추가 구분자를 붙여주는 방법으로 생성자에서 해당 구분자를 명시하면 그 구분자를 가진 Bean을 주입해준다.

    • @Primary와 @Qualifier 중에 @Qualifier의 우선순위가 더 높다.

  • @Configuration@Bean

    • @Configuration : 클래스에 붙이는 어노테이션으로, @Bean을 사용할 때 함께 사용해 주어야 한다.

    • @Bean : 메소드에 붙이는 어노테이션으로, 메소드에서 반환되는 객체를 스프링 빈에 등록한다.

    • 보통 직접 만든 클래스를 스프링 빈으로 등록할 때에는 @Service나 @Repository를 사용하고, 외부 라이브러리나 프레임워크에 만들어져 있는 클래스를 스프링 빈으로 등록할 때에는 @Configuration + @Bean 조합을 많이 사용하게 된다.

  • @Component

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

    • @Component 어노테이션을 붙이면 주어진 클래스를 ‘컴포넌트'로 간주하고, 컴포넌트들은 스프링 스프링 서버가 뜰 때 자동으로 감지된다. @Component 덕분에 지금까지 우리가 사용했던 어노테이션들이 모두 자동으로 감지되었던 것이다.

    • @Component 어노테이션은 컨트롤러, 서비스, 리포지토리가 아닌 추가적인 클래스를 스프링 빈으로 등록할 때에도 사용된다.

     

<Spring Bean을 주입받는 방법>

1. 생성자를 이용한 주입

  • 보통 제일 우선시되는 방법이다.

@Repository
public class UserRepository {
	private final JdbcTemplate jdbcTemplate;
	
	// 생성자에 JdbcTemplate이 있으므로 스프링 컨테이너가 넣어준다.
	public UserRepository(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	...
}

 

2. setter를 이용한 주입

  • setter 메소드에 @Autowired 어노테이션을 사용하여 주입한다.

@Repository
public class UserRepository {
	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	...
}

 

3. 필드에 직접적으로 주입

  • 필드 위에 @Autowired 어노테이션을 사용하여 주입한다.

@Repository
public class UserRepository {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	...
}

 

4. @Qualifier 어노테이션을 이용한 주입

  • @Qualifier 어노테이션은 Spring Bean을 사용하는 쪽과 등록하는 쪽 모두 사용할 수 있다.

@Service
@Qualifier("main")
public class BananaService {

	...
}
@RestController
public class UserController {

	private final UserService userService;
	private final FruitService fruitService;
	
	public UserController(UserService userService,
	@Qualifier("main") FruitService fruitService) {
		this.userService = userService;
		this.fruitService = fruitService;
	}
	
	...
}

회고

이번 주에는 지난 금요일에 들었던 깜짝 특강이 기억에 남았습니다. 테스트 코드에 대한 것은 막연하게 들어만 봤었습니다. 얼마 전에 프로젝트를 진행하면서 팀원이 사용한 것을 보긴 했지만, 당시에 저는 프론트앤드 역할이라 테스트 코드에 대해서 고찰해 볼 기회가 적었습니다. 이렇듯 테스트 코드를 실제로 적용한 적은 없었지만 지난 특강으로 클린코드에 대한 개념과 더불어 테스트 코드의 작성에 대한 개념을 익히게 되어 도움이 많이 되었습니다.


 

댓글을 작성해보세요.

채널톡 아이콘