스프링이란?

HiroPark·2022년 7월 26일
0

Spring

목록 보기
2/11

김영한님의 인프런 강의를 듣고 개인 목적으로 정리한 글임을 밝힙니다.

- 스프링은 하나의 프로그램이 아니라, 여러 기술들의 모음이다.

- 스프링 프레임워크와 스프링 부트가 스프링의 핵심

-이에 스프링 데이터, 스프링 세션, 스프링 시큐리티, 스프링 Rest Docs, 스프링 배치, 스프링 클라우드 등을 선택적으로 연결할 수 있다.

가장 중요한 것은 결국 스프링 프레임워크.

  • 핵심 기술 : DI 컨테이너 , AOP, 이벤트 , 기타
  • 웹 기술 : 스프링 MVC, 스프링 WebFlux
  • 데이터 접근 기술 : 트랜잭션, JDBC, ORM지원 ,XML 지원
  • 기술 통합 : 캐시 , 이메일, 원격 접근, 스케줄링
  • 스프링 기반 테스트 지원
  • 언어 : 코틀린, 그루비

최근에는 스프링을 편리하게 사용할 수 있도록 지원하는 기술인 스프링 부트 를 통해 스프링을 사용한다.

스프링 부트의 장점들

  1. 단독으로 실행할 수 있는 스프링 애플리케이션을 쉽게 생성할 수 있다
  • 톰캣 같은 별도의 웹서버를 설치하지 않아도 된다.
  • 스프링 부트가 빌드하고 서버 띄우는 과정까지 단독으로 처리해준다.
  1. 손쉬운 빌드 구성을 위한 starter 종속성 제공
  • 라이브러리를 사용할때, 하나의 라이브러리를 사용하면 starter가 연관된 라이브러리를 함께 가져와준다
  1. 스프링과 써드파티 라이브러리 자동 구성
  • 스프링 부트가 메이저한 외부 라이브러리와의 연동을 지원하고, 버전까지 지정해서 다운로드 받을 수 있도록 도와준다. -> 외부 라이브러리 버전에 대해 고민할 필요가 없다!!
  1. 메트릭, 상태 확인, 외부 구성 같은 프로덕션 준비 기능 제공

  2. 관례에 의한 간결한 설정

  • 기존 스프링의 방대한 설정을 간결하게 줄여준다.

스프링 부트는 스프링 프레임워크와 별도의 무엇이 아니라, 스프링을 편리하게 사용할 수 있는 기능들을 제공하는 역할을 한다.

Spring?

문맥에 따라 다르게 사용되는 스프링이란 단어.
1. 스프링 DI 컨테이너 기술
2. 스프링 프레임워크 자체
3. 스프링 부트, 스프링 프레임워크 등을 모두 포함한 스프링 생태계

Why Spring?

이 기술을 왜 만들었는가? 이 기술의 핵심 컨셉은 무엇인가?

스프링은 자바 기반 프레임 워크

  • 자바는 - 객체 지향 언어
  • 스프링은 객체 지향 언어의 특징을 가장 잘 살려내는 프레임워크

스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크이다.

  • 객체 들의 모임으로 프로그램을 파악.
  • 각각의 객체는 서로 협력한다
  • 객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들기에, 대규모 소프트웨어 개발에 많이 사용된다.

    다형성

다형성의 실세계 비유

  • 역할(인터페이스) 과 구현(인터페이스 구현한 객체)로 세상을 구분해보자.

자동차에 대한 구현이 바뀌어도(K3에서 테슬라로 갈아타도), 운전자에게 영향을 주지 않는다.
"자동차 역할" 이라는 인터페이스를 따라서 자동차를 구현했기 때문이다.
운전자는 오직 자동차 역할 이라는 인터페이스에 대해서만 알고 있으면 된다.

  • 이렇게 자동차 역할 과 자동차 구현을 분리한 이유는 운전자(클라이언트) 때문이다.
  • 클라이언트에 영향을 주지 않고 , 역할을 따른 구현을 통해 새로운 기능을 제공할 수 있다.

이처럼 역할과 구현을 분리한다.

핵심은 클라이언트

  • 클라이언트는 대상의 역할(인터페이스)만 알면 된다.
  • 클라이언트는 구현 대상의 내부 구조를 몰라도 된다.
  • 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.
  • 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않는다.

자바에서의 다형성

  • 역할 = 인터페이스

  • 구현 = 인터페이스를 구현한 클래스, 구현 객체

  • 웹 개발에 있어서 클라이언트는 "요청"

  • 서버는 이 요청을 받아서 응답.

  • 따라서, 객체 클라이언트와 객체 서버는 서로 협력관계를 가진다.

클라이언트(MemberService)는 MemberRepository에 의존.
이때 MemberRepository에, MemoryMemberRepository 또는 JdbcMemberRepository를 할당할 수 있다.

public class MemberService {
	// private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
} // 위의 둘 다 가능하다

위에서 볼 수 있듯, 다형성의 본질은 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다 는 것이다.
객체간의 협력을 유지함과 동시에, 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.

  • 역할인 인터페이스를 잘 설계하는 것이 가장 중요하다.

한계점

  • 역할(인터페이스) 자체가 변하면, 클라이언트 - 서버 모두에 큰 변경이 발생한다.
  • 자동차 자체가 비행기로 변경된다면 기존 자동차 인터페이스를 구현한 객체들은 사용할 수 없게 됨
  • USB 인터페이스가 변경된다면 기존 USB인터페이스를 구현한 아이들은 쓰지 못하게 됨
    => 따라서, 인터페이스를 안정적으로 잘 설계하는 것이 가장 중요하다.

좋은 객체 지향 설계의 5원칙(SOLID)

1. Single Responsibility Principle

  • 한 클래스는 하나의 책임만 가져야 한다.
  • "하나의 책임"은 모호한 개념이다
    따라서 SRP를 측정하는 중요한 기준은 변경텍스트,
    변경이 있을 때 파급효과가 적으면 단일 책임 원칙을 잘 따른것이다.

2. Open/Closed Principle

  • 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
  • 확장을 하려면 당연히 기존 코드를 변경해야 하는것 아녀??
  • 다형성을 활용
  • 인터페이스를 구현한 새로운 클래스를 만들어서, 확장을 도모하면서도 기존 코드를 변경하지는 않는다.
public class MemberService {
	// private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
} 

근데 이 예제를 다시 보면, 구현체를 바꿔주는 과정에서 클라이언트인 MemberService의 코드가 바뀌게 된다. 이는 OCP 원칙의 문제점을 보여준다.

  • 클라이언트가 구현 클래스를 직접 선택한다.
  • 따라서, 구현 객체를 변경하려면 클라이언트 코드를 변경해야 한다.
  • 다형성을 사용했음에도 OCP를 지킬 수 없다.

    이 문제를 해결하기 위해, 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요하다. 이 역할을 스프링 컨테이너가 수행

3. Liskov Substitution Principle

  • 다형성에서 하위 클래스는 인터페이스의 규약을 다 지켜야 한다.
  • 인터페이스를 구현한 구현체를 믿고 사용하기 위해 LSP 원칙이 필요.
  • 자동차 인터페이스와 그에 대한 구현체가 있을 때, 악셀 메소드는 "앞으로 가는 기능" 이라는 규약이 있다. 이를 어기고 악셀을 뒤로 가게 구현하면 LSP를 위반하는 것.

4 Interface Segregation Principle

  • 특정 클라이언트를 위한 인터페이스 여러개가, 범용 인터페이스 하나보다 낫다.
  • 자동차 인터페이스는 운전 인터페이스, 정비 인터페이스로 분리하는 것이 좋다.
  • 이러면, 사용자 클라이언트도 운전자 클라이언트와, 정비사 클라이언트로 분리할 수 있다.
  • 인터페이스가 명확해지고, 대체 가능성이 높아진다.

5. Dependency Inversion Principle
"추상화에 의존해야지, 구체화에 의존하면 안된다."

  • 클라이언트 코드는 구현 클래스가 아닌, 인터페이스만 바라봐야 한다(의존해야 한다). = "역할"에 의존하라!
  • MemberService는 JdbcMeberRespository 등에 의존하지 말고 MemberRepository에만 의존해야 한다.
public class MemberService {
    private MemberRepository memberRepository = new JdbcMemberRepository();
} 

이 경우는 MemberService(클라이언트)가 인터페이스인 memberRepository 뿐 아니라, 구현 클래스인 JdbcmemberRepository에도 의존 하는 코드이다.

  • MemberService 클라이언트가 구현 클래스를 직접 선택 한 상황이기 때문.
    => DIP 위반!!
  • 다형성만으로는 DIP를 지킬 수 없다.

스프링과 객체 지향

위에서 살펴보았던데로, 자바의 다형성 만으로는 객체지향원칙의 OCP,DIP를 지킬 수 없다.

  • 스프링은 다형성 + OCP, DIP를 가능하게 지원한다.
    - DI(Dependency Injection)
    • DI컨테이너 제공
  • 클라이언트 코드의 변경 없이 기능을 확장할 수 있다.

정리

  • 모든 설계에 역할과 구현을 분리하자.
  • 이상적으로는 모든 설계에 인터페이스를 부여하는 것이 맞다.
  • 그러나, 인터페이스를 도입하면 추상화 라는 비용이 발생한다.
    - 기능을 확장할 가능성이 없다면, 구체 클래스를 직접 사용하고, 향후 꼭 필요할 때 인터페이스를 도입하는 것도 방법이다.
profile
https://de-vlog.tistory.com/ 이사중입니다

0개의 댓글