본문 바로가기
Study/Java Spring Boot

[Spring] 핵심 원리 1 객체지향 설계와 스프링(SOLID)

본 글은 김영한님의 강의 내용을 바탕으로 정리한 글입니다.

 

스프링 핵심 원리 - 기본편 - 인프런 | 학습 페이지

지식을 나누면 반드시 나에게 돌아옵니다. 인프런을 통해 나의 지식에 가치를 부여하세요....

www.inflearn.com

1. 스프링의 배경

EJB (Enterprise JavaBeans) 에 등장하여 자바가 거대해지고 발전함에 따라  

각종 인터페이스에 의존적으로 개발되고 어렵고 난해한 코드와 느린 런타임, 가독성이 최악에 치닫게 되어  

POJO(Plain Old Java Object, 간단한 원래 자바 오브젝트로 돌아가자) 라는 말이 나왔다.

로드 존슨, 

EJB를 비판한 실무 개발자 로드존슨J2EE라는 코드를 만들게되고 이것이 Spring의 기본 코드가 된다.

개빈 킹이라는 하이버네이트 ORM을 만들면서  EJB 엔티티 빈 기술을 대체하고,

JPA(Java Persistence API)의 새로운 표준을 정의하게 된다.

 

EJB는 자바의 혹한기, 겨울이라고 일컷고, J2EE의 개발로 자바의 Spring (봄)이 도래했다며 스프링이라는 이름이 붙었다.

이 둘이, 현재의 자바 백엔드 개발에 센세이션을 일으킨 사람들이다.

 

2. Spring이란

스프링은 자바언어를 이용한 웹 개발에 사용되는 기술로

필수적으로 Spring FrameworkSpring Boot를 이용해서 개발되며, 

추가적으로 Spring JPA, Spring Data(DB연동기술), Security(보안), Session(세션기술), Rest Docs(API 문서도구), Batch(배치수행), Cloud 등이 있다.

 

장점

스프링부트는 단독으로 Tomcat을 내장하여 웹 서버의 기능을 가지고 쉽게 웹을 개발하고 서비스할 수 있다.

DataBase에 편리하게 접근하며, 쉽게 API서버를 만들수 있다.

전자정부 프레임워크에 사용되고, 마이크로 서비스에도 활용되지만 진짜 핵심장점은 아래와 같다.

 

핵심

객체 지향 언어!

EJB 가 가지는 단점을 커버하며 겨울을 깨고 등장한 기술이다. 

객체지향이 기존의 종속적인 개발의 틀을 깨고, 독립적이고 명확한 설계를 가능케 하는 기술이다.

 

 

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

스프링을 올바로 이해하고 사용하기 위해서는 핵심점인 객체지향에 대해서 올바로 이해하고 작성되야 한다.

객체 지향의 장점은 추상화, 캡슐화, 상속성, 다형성을 가진다.

코드를 명령어의 시각이 아닌, 객체(Object)들의 모임과 관계임을 파악하고,

객체들을 유연하고 변경하기 쉽게 작성하는 능력이 중요하다.

 

아래 예를 살펴보자.

예시 1)

운전자가 자동차를 가질 수 있고, 이 두 객체는 각각 다른 역할을 가진다.

좋은 구현은 이때에 자동차와 운전자의 역할이 독립적으로 구현되야하며,

운전자가 다른 차를 소유하는 경우에도 확장가능하도록 설계해야하는 것이다.

 

이를 프로그램적으로 바라보면,

확장성을 가지는 자동차는 인터페이스에 해당되며, K3, 아반떼, 테슬라 등이 구현 객체에 해당되는것이다.

객체를 설계할때, 관계와 역할을 먼저 생각하고 설계하여 코딩하는 과정이 필요하다.

 

변화가 있을 부분을 인터페이스로 개발하여 대체될수 있도록 다형성을 고려해서 설계해야한다.

 

예시 2) 

클라이언트의 요청으로 회원데이터를 저장(Save)하는 기능을 가지는 MemberRepository 인터페이스가 있다.

MemberService는 해당 인터페이스의 인스턴스를 접근할때.

해당 인스턴스가 메모리에 저장하도록 구현 (MemoryMemberRepository)했다가,

추후 Jdbc를 이용해서 DB에 접속하도록 추가 클래스(JdbcMemberRepository)가 개발되더라도,

상속받는 인터페이스가 같기때문에 쉽게 연결시켜줄수 있다.

이러한 객체지향적 특성이 다형성이며, 이러한 관계가 고려되어 작성될때, 

유연하고 확장가능한 스프링만에 핵심적인 강점을 면밀히 보일수가 있다.

 

스프링에서는 IoC(제어의 역전), DI(의존성 주입)로 다형성을 활용해서 레고블럭을 조립하듯이 편리하게 다룰 수 있다.

 

4. 좋은 객체 지향 설계 5가지 원칙 - SOLID ★★★

클린코드 저서로 유명한 로버트 마틴이 제시한 좋은 객체 지향설계의 5가지 원칙이다.

SOLID 는 면접에 자주 나오는 질문이기도 한데, 아래와 같은 내용에 앞글자를 딴것이다.

모두가 응집도가 높고, 결합도가 낮은 프로그램으로 설계하라는 내용과 상통한다.

 

1) SRP: 단일 책임 원칙(Single Responsibility Principle)

한 부품(클래스, 함수 등)하나의 책임만 지닌다.

하나의 기능이 변경될때, 해당 역할을 지니는 클래스만 변경되야 한다. 

클래스 내부의 함수끼리 강한 결함도를 가지면, 하나의 기능이 변경되는데에도 많은 수정과 유지보수 비용이 든다.

그렇기에 책임을 분리시킬 필요가 있다.

 

2) OCP: 개방-폐쇄 원칙 (Open/Closed Principle)

확장에는 열려있으나, 변경에는 닫혀있어야 한다. -> 인터페이스를 활용하여 구현하면 좋다.

하나의 기능을 추가할 때, 기존 코드는 변경(Closed)없이 기능을 수정하거나 추가(Open)할 수 있도록 만들어야 한다.

클래스나 메소드 단위별로 추가되어도 기존코드와의 결합은 없어야 한다는 이야기다.

 

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

MIT 컴퓨터 사이언스 교수인 리스코프가 제안한 설계 원칙이다.

이는 객체 지향 프로그래밍에서 부모, 자식 인스터스를 치환해도 문제가 없어야 한다는 것을 의미한다.

상속 관계에서는 일반화 관계(IS-A)가 성립해야 한다.

일반화 관계에 있다는 것은 일관성이 있다는 것이다.

 

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

한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 

하나의 일반적인 인터페이스 보다는, 여러 개의 구체적인 인터페이스가 낫다.

이는 다시 말해서, 자신이 사용하지 않는 기능(인터페이스)에는 영향을 받지 말아야 한다는 의미이다. 

인터페이스 분리 원칙을 통해 시스템의 내부 의존성을 약화시켜 리팩토링, 수정, 재배포를 쉽게 할 수 있다. 

 

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

의존 관계를 맺을 때, 변화하기 쉬운것 보단 변화하기 어려운 것에 의존해야 한다는 원칙이다.

여기서 말하는 변화하기 쉬운것이란 구체적인 것을 말하고, 변화하기 어려운 것이란 추상적인 것을 말한다.

객체 지향적인 관점에서 보자면 변화하기 쉬운것이란 구체화 된 클래스를 의미하고,

변화하기 어려운 것은 추상클래스나 인터페이스를 의미한다.

따라서 DIP를 만족한다는것은 

상속은 구체적인 클래스보다 인터페이스나 추상 클래스와 관계를 맺는다는 것을 의미한다.


김영한님의 강의에서 OCP를 보여주시는 예제 개발하다보면 DIP에 어긋나는 흐름이 있었다.

결론적으로는 스프링에 DI 컨테이너를 통해 구체화된 인스턴스가 아닌 인터페이스와 의존관계를 정리시켰지만.

어떤 방법으로 싱글톤의 환경에서 DIP를 고수하시는지 지금부터 살펴보자!

 

+ PS 많은 이들의 이야기로는 실무에서 인터페이스를 자주 사용되지 않는다고 한다.

인터페이스는 결국 추상화를 구현하는 개발비용이 발생하기 때문에

개념을 정립하고 이해하는데에 집중하여 나중에 리팩터링을 통해 필요시 도입하기도 한다고 한다.