본문 바로가기
Back-end/Spring 개념

4. Spring을 사용하는 이유

by devraphy 2022. 1. 27.

0. 개요 

- 이전 포스팅에서 좋은 객체지향 프로그래밍을 위한 SOLID 원칙을 배웠다.

- 이제 SOLID만 따른다면, Java를 사용해 온전한 객체지향 프로그래밍을 구현할 수 있을까? 


1. Java는 SOLID 원칙을 지킬 수 없다. 

- Java만을 이용해서 SOLID 원칙을 구현하는 것에는 문제가 있다.  

- 무엇이 문제인지 알아보자. 

a) OCP와 DIP원칙의 위배 

- Java만을 이용하여 객체지향 프로그래밍을 만들다 보면 OCP와 DIP원칙을 위반하게 된다.

- 간단한 예제를 살펴보자.

public class ServiceImpl implements Service {
   private final Repository repository = new MemoryRepository();
}

- 위의 예시에서 Service의 구현체인 ServiceImpl은 Repository의 구현체인 MemoryRepository를 사용한다.

- 이처럼 ServiceImpl이 직접 MemoryRepository를 선택하는 경우, OCP와 DIP 원칙이 위배된다. 

 

- 그 이유는... 

- MemoryRepository(구현체)에 의존적인 코드가 되며, client 코드를 직접 변경하는 행위에 해당된다. 

- 추후에 Repository의 구현체를 변경해야 한다면, ServiceImpl의 코드(= client의 코드)를 직접 변경해야 한다. 

- 이처럼 client의 코드를 수정하고, client에서 직접 구현체 간의 연결관계를 설정하는 방식은 OCP와 DIP원칙을 위배한 것이다. 

 

- 이처럼 Java만을 이용하여 SOLID원칙을 구현할 수 없다. 그렇다면 해결책은 무엇일까? 

 

b) AppConfig의 등장

- OCP와 DIP를 지키는 가장 쉬운 방법은 누군가 대신해서 그 역할을 수행하는 것이다. 

- 직접 구현체를 선택하는 방식이 아니라, 외부에서 대신 선택해주는 방식으로 말이다. 

- 그 역할을 AppConfig가 대신하게 된다. 

 


2. AppConfig(설정 정보 파일)

a) AppConfig 사용 전

- 위의 사진은 AppConfig를 사용하기 전, client(= ServiceImpl)가 직접 의존관계를 형성하는 구조다. 

- 이처럼 client 측에서 직접 구현체를 선택하고, 직접 의존관계(=연관관계)를 선택하였다. 

- 그러나 이는 OCP, DIP를 위반한 구조다. 

 

b) AppConfig 사용 후

public class AppConfig {

    public Service serviceImpl() {
        return new ServiceImpl(memoryRepository());
    }

    public Repository memoryRepository() {
        return new MemoryRepository();
    }
    
}

- AppConfig 파일은 외부에서 구현체를 생성하고 의존관계를 형성하여, OCP와 DIP 위반을 해결한다. 

- AppConfig는 외부에서 구현체 간의 의존관계를 만들어 주입한다. 그러므로 client 코드의 직접적인 수정은 발생하지 않는다. 

 

- 이처럼 외부에서 필요한 역할을 하게 되면서 객체지향 프로그래밍의 또 다른 특징이 발현한다. 

- 바로 프로그램의 동작 흐름이 내부가 아니라 외부에 의해 통제된다는 것이다. 

 

a) IoC(Inversion of Control)

- AppConfig를 통해 프로그램의 외부에서 구현체를 선택하여 주입하는 방식으로 바뀌었다.

- 외부에서 의존관계를 형성하므로 client는 어떤 구현체와 관계가 형성되는지 알 수 없다.  

- 이처럼 전반적인 프로그램 구조 또는 흐름이 외부(AppConfig)에서 통제 되는 특징을 IoC라고 한다.

 

b) DI(Dependency Injection)

- AppConfig가 구현체를 선택하여 client에게 주입시키는 방식으로 의존 관계를 형성한다.

- 이처럼 어떤 구현체 간의 관계(의존성)를 외부에서 주입하는 것을 의존성 주입(DI)이라고 한다. 

 

c) IoC와 DI가 가능한 이유 - 리스 코프 치환 원칙(LSP) 

- client는 구현체가 아닌 역할(interface)을 선택한다. 그리고 AppConfig가 구현체를 선택하여 client에게 주입한다.  

- 그렇다면 client는 어떻게 구현체를 주입받을까?  

 

- 여기서 리스 코프 치환 원칙(LSP)이 작동한다. 

- LSP는 상위 객체(= 부모)를 하위 객체(= 자식)로 치환하더라도 프로그램이 문제없이 정상 작동해야 한다는 원칙이다. 

- client에서 선택한 interface는 구현체들의 상위 객체로, 하위 객체인 구현체로 치환되어도 그 기능은 정상 작동한다. 


3. Spring을 사용하는 이유 

- 여기까지 SOLID원칙을 지켜가며 객체지향 프로그래밍을 구현하는 방법에 대해서 알아보았다.

- Java만을 이용하여 구현하기에는 한계가 있어, AppConfig라는 외부 파일을 생성하여 이를 통해 성공적으로 구현이 가능해졌다.

- 그러나 여기에는 한 가지 치명적인 단점이 있다. 

 

a) AppConfig파일의 구조적 문제와 한계점 

- AppConfig 파일을 관리하는 것은 매우 귀찮은 일이다. 

- 중복되는 코드가 많으며, 어떤 코드가 어떤 역할을 하는지, 어떤 의존성 관계를 형성하는지 한눈에 알아보기 힘들다(가독성 떨어짐).

- 더불어, 현업 프로젝트는 적어도 수백 개의 구현체를 이용하여 프로그램을 구성한다.  

- 수백 개의 구현체와 그 구현체 간의 의존성(관계)을 AppConfig 파일 하나로 관리한다는 것은 매우 비효율적이다. 

- 즉, 프로그램을 관리하는데 구조적인 문제가 있으며 관리의 한계점이 있다. 

 

b) Spring == AppConfig의 구조적 문제 해결책 

- 위에서 언급한 AppConfig의 모든 문제점은 Spring framework를 사용하면 해결된다.

- Java와 Spring에서 제공하는 Annotation을 이용하여 설정 파일 없이 구현체의 역할과 의존관계를 명시할 수 있다.

- 그 외에도 Spring에서 제공하는 기능으로 객체지향 프로그래밍과 다형성을 극대화할 수 있다.

- 이와 같은 이유로 Spring framework를 사용한다. 

'Back-end > Spring 개념' 카테고리의 다른 글

6. Spring Container의 다형성  (0) 2022.02.01
5. Spring Container  (0) 2022.01.31
3. SOLID 원칙  (0) 2022.01.26
2. 다형성(Polymorphism)과 객체지향 프로그래밍(OOP)  (0) 2022.01.24
1. Maven과 Gradle이란?  (0) 2022.01.23

댓글