2023. 3. 28. 21:34ㆍJAVA Back-End/Spring
스프링 프레임워크
- 핵심 기술
스프링 DI 컨테이너, AOP, 이벤트 , 등 - 웹 기술
스프링 mvc , 스프링 webflux - 데이터 접근 기술
트랜잭션 처리, JDBC, ORM지원, XML지원 - 기술 통합
캐시 , 이메일, 원격접근, 스케줄링 - 테스트
스프링 기반 테스트 지원 - 언어
자바, 코틀린, 그루비
스프링 부트 프레임워크
최근 스프링부트를 사용해 스프링 프레임워크의 기술들을 편리하게 사용. 최근엔 기본으로 많이 사용한다
- 단독으로 실행할 수 있는 스프링 애플리케이션을 쉽게 생성
- tomcat같은 웹서버를 내장함. 그래서 별도 웹 서버를 설치할 필요 없다.
- 손쉬운 빌드 구성을 위한 starter 종속성 제공
- 스프링과 3rd parth(외부) 라이브러리 자동 구성
- 관례에 의한 간결한 설정
- '스프링'은 스프링부트 스프링 등을 포함한 스프링 생태계로 볼수도 있고 스프링 DI 컨테이너 기술로 볼 수도 있다.
스프링의 핵심 개념
이걸 왜 만들었을까?
이 기술의 핵심 컨셉은?
- 스프링은 자바 기반의 프레임워크 => 객체 지향 언어
- 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크
객체 지향 프로그래밍
- 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위. 즉 객체들의 모임 으로 파악하려고 한 것.
생성된 각 객체는 메시지를 주고받고 데이터를 처리할 수 있음! (협력의 관계) - 객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들어서 대규모 소프트웨어 개발에 많이 사용됨.
- 유연하고, 변경이 용이
- 레고 블럭 조립하듯
- 부품을 갈아끼우듯
- 컴포넌트를 쉽고 유연하게 변경하면서 개발
- 유연하고, 변경이 용이
다형성
- 진짜 다형성이 중요함. 실제 세계와 객체 지향을 1대1로 매칭하지 말아봅시다.
- 그래도 실세계의 비유로 이해하기에는 좋음.
- 역할 과 구현 으로 세상을 구분해보자.
- 예시1 - 자동차와 운전자(역할)
자동차 모델이나 브랜드가 바껴도 (아반떼(구현) -> 볼보xc60(구현)) 운전자의 "역할"에서 운전은 할 수 있습니다.
자동차 "역할"(인터페이스)에 대해서 다 만들어서! 운전자(클라이언트)는 역할을 계속해서 수행할 수 있습니다.
심지어 기름 자동차에서 수소자동차가 나올지라도!!
자동차의 역할을 여려 개 구현하는 게 중요한 게 아닙니다!! - 예시2 - 뮤지컬 로미오와 줄리엣 공연
로미오 역할(장동건(구현) , 원빈(구현), 무명배우1(구현))
줄리엣 역할(김태희(구현) , 송혜교(구현), 무명배우2(구현))
역할들은 있고 대본과 연기를 숙지해서 어떤 배우로도 대체 가능. 역할을 대체 가능해야한다. 급작스런 일로 변경할 일이 있으니
내부를 몰라도 됩니다.
다형성의 실세계 비유
- 운전자 - 자동차
- 공연 역할
- 키보드, 마우스
역할과 구현을 분리
"역할"과 "구현"으로 구분하면 세상이 단순해지고, 유연해지며 변경도 편리해 집니다.
- 클라이언트(운전자, 배우)는 대상(자동차, 로미오)의 역할(인터페이스)만 알면 됨!!
- 클라이언트(운전자, 배우)는 구현 대상의 내부 구조가 어떻게 변경되는 지 몰라도 됨!!
- 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다!
- 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않는다.(k3 -> 테슬라 차로 바꿔도 상관 x)
- 자바 언어의 다형성을 활용
- 역할 : 인터페이스
- 구현 : 인터페이스를 구현한 class, 구현 객체
- 객체를 설계할 때 "역할"과 "구현"을 명확하게 분리
- 객체 설계시 역할(인터페이스)를 먼저 부여하고, 그 역할을 수행하는 구현 객체 만듦
핵심은 구현보다 인터페이스가 먼저다! 역할이 먼저!
객체의 협력이라는 관계부터 생각
- 혼자 있는 객체는..없다..
- 클라이언트: 요청하는 이, 서버: 응답하는 이
- 수~많은 객체 클라이언트와 객체 서버는 서로 협력 관계를 가집니다
다형성의 본질
- 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있습니다
- 다형성의 본질은 "협력"이라는 객체 사이의 관계에서 시작해야합니다
- 인터페이스를 구현한 객체 인스턴스를 "실행 시점"에 "유연"하게 "변경"할 수 있습니다
역할과 구현을 분리하는 것의 한계
- 역할(인터페이스) 자체가 변하면, 클라이언트/서버 모두 큰.. 변경이 발생합니다 ㅜ
- 자동차를 비행기로 변경..?
- 대본 자체가 변경..?
- USB 인터페이스가 변경..?
이러한 이유로 클라 서버에 큰 부담이 가므로 인터페이스를 안 변하게 안정적으로 설계하는 것이 정말 중요!!
스프링과 객체 지향
- 스프링은 다형성을 극대화해서 이용
- 다형성이 제일 중요!
- 스프링에서 제어의 역전(IoC), 의존성 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원합니다!
좋은 객체 지향 설계 5원칙 (SOLID)
클린 코드로 유명한 '로버트 마틴'이 좋은 객체지향 설계 5원칙
SRP (Single Responsibility Principle): 단일 책임 원칙
- 한 클래스는 한 책임만 가진다
- 마틴이 주장하는 건 그런데 하나의 책임이 좀 모호.. 클 수도 있고 작을 수 있다.
- 중요한 기준은 "변경" 이다. 변경 시 파급효과가 적으면 SRP를 잘 따른것!
- ex) UI변경, 객체 생성과 사용을 분리
OCP (Open/Closed Principle) : 개방-폐쇄 원칙
- 가장 중요한 원칙!
- 확장에는 열여 있으나 변경에는 닫혀 있어야 함!
- 인터페이스가 있고, 그거에 대한 새 기능을 구현하면 확장에 열여 있고 변경하는 것은 아니다. -> 결국 다형성을 이용한 역할과 구현의 분리!
- 분명 다형성을 사용했지만 OCP원칙을 지킬 수 없다... -> 이걸 해결해주기 위해 IoC, DI를 스프링에서 해결해 줄 수 있다!
LSP (Liskov substitution principle) : 리스코프 치환 원칙
- 어떤 인터페이스가 있는데, 그거에 대한 구현체가 있음.
- 즉, 다형성에서 하위 클래스(구현체)는 인터페이스(역할) 규약을 다 지켜야 함!
- 자동차 인터페이스의 엑셀은 앞으로 가라는 기능, 뒤로 가게 구현하면 LSP 위반! 느리더라도 앞으로 가야함. (뒤로 가게 하더라도 컴파일 오류는 나지 않음..)
ISP (Interface segregation principle) : 인터페이스 분리 원칙
- 자동차 인터페이스 -> 운전 인터페이스 , 정비 인터페이스로 분리 (자동차 인터페이스에 통으로 넣지 않고)
- 사용자 클라이언트 -> 은전자 클라이언트, 정비사 클라이언트로 분리 가능
- 이렇게 하면 정비 인터페이스 자체가 변해도, 운전자 클라이언트에 영향을 주지 않음
DIP (Dependency inversion principle) : 의존관계 역전 원칙
프로그래머는 "추상화에 의존해야지, 구체화에 의전하면 안된다!" 의존성 주입은 이 원칙을 따르는 방법 중 하나
쉽게 이야기하면 구현 클래스에 의존하지 말고! 인터페이스에 의존하라.
MemberService가 MemberRepository 인터페이스만 바라보고 MemoryMemberRepository나 JdbcRepository는 몰라야함!
DIP 위반
// MemberService 클라이언트가 구현 클래스를 직접 선택. (인터페이스가 아닌) class MemberService { // MemberRepository만 의존해야하는데 MemoryMemberRepository도 의존. // 구현체에 의존하면 안된다.인터페이스에만 의존해야함. MemberRepository m = new MemoryMemberRepository() }
역할(인터페이스)에 의존하게 하는 것. 객체 세상도 클아이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있음
정리
- 객체 지향 핵심은 다형성
- 하지만, 다형성 만으로는 쉽게 부품 갈아끼우듯 개발하긴 무리무리..
- 다형성 만으로는 OCP, DIP를 지킬 수 없다..
- MemberRepository 인터페이스만으로 코드가 어케 돌아가누ㅜㅜ NPE(Null Point Exceptin) 터지겠지.. 구현체가 있어야 돌아갈 거 아녀..
- 뭔가가 더 필요하다!
다형성에 대한 이야기와 SOLID라는 객체지향 원칙을 정리해봤는데 OCP, DIP 원칙을 지키며 개발하니 할 일이 너무 많음.. 그래서 프레임워크로 만들었습니다.
순수 자바로 OCP, DIP 지키며 개발하면 결국 스프링(정확히 DI컨테이너)프레임워크를 쓰게됨
- 모든 설계에 역할/구현을 분리하자
- 애플리케이션 설계도 공연 설계 하듯 배역만 만들고, 배우는 언제든 유연하게 변경할 수 있게 만드는게 좋은 객체 지향 설계이다.
- 이상적으로는 모든 설계에 싹 다 인터페이스를 부여하자
- 예로 할인 정책 기획 추가 되면, 할인 정책 (0원 할인) 인터페이스 부터 설계하고 구현체 개발하면 된다.
- 실무 고민)
- 인터페이스를 도입하면 '추상화' 비용이 발생하긴 함..
- 인터페이스 보고 구현 클래스(Impl) 까지 까봐야하는 뎁스가 커지긴 함.
- 따라서 기능 확장할 가능성이 없다면. 구체 클래스 직접 사용. 향후 꼭! 필요할 경우엔 -> 리팩토링 과정으로 인터페이스 추가해서 사용
[reference]
- 인프런 / 스프링 핵심 원리 - 기본 (김영한)
'JAVA Back-End > Spring ' 카테고리의 다른 글
[Spring] Spring MVC (0) | 2019.06.08 |
---|---|
[Spring] Spring JDBC (0) | 2019.06.07 |
[Spring] xml파일을 이용한 Spring설정 (0) | 2019.05.18 |
[Spring] IoC / DI 컨테이너 (0) | 2019.05.16 |
[Spring] Spring Framework? (0) | 2019.05.16 |