[SPRING] 인프런 스프링 기본편 강의 공부기록. 上

2022. 3. 2. 00:48JAVA

EJB 지옥에서 안되겠다 ! 하고 태동되었던 것이 스프링

 

  • EJB 컨테이너 대체
  • 단순함의 승리
  • 현재 사실상 표준 기술

 

하이버네이트(Hibernate)

  • EJB 엔티티빈 기술을 대체
  • JPA 새로운 표준 정의

 

스프링 생태계는 현재 아주 거대함.

(스프링 프레임워크, 스프링부트, 스프링 데이터, 스프링 세션, 스프링 시큐리티, 스프링 배치, 스프링 클라우드, ... 등)

 

핵심은 스프링 프레임워크 !

스프링부트는 스프링을 편리하게 사용할 수 있게 지원해줌

 

스프링의 진짜 핵심은?

  • 스프링은 자바 언어 기반의 프레임워크
  • 자바 언어의 가장 큰 특징 - 객체 지향 언어
  • 스프링은 객체 지향 언어가 가진 강력한 특징을 살려내는 프레임워크
  • 스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크

< 객체 지향 ! >

 

객체 지향의 특징은?

자바 기초강의에서 닳도록 들은

  • 추상화
  • 캡슐화
  • 상속
  • 다형성

객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 "객체"들의 모임으로 파악하고자 하는 것이다. 각각의 객체는 메시지 를 주고받고, 데이터를 처리할 수 있다.

프로그램을 유연하고 변경에 용이하게 만드는 것.

 

특히 다형성에 집중해야함

역할(인터페이스)과 구현(구현체)으로 구분해서 보아야 한다.

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

 

입문편에서 MemberRepository 를 MemoryMemberRepository로 최초 구현을 진행하고, 추후에 JdbcMemberRepository 구현체로 갈아끼울 수 있었다. ! 기존의 코드 수정 없이 ! (클라이언트의 변경을 최소화)

그래서 인터페이스를 안정적으로 잘 설계하는 것이 중요.

 

 

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

 

  • SRP: 단일 책임 원칙(single responsibility principle)
  • OCP: 개방-폐쇄 원칙 (Open/closed principle)
  • LSP: 리스코프 치환 원칙 (Liskov substitution principle)
  • ISP: 인터페이스 분리 원칙 (Interface segregation principle)
  • DIP: 의존관계 역전 원칙 (Dependency inversion principle)

글로만 보면 이해가 가지 않을 수 있다. 코드로 작성하고 수정하며 느껴봐야 진정 내것으로 만들 수 있다.

 

 

스프링은 DI와 DI 컨테이너로 다형성과 OCP, DIP를 가능하게 만들어준다.

순수 자바로 SOLID 원칙을 모두 지켜가며 개발을 진행하다보면 언젠가 자신도 모르게 스프링 프레임워크를 만들게 된다.

 

 

 


 

이제 실전, 다시 프로젝트 생성부터 !

 

https://start.spring.io 

 

디펜던시 아무것도 안넣고 generate.

 

spring web을 넣지 않았기 때문에 실행하면 실행되고 끝나는 것이 정상

 

종료되는 것이 당연하다

 


 

비즈니스 요구사항:

 

회원

  • 회원을 가입하고 조회할 수 있다.
  • 회원은 일반과 VIP 두 가지 등급이 있다.
  • 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)

주문과 할인 정책

  • 회원은 상품을 주문할 수 있다.
  • 회원 등급에 따라 할인 정책을 적용할 수 있다.
  • 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
  • 할인 정책은 변경 가능성이 높다.
  • 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고 싶다.
  • 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)

 

아직 미확정인 부분이 많다. 확정될 때까지 개발을 미룰 수는 없으므로 인터페이스 기반의 개발을 진행하면 된다.

 


회원 도메인 설계도:

 

클라이언트 -> 회원서비스impl -> 회원저장소(memoryimpl)

 

 

회원 도메인 개발 !

라이브코딩 꼭 하기

실습한 코드는
https://github.com/leezzangmin/inflearn_spring_study/tree/main/core
에 기록해 두었습니다.

 

단축키, 축약어

psvm

sout, soutv

Ctrl + Alt + V = 리턴 자동완성

 

 

 

 

핵심 플로우

 

애자일 소프트웨어 개발 선언 몰라요?  "계획을 따르기보다 변화에 대응하기를"

 

개발 중에 할인정책 요구사항이 <정액할인정책> 에서 <정률할인정책> 으로 바뀐다면?

 

클라이언트의 OrderServiceImpl 코드를

private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();

1번 줄에서 2번 줄로 수정해야한다.

그렇게 되면 OCP, DIP 같은 설계원칙을 준수하지 못한다.

 

 

DIP는 왜? 

OrderServiceImpl 클래스가 인터페이스인 DiscountPolicy 뿐만 아니라 그 구현체인 FixDiscountPolicy에도 의존하고 있기 때문이다.

 

OCP는 왜?

클라이언트의 코드가 수정되기 때문이다.

 

 

 

어떻게 이 문제를 해결할 수 있을까?

<인터페이스에만 의존하도록 설계를 변경해야 한다>

 

 

그럼 이렇게 하면 되겠네

private final DiscountPolicy discountPolicy;

엥 이게 된다고?

안된다. 당연히 NullPointerException 발생

 

 

누군가 클라이언트에 구현 객체를 대신 생성하고 주입해주는 것이 궁극적인 해결책이다.

 

현재는 클라이언트가 구현체를 선택하는 과중한 책임을 가지고 있다.

외부 기획자가 구현체를 선택해서 주입해주자 !

 

 

public class AppConfig {
    public MemberService memberService()
    {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }

    public OrderService orderService() {
        return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
    }
}

이렇게 AppConfig에서 생성자를 통해 특정 객체를 주입한다.

 

정리

  • AppConfig을 통해서 관심사를 확실히 분리한다.
  • 배역과 배우를 생각하자
  • AppConfig은 극 외부의 공연 기획자다
  • Appconfig은 구체 클래스를 선택한다. 배역에 맞는 담당 배우를 선택한다. 어플리케이션이 어떻게 동작할지 전체 구성을 책임진다.
  • 배우들은 기능을 실행하는 책임만 지면 된다.
  • ex) OrderServiceImpl은 기능을 실행하는 책임만 지면 된다.

 

 

드디어 DIP와 OCP를 성립한다 ~~~~!