본문 바로가기
면접을 위한 CS 전공지식 노트

면접을 위한 CS 전공지식 노트 - 1장

by wwns 2022. 11. 22.
반응형

면접을 위한 CS 전공지식 노트 책을 읽고 간단한 CS 지식을 정리해 보도록 합니다.!

 

1.1 디자인 패턴

  1. 싱글톤 패턴
    1. 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴으로 보통 DB Connection에서 많이 쓰인다.
    2. 해당 인스턴스를 다른 모듈들이 공유하며 사용하기 때문에 인스턴스 생성 비용이 줄어드는 장점
    3. 모듈들이 공유한다는 것은 의존성이 높아진다는 의미
package pattern;
 
public class Singleton {
    private static Singleton instance;
 
    private Singleton() {}	// 외부에서의 인스턴스화를 막음.
 
    public static Singleton getInstance() {
        return instance == null ? new Singleton() : this.instance;
    }
}

싱글톤 사용의 단점

  • 모듈 간의 결합을 강하게 만든다.
  • TDD를 할 때 걸림돌이 된다.
    • TDD를 할 때 단위 테스트를 주로 하는데, 단위 테스트는 테스트가 서로 독립적이어야 하는데 싱글톤은 하나의 인스턴스를 생성해서 모듈에서 공유하기 때문에 '독립적인' 인스턴스를 만들기 어렵다.

싱글톤 패턴 사용 시 다른 모듈에서 강한 의존성이 생긴다.

의존성 주입(DI, Dependency Injection)

  • 싱글톤 패턴을 사용하면 모듈 간 의존성이 강해지는데, 의존성 주입 방식을 사용하면 모듈 간의 결합을 좀 더 느슨하게 해결할 수 있다.

  • 메인 모듈이 '직접' 다른 하위 모듈에 대한 의존성을 주기보다 중간에 의존성 주입자를 두면 메인 모듈이 '간접'적으로 의존성을 주입하는 방식.
  • 상위 모듈은 하위 모듈에 대한 의존성이 떨어지며 이를 '디커플링 된다'라고 한다.

의존성 주입의 장점

  • 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅하기 쉽고 마이그레이션 하기도 수월하다.
  • 구현 시 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어주기 떄문에 의존성 방향이 일관되고 애플리케이션을 쉽게 추론할 수 있으며 모듈 간의 관계들이 좀 더 명확해진다.
    • 인스턴스를 주입 받는다는 것은 외부에서 생성된 인스턴스를 인터페이스를 통해서 넘겨받는 것

의존성 주입의 단점

  • 모듈들이 더욱 더 분리되므로 클래스 수가 늘어나 복잡성이 증가
  • 런타임 페널티 (런타임 시 의존관계가 결정)

 

의존성 주입은 프레임워크를 사용한다면 모두가 알고 있을 개념일 것이다. 위의 그림처럼 의존성 주입자는 예로 들면 스프링 프레임워크에서 스프링 컨테이너가 해당되고, 컨테이너에 등록된 Bean을 주입해준다. 크게 생각해보지 않고 의존성 주입을 마구 사용했던 적이 있었고, 여러 의존성 주입 방식 중 가장 간단한 Filed Injection만 사용했었다. 하지만 순환 참조 시 애플리케이션 구동에 에러가 발생하지 않는다는 문제점 때문에 생성자 주입 방식만 사용 가능해졌다. 처음 공부할 때는 몰랐지만 이제는 이유를 알았고, 잊지 않기 위해 간단히 정리해보려 한다.

 

스프링에서 사용할 수 있는 DI 방법 세 가지 -> 한 가지가 된 이유?

@Service
public class CourseServiceImpl implements CourseService {

    @Autowired
    private StudentService studentService;

    @Override
    public void courseMethod() {
        studentService.studentMethod();
    }
}

CourseService와 StudentService가 있고 서로를 순환 참조하는 경우를 예로 들려고 한다.

  • Filed Injection
@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    private CourseService courseService;

    @Override
    public void studentMethod() {
        courseService.courseMethod();
    }
}

Filed Injection은 @Autowired 어노테이션을 사용해 스프링 컨테이너에서 Bean을 주입해주는 방식이며 순환 참조를 해도 스프링 애플리케이션 구동에 문제가 없다.

  • Setter Based Injection
@Service
public class StudentServiceImpl implements StudentService {

    private CourseService courseService;

    @Autowired
    public void setCourseService(CourseService courseService) {
        this.courseService = courseService;
    }

    @Override
    public void studentMethod() {
        courseService.courseMethod();
    }
}

@Autowired를 통해 setter로 주입시키는 방식이다. Filed Injection과 같이 순환 참조를 해도 스프링 애플리케이션 구동에 문제가 없다.

컨테이너가 빈을 생성하면서 둘의 순환참조 관계를 알아차릴 수 없다.

당연한 이야기이다. 객체 생성시점에서 순환참조가 일어나는 것을 알 수 있는 방법이 없다.

비즈니스 로직에서 메서드 호출이 됐을 때서야 순환참조가 일어나는 것을 알 수 있다.

이렇게 두 가지  의존성 주입 방식에서는 문제점이 있기 때문에 사용이 금지되고 있다.

  • Contructor based Injection
@Service
public class StudentServiceImpl implements StudentService {

    private final CourseService courseService;

    @Autowired
    public StudentServiceImpl(CourseService courseService) {
        this.courseService = courseService;
    }

    @Override
    public void studentMethod() {
        courseService.courseMethod();
    }
}

'컨테이너가 빈을 생성하면서 둘의 순환참조 관계를 알아차릴 수 없다.'이 말의 의미가 무엇인지 생성자 주입 방식을 보면 알 수 있다. 생성자에 @Autowired가 들어가면서 컨테이너가 빈을 생성할 때 객체 생성에 순환 관계가 생기는 것을 알아차리고 에러를 내뱉는다.

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  courseServiceImpl defined in file [/Users/yaboong/.../CourseServiceImpl.class]
↑     ↓
|  studentServiceImpl defined in file [/Users/yaboong/.../StudentServiceImpl.class]
└─────┘

+ 생성자 주입 방식(Contructor based Injection) 장점

  • 의존관계 설정이 되지 않으면 객체생성 불가하다
    • 컴파일 시점에서 에러가 발생, NPE 방지
  • 의존성 주입이 필요한 필드를 final로 선언 가능하다.
    • Immutable 객체로 만들 수 있음
  • 순환 참조 감지 가능
  • 테스트 코드 작성 용이
    • 단위 테스트 시 의존관계를 가지는 객체를 생성해서 주입할 수 있다.
    • 생성자에 주입하고 싶은 구현체를 넣으면 됨.

 

어느 순간부터 private final으로 의존성을 가지는 인스턴스를 관리하기 시작했었던 기억이 있었는데 CS 면접 책을 읽으면서 정리할 수 있어서 좋았다..

이제 10p 읽었는데 글 하나를 길게 써버렸다니.. 책을 읽으면서 정리하고 추가적으로 정리하고 싶은 부분이 있으면 정리하겠습니다!

 

반응형

'면접을 위한 CS 전공지식 노트' 카테고리의 다른 글

네트워크  (0) 2022.11.30
프로그래밍 패러다임  (2) 2022.11.27
면접을 위한 CS 전공지식 노트 - 1장-2  (0) 2022.11.24