Backend/Spring

객체 지향 설계와 스프링

아네스 2022. 1. 12. 20:03
반응형

본문은 김영한님의 스프링 핵심원리 - 기본편의 내용을 담고있습니다.

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢

www.inflearn.com

스프링이란 ?

자바계열 표준기술 EJB(Enterprise Java Beans)

이론상 좋은데, 개발자들이 죽어남. 너무 복잡하고 쓰기 어렵기까지 한데, 느림..

 

스프링 생태계

여러가지 기술들의 모음

필수적인 스프링 프레임워크 / 스프링 부트

선택적으로 스프링 데이터 / 세션 / 시큐리티 / Rest Docs / 배치 / 클라우드 등등..

 

결국 가장 중요한건 스프링 프레임워크

핵심기술 : 스프링 DI 컨테이너, AOP, 이벤트, 기타 ( 강의 타겟 내용 )

웹기술 : 스프링 MVC, 스프링 WebFlux

데이터 접근 기술 : 트랜잭션, JDBC, ORM 기술, XML지원

기술 통합 : 캐시, 이메일, 원격접근, 스케쥴링

테스트 : 스프링 기반 테스트 지원

언어 : 코틀린, 그루비 등등..

 

스프링 부트

 - 스프링을 편리하게 사용할 수 있도록 지원, 최근에는 기본적으로 사용함.

 - Tomcat 같은 웹 서버를 내장해서 별도의 웹 서버 설치가 필요하지 않음.

 - 손쉬운 빌드 구성을 위한 starter 종속성 제공

 - 스프링과 3rd parth(외부) 라이브러리 자동 구성 : 라이브러리 버전 호환성 테스트 되어있음.

 - 메트릭, 상태확인, 외부 구성 같은 프로덕션 준비 기능 제공 

 - 관례에 의한 간결한 설정 ( 설정이 진짜 힘들었음. default 설정이 있음 : 필요하면 커스터마이징 )

 

스프링 단어 ?

 : 문맥에 따라 다르게 사용됨

  - 스프링 DI 컨테이너 기술 ( bean관리 등등.. )

  - 스프링 프레임워크

  - 스프링 부트, 스프링 프레임 워크 등을 모두 포함한 스프링 생태계

 

스프링은 왜 만들었나요 ?

핵심 개념

이 기술을 왜 만들었는가 ?

이 기술의 핵심 컨셉은?

 

스프링의 핵심 개념, 컨셉?

 - 자바 언어 기반의 프레임 워크

 - 자바 언어의 가장 큰 특징 = 객체 지향 언어

 - 객체 지향 언어가 가진 강력한 특징을 살려내는 프레임워크

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


좋은 객체 지향 프로그래밍이란?

객체 지향 프로그래밍

 : 객체들의 모임 , 각각의 객체 협력함. 유연하고 변경이 용이 

 

유연하고 변경이 용이하다 ?

 - 레고블럭 조립하듯

 - 키보드, 마우스 갈아 끼우듯이

 - 컴퓨터 부품 갈아 끼우듯이

 

다형성 ( Polymorphism )

실세계와 비유하기에 용이하지는 않지만 그래도 이해해보자.

역할과 구현으로 세상을 구분해보자.

 

운전자 - 자동차 ( K3 / 아반떼 / 테슬라 모델3 )

운전자는 자동차가 바뀌어도 운전 할 수 있음.

자동차의 역할은 존재하고 자동차의 구현이 바뀌었다고 해서 문제가 생기지 않음

운전자는 자동차의 인터페이스만 알고 있으면 됨. ( 내부 구조를 몰라도 된다 )

완전히 새로운 자동차가 나와도 자동차 역할만 그대로면 무한히 확장 가능하다는 의미.

클라이언트에 영향을 주지 않고 새로운 기능을 추가할 수 있음을 의미. 

 

공연무대 (로미오와 줄리엣)

로미오 역할 / 줄리엣 역할이 있는 거고 배우는 누가 들어와도 상관없는것임.

역할을 수행할 대본만 충실하면 배우는 대체 가능함.

 

이런것이 바로 유연하고, 변경 용이하다는 점임.

 

역할과 구현으로 분리하면..

세상이 단순해지고, 유연해지고 , 변경도 편리해진다.

 - 클라이언트는 대상의 역할(인터페이스)만 알면된다.

 - 구현 대상의 내부 구조를 몰라도 된다.

 - 내부 구조가 변경되어도 영향을 받지 않는다.

 - 대상 자체를 변경해도 영향을 받지 않는다.

 

 

자바 언어에서는 다형성을 활용

 - 역할 = 인터페이스

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

객체를 설계할 때 역할과 구현을 명확히 분리

인터페이스를 먼저 부여하고, 역할을 수행하는 구현 객체를 만드는 것이 중요.

 

객체의 협력이라는 관계부터 생각

 - 혼자있는 객체는 없다.

 - 클라이언트 : 요청 , 서버 : 응답

 

자바 언어의 다형성

 - 오버라이딩을 떠올려보면 save()라는 인터페이스가 있으면 save할 수 있는 객체만 있으면 갈아 끼울 수 있음.

public class MemberService {
	private MemberRepository memberRepository = new MemoryMemberRepository();
}

public class MemberService {
	// 갈아끼워질 수 있다.
	//private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
}

 

다형성의 본질

 - 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다.

 - 다형성의 본질을 이해하려면 협력이라는 객체 사이의 관계에서 시작해야함.

 - 클라이언트를 변경하지 않고, 서버의 구현기능을 유연하게 변경할 수 있다.

 

정리

 - 실세계의 역할과 구현이라는 편리한 컨셉을 다형성을 통해 객체 세상으로 가져올 수 있다.

 - 유연, 변경 용이

 - 확장 가능설계

 - 클라이언트에 영향을 주지 않는 변경

 - 인터페이스를 안정적으로 잘 설계하는게 중요. ( 이게 깨지면 무너짐 )

 

한계

 - 인터페이스 자체가 변하면, 클라이언트/서버 모두 변경해야되서 심각해짐

 - 자동차가 비행기가 된다던지, 대본자체가 변경되던지, USB 키보드가 아니라 다른 연결방식이 된다던지 등등..

 - 결국 인터페이스를 안정적으로 잘 설계하는 것이 중요하다.

 

스프링과 객체 지향

 - 다형성이 가장 중요하다.

 - 스프링은 다형성을 극대화해서 이용할 수 있게 도와줌.

 - 제어의 역전(IoC), 의존관계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원

 - 스프링을 사용하면 다형성을 매우 쉽게 다룰 수 있게 해준다.

 


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

클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리함.

1. SRP : 단일 책임 원칙 ( Single responsibility principle)

 - 한 클래스는 하나의 책임만 가져야한다.

 - 책임이 모호하다. 중요한 판단의 기준은 변경이다.

 - 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이라 볼 수 있다.

 - ex) UI를 바꿨을 뿐인데 SQL 문부터 다 고쳐야 한다면 ?

 - 책임의 범위를 조절하는 것이 묘미.

 

2. OCP: 개방-폐쇄 원칙 ( Open/Closed principle) ** 중요

 - 소프트웨어 요소는 확장에는 열려있으나, 변경에는 닫혀있어야 한다.

 - 다형성을 생각하면 이해하기 쉽다.

 - 인터페이스는 변경안되고, 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현

 - 문제점

   : 구현객체를 변경하려면 클라이언트 코드를 변경해야한다.

   : 분명 다형성을 사용했지만 OCP원칙을 지킬 수 없다.

   -> 객체를 생성하고 연관관계를 맺어주는 별도의 조립, 설정자가 필요하다. ( 이걸 스프링이 해주는 것 )

 

3. LSP: 리스코프 치환 원칙 ( Liskov substitution principle)

 -  객체는 프로그램의 정확성을 깨드리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야한다.

 - 예를들어 자동차 인터페이스의 엑셀을 구현하는데, 엑셀을 밟으면 앞으로 가야하는데, 뒤로 가게끔 구현을 한다면 프로그램의 정확성을 위배한 것이기에 LSP를 지키지 못한 것이다.

 - 단순 컴파일을 의미하는 것이 아님. 

 

4. ISP: 인터페이스 분리 원칙 (Interface segregation principle)

 - 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다.

 - 자동차 인터페이스 하나로 퉁치는 것보다 운전 인터페이스 , 정비 인터페이스로 분리하면

 - 사용자 클라이언트는 운전자 / 정비사 클라이언트로 분리할 수 있게됨.

 - 인터페이스가 명확해지고, 대체 가능성이 높아진다.

 

5. DIP: 의존관계 역전 원칙 (Dependency inversion principle)

 - 프로그래머는 "추상화에 의존해야지, 구체화에 의존하면 안된다"

 - 의존성 주입은 이원칙을 따르는 방법 중 하나이다.

 - 쉽게 말해서 클라이언트가 interface만 알고, 구현에 대해서는 몰라야한다는 것.

 - 역활에 의존해야지, 구현에 의존해야함.

 

정리

 - 객체지향의 핵심은 다형성

 - 다형성 만으로는 쉽게 부품을 갈아끼우듯이 개발할 수 없다.

 - 다형성 만으로는 구현 객체를 변경할 때 클라이언트 코드도 함께 변경된다.

 - 다형성 만으로는 OCP, DIP를 지킬 수 없다.

 - 뭔가가 더 필요하다...


다시 스프링으로

 - 스프링은 다음 기술로 다형성 + OCP, DIP를 가능하게 지원

   : DI(Dependency Injection) : 의존관계, 의존성 주입

   : DI 컨테이너 제공

 - 클라이언트 코드의 변경없이 기능 확장

 - 쉽게 부품을 교체하듯이 개발

 

스프링 없던 시절

 - OCP, DIP 원칙을 지키면서 개발을 해보니, 너무 할일이 많아 프레임워크로 만들어버림

 - 순수하게 자바로 OCP, DIP 원칙들을 지키면서 개발을 해보면, 스프링 프레임 워크를 만들게 된다( DI컨테이너 )

 - 이제 스프링이 왜 만들어졌는지 코드로 이해해보자.

 

정리 

 - 모든 설계에 역할과 구현을 분리하자.

 - 클라이언트가 사용할 인터페이스만 만들어두고, 구현체는 유연하게 변경할 수 있도록 만드는 것이 좋은 객체지향설계

 - 이상적으로는 모든 설계에 인터페이스를 부여하는게 좋지만 문제가 생김

실무 고민

 - 인터페이스를 도입하면 추상화라는 비용이 발생함

 - 기능을 확장할 가능성이 없다면, 구현 클래스를 직접 사용하고, 향후에 인터페이스로 확장하는 것을 고려하는것이 좋다.

 

책추천

 객체지향 책 추천 : 객체지향의 사실과 오해

 스프링 책 추천 : 토비의 스프링

 JPA 책 추천 : 자바 ORM 표준 JPA 프로그래밍

반응형