Skip to content

Latest commit

 

History

History
188 lines (129 loc) · 23.6 KB

토비의-스프링.md

File metadata and controls

188 lines (129 loc) · 23.6 KB

토비의 스프링

책 사진

  1. Vol.1 스프링의 이해와 원리
    1. 스프링이란 무엇인가?
    2. 스프링의 성공 요인
    3. 스프링의 학습과 활용의 어려움
    4. 오브젝트와 의존관계
  2. Vol.2 스프링의 기술과 선택

어떻게 스프링을 공부해야하는가?-백기선님

레퍼런스를 읽고, 토비의 스프링을 쫙 읽는다는 것은 가성비가 안나옴.

스프링의 핵심적인 부분을 아는 것이 먼저임.

  • 스프링 삼각형(IoC 컨테이너, AOP, 추상화 게층:PSA(MVC, JDBC, Resource, O/X M, O/J M)
    • IoC 컨테이너: Bean, Application Context, Bean Factory를 써서 Bean Definition, Bean Lookup 하는 방법 예제 코드 짜보기
      • 깊게 빠져들지 말자: Bean의 Scope이 Singleton이고 Prototype이고 까지는 좋다. Bean의 Custom한 Scope를 만드는 방법.
        Bean의 Id와 name이 있다는 건 안다. 근데 Bean의 Id와 name의 차이는 뭐고 Controller에 등록될 때, Bean의 name으로 등록이 되고, Bean의 Alias는 뭐고...
    • AOP: 간단하게 예제코드를 짜볼 것, A라는 서비스에 hello 라는 메서드가 있는데 그 메시지 앞과 뒤에 뭔가 출력을 해주는데 hello를 건들지 않고 출력을 하도록 한다. 간단하게 Aspect를 정의해서.
      • 이게 Proxy로 만들어져 있는데... AOP 안에서 자기가 자기 메서드를 호출하면 Proxy가 적용이 안되는데... 여기까지는 좋다. 그걸 해결하는 방법에 대해서 알 필요는 전혀 없다.

체력, 의지, 시간이 남아돌면 무식하게 공부해도 된다. 레퍼런스 매일매일 보면서 코딩, 블로깅하고... 그런 시간을 대학생때 보냈다.

원하는 목표에 준하는 정도로 보는 것이 좋다.

샘플 코드 학습 -> 그 다음 레퍼런스나 토비의 스프링을 학습한다.(필요한 부분을 공부한다.)

Vol.1 스프링의 이해와 원리

스프링이란 무엇인가?

스프링은 자바 엔터프라이즈 애플리케이션 개발에 사용되는 애플리케이션 프레임워크다. 애플리케이션 프레임워크는 개발을 빠르고 효율적으로 할 수 있도록, 애플리케이션의 바탕이 되는 틀과, 공통 프로그래밍 모델, 기술 API등을 제공해준다.

애플리케이션의 기본 틀 - 스프링 컨테이너

스프링은 스프링 컨테이너 또는 애플리케이션 컨텍스트라고 불리는 스프링 런타임 엔진을 제공한다. 스프링 컨테이너는 설정정보를 참고로 해서 애플리케이션을 구성하는 오브젝트를 생성하고 관리한다.
스프링 컨테이너는 독립적으로 동작할 수도 있지만, 보통 웹 모듈에서 동작하는 서비스나 서블릿으로 등록해서 사용한다.

스프링을 사용하려면 먼저 스프링 컨테이너를 다루는 방법과 스프링 컨테이너가 애플리케이션 오브젝트를 이용할 수 있도록 설정정보를 작성하는 방법을 알아야 한다.

공통 프로그래밍 모델(스프링 삼각형) - IoC/DI, 서비스 추상화, AOP

  1. IoC/DI: 오브젝트의 생명주기와 의존관계에 대한 프로그래밍 모델. 스프링은 유연하고 확장성이 뛰어난 코드를 만들 수 있게 도와주는 객체지향 설계 원칙과 디자인 패턴의 핵심 원리를 담고 있는 IoC/DI를 프레임워크의 근간으로 삼고 있다.
    스프링 프레임워크에서 동작하는 코드는 IoC/DI 방식을 따라서 작성돼야 스프링이 제공하는 가치를 제대로 누릴 수 있다.
  2. 서비스 추상화(PSA): 스프링을 사용하면 환경이나 서버, 특정 기술에 종속되지 않고 이식성이 뛰어나며 유연한 애플리케이션을 만들 수 있는데, 이를 가능하게 해주는 것이 바로 서비스 추상화다. 구체적인 기술과 환경에 종속되지 않도록 유연한 추상계층을 두는 방법이다.
  3. AOP: 애플리케이션 코드에 산재해서 나타나는 부가적인 기능을 독립적으로 모듈화하는 프로그래밍 모델이다.

스프링을 사용해서 애플리케이션을 개발하는 개발자라면 이 세 가지 핵심 프로그래밍 모델을 잘 이해해야 하고 자유롭게 응용할 수 있어야 한다.

기술 API

스프링은 방대한 양의 기술 API를 제공한다. 스프링이 제공하는 API와 지원 기술은 모두 스프링의 프로그래밍 모델에 따라 작성되어 있기 때문에, 이를 가져다 쓰는 것만으로도 스프링의 프로그래밍 모델을 코드에 자연스럽게 적용할 수 있다.

스프링을 사용한다는 것은 바로 이 세 가지(스프링 컨테이너, 스프링 삼각형, 기술 API)를 적극적으로 활용해서 애플리케이션을 개발한다는 뜻이다. 클래스는 스프링 컨테이너 위에서 오브젝트로 만들어져 동작하게 만들고, 코든느 스프링의 프로그래밍 모델을 따라서 작성하고, 엔터프라이즈 기술을 사용할 때는 스프링이 제공하는 기술 API와 서비스를 활용하도록 해주면 된다.

스프링의 성공 요인

스프링은 견고하고 건전한 자바와 엔터프라이즈 개발의 핵심 가치에 충실했기 때문에 성공할 수 있었다. 스프링을 사용하는 개발자들이 스프링을 통해 얻게 되는 두 가지 중요한 가치가 있다면 그것은 단숨함과 유연성이다.

단순함(simplicity)

스프링은 EJB라는 강한 권위를 가졌던 표준 기술을 비판하면서 등장했다. 스프링이 지향하는 것은 목적을 이룰 수 있는 가장 단순하고 명쾌한 접근 방법이다. 스프링은 객체지향 언어의 장점을 다시 개발자들이 살릴 수 있도록 도와주는 도구다. 그래서 스프링이 강력히 주장한느 것은 가장 단순한 객체지향적인 개발 모델인 POJO 프로그래밍이다.

유연성(flexiblity)

스프링은 유연성과 확장성이 매우 뛰어나다. 스프링의 유연성으로 인해 스프링은 다른 많은 프레임워크와 편리하게 접목돼서 사용될 수 있다. 스프링은 프레임워크를 위한 프레임워크 또는 여러 프레임워크를 함께 사용하게 해주는 접착 프레임워크라고도 불린다.

스프링은 스스로 발전하는 프레임워크다. 스프링 개발 철학 중 하나는 "항상 프레임워크 기반의 접근 방법을 사용하라"이다. 스프링 기능의 대부분은 핵심 기능을 확장해서 발전시킨 결과물이다. 스프링은 개발자들에게 스프링을 확장해서 사용하도록 권장한다. 프레임워크를 확장해서 사용한 뒤 시간이 지남에 따라 경험하게 되는 버전 호환성 문제가 스프링에서는 거의 없다. 스프링을 제대로 사용하려면 스프링을 필요에 맞게 확장해서 자신만의 프레임워클를 만들어서 사용할 줄 알아야 한다.

스프링 학습과 활용의 어려움

스프링의 가치를 제대로 누리며 사용하려면 스프링을 제대로 공부해야 한다. 스프링은 특히 프레임워크가 지향하는 가치와 프로그래밍 모델을 충분히 이해하지 못하고는 제대로 활용할 수 없다. 반면에 한번 스프링의 원리와 개발 사상을 확실히 이해하고 나면 그 이후에 새로운 기능이 아무리 많이 추가되더라도 빠르고 쉽게 학습하고 사용할 수 있다.

스프링을 효과적으로 익히는 방법(3단계)

  • 스프링의 핵심 가치와 원리에 대한 이해: 스프링의 핵심 가치를 이해하고, 스프링 스스로가 그 가치를 어떻게 적용해서 만들어져 있는지를 이해하는 것이다. 스프링에는 가장 중요한 핵심 가치와 그것이 가능하도록 도와주는 세 가지 핵심 기술이 있다. 또한, 스프링이 강조하는 중요한 프로그래밍 모델이 있다. 이를 자세히 공부하고 스프링을 일관된 방식으로 이해할 수 있는 눈을 갖는 것이 첫 번째 단계다.
  • 스프링의 기술에 대한 지식과 선택 기준 정립: 스프링의 기본 원리를 확실하게 이해하고 나면 스프링이 이를 어떻게 다양한 방법으로 확장하고 적용했는지 살펴볼 차례다. 스프링은 어떤 분야와 기술 환경에도 적용 가능하도록 기술 영역별로 매우 폭넓은 접근 방법을 제공한다. 스프링이 제공하는 방법 중에서 어떤 것을 선택할 것인지 등의 문제는 개발자의 몫이다. 단지 이런 고민을 피하려고 남들이 만들어놓은 예제를 가져다가 생각 없이 사용하는 일은 피해야 한다.
    먼저 스프링이 제공하는 기술의 종류와 접근 방법에는 어떤 것이 있는지 충분히 살펴보고, 선택의 기준을 마련해서 그때그때 상황에 맞는 최선의 기술과 접근 방법을 선택할 수 있어야 한다.
  • 스프링의 적용과 확장: 다양한 기술을 어떻게 실제 애플리케이션 개발에 어떤 식으로 적용해야 하는지를 공부해야 한다. 또한 스프링에서 제공하는 기능을 그대로 사용하는 것 외에도 그것을 확장하거나 추상화해서 사용하는 방법을 알아야 한다. 스프링을 효과적으로 사용하는 기업과 개발팀에서는 스프링을 기반으로 프레임워크를 만들어서 사용한다. 이것은 매우 자연스럽고 바람직한 방법이다.
    세 번째 단계는 이렇게 스프링을 실전에서 사용하는 데 필요한 응용 방법과 확장 방법을 공부하는 것이다.

프레임워크의 가장 중요한 목적은 개발자가 일정한 틀을 따라 효과적으로 애플리케이션을 개발하도록 돕는 것이다. 따라서 프레임워크를 잘 이해하려면 프레임워크를 사용했을 때 애플리케이션 코드가 어떻게 만들어지는지 자세히 살펴화야 한다.

스프링을 성공적으로 학습했는지를 확인할 수 있는 좋은 방법: 스프링을 공부하고 적용한 이후에 자신이 좀 더 나은 개발자가 되었는가 확인해보는 것이다. 스프링을 사용하고 나서 자신의 코드가 좀 더 깔끔하고 단순하면서 객체지향 원칙에 충실하게 작성됐는지, 생산성과 품질이 더 나아졌는지 스스로 질문해보자. 이전보다 더 많은 테스트 코드를 작성하고 있고, 유연하고 확장이 손쉬운 애플리케이션이 만들어지고 있는지도 점검해보자. 무엇보다도 스프링을 사용하면서 개발이 좀 더 즐거워졌는가 스스로에게 물어보면 좋겠다. 스프링을 공부하고 적용했지만 스프링의 사용법에 조금 익숙해진 것을 빼면 더 나아진게 없다고 느낀다면 스프링을 잘못 공부한 것일지도 모른다.

오브젝트와 의존관계

스프링은 자바를 기반으로 한 기술이다. 스프링이 자바에서 가장 중요하게 가치를 두는 것은 바로 객체지향 프로그래밍이 가능한 언어라는 점이다. 객체지향 기술의 진정한 가치를 회복시키고, 그로부터 객체지향 프로그래밍이 제공하는 폭넓은 혜택을 누릴 수 있도록 기본으로 돌아가자는 것이 바로 스프링의 핵심 철학이다.

그래서 스프링이 가장 관심을 많이 두는 대상은 오브젝트다. 스프링을 이해하려면 먼저 오브젝트에 깊은 관심을 가져야 한다.
애플리케이션에서 오브젝트가 생성되고 다른 오브젝트와 관게를 맺고, 사용되고, 소멸하기까지의 전 과정을 진지하게 생각해볼 필요가 있다.
더 나아가서 오브젝트는 어떻게 설계돼야 하는지, 어떤 단위로 만들어지며 어떤 과정을 통해 자신의 존재를 드러내고 등장해야 하는지에 대해서도 살펴봐야 한다.

결국 오브젝트에 대한 관심은 오브젝트의 기술적인 특징과 사용 방법을 넘어서 오브젝트의 설계로 발전하게 된다. 객체지향 설계의 기초와 원칙을 비롯해서, 다양한 목적을 위해 재활용 가능한 설계 방법인 디자인 패턴, 좀 더 깔끔한 구조가 되도록 지속적으로 개선해나가는 리팩토링, 오브젝트가 기대한 대로 동작하고 있는지를 효과적으로 검증하는 데 쓰이는 단위 테스트와 같은 오브젝트 설계와 구현에 관한 여러가지 응용 기술과 지식이 요구된다.

스프링은 오브젝트를 어떻게 효과적으로 설계하고 구현하고, 사용하고, 이를 개선해나갈 것인가에 대한 명쾌한 기준을 마련해준다.

스프링은 객체지향의 베스트 프랙티스를 평범한 개발자도 자연스럽고 손쉽게 적용할 수 있도록 프레임워크 형태로 제공한다.

스프링을 제일 처음 익힐 때에는 스프링이 관심을 갖는 대상인 오브젝트의 설계와 구현, 동작원리에 더 집중하기를 바란다.

테스트 코드를 작성하는 가장 간단한 방법: main()을 이용한 테스트 코드 작성

만들어진 코드의 기능을 검증하고자 할 때 사용할 수 있는 가장 간단한 방법은 오브젝트 스스로 자신을 검증하도록 만들어주는 것이다. 이를 셀프 테스트라고 한다.

하지만 이렇게 만들어진 코드는 잘 동작하지만, 문제점이 아주 많은 코드다. 그럼 이 코드를 멋진 스프링 스타일의 코드로 개선해보는 작업을 할 것이다.
생각해보자. 잘 동작하는 코드를 굳이 수정하고 개선해야하는 이유는 뭘까? 그렇게 DAO 코드를 개선했을 때의 장점은 무엇일까? 그런 장점들이 당장에, 또는 미래에 주는 유익은 또 무엇인가? 또, 객체지향 설계의 원칙과는 무슨 상관이 있을까? 이 DAO를 개선하는 경우와 그대로 사용하는 경우, 스프링을 사용하는 개발에서 무슨 차이가 있을까?

스프링을 공부한다는 건 바로 이런 문제 제기와 의문에 대한 답을 찾아나가는 과정이다. 최종 결론은 스프링을 이용해 개발자 스스로 만들어내는 것이지, 스프링이 덥석 줄 수 있는게 아니기 때문이다.

DAO의 분리

관심사의 분리

개발자가 객체를 설계할 때 가장 염두에 둬야 할 사항은 바로 미래의 변화를 어떻게 대비할 것인가이다. 변화는 먼 미래에만 일어나는 게 아니다. 며칠 내에, 때론 몇 시간 후에 변화에 대한 요구가 갑자기 발생할 수 있다.
객체지향 설계와 프로그래밍이 이전의 절차적 프로그래밍 패러다임에 비해 초기에 좀 더 많은, 번거로운 작업을 요구하는 이유는 객체지향 기술 자체가 지니는, 변화에 효과적으로 대처할 수 있다는 기술적인 특징 때문이다.
객체지향은 흔히 실세계를 최대한 가깝게 모델링 할 수 있기 때문에 의미가 있다 여겨진다. 하지만 그보다는 객체지향 기술이 만들어내는 가상의 추상세계 자체를 효과적으로 구성할 수 있고, 이를 자유롭고 편리하게 변경, 발전, 확장시킬 수 있다는 데 더 의미가 있다.

미래를 준비하는 데 있어 가장 중요한 과제는 변화에 어떻게 대비할 것인가이다. 가장 좋은 대책은 변화의 폭을 최소한으로 줄여주는 것이다.
그러면 어떻게 변경이 일어날 때 필요한 작업을 최소화하고, 그 변경이 다른 곳에 문제를 일으키지 않게 할 수 있었을까? 그것은 분리와 확장을 고려한 설계가 있었기 때문이다.

먼저 분리에 대해 생각해보자.
모든 변경과 발전은 한 번에 한 가지 관심사항에 집중에 일어난다.
문제는, 변화는 대체로 집중된 한 가지 관심에 대해 일어나지만 그에 따른 작업은 한 곳에 집중되지 않는 경우가 많다는 점이다. 변화가 한 번에 한가지 관심에 집중돼서 일어난다면, 우리가 준비해야 할 일은 한 가지 관심이 한 군데에 집중되게 하는 것이다. 즉 관심이 같은 것끼리는 모으고, 관심이 다른 것은 따로 떨어져 있게 하는 것이다.

프로그래밍의 기초 개념 중에 관심사의 분리(Seperation of Concerns) 라는 게 있다. 이를 객체지향에 적용해보면, 관심이 같은 것 끼리는 하나의 객체 안으로 또는 친한 객체로 모이게 하고, 관심이 다른 것은 가능한 한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것이라고 생각할 수 있다.

리팩토링
리팩토링은 기존의 코드를 외부의 동작방식에는 변화 없이 내부 구조를 변경해서 재구성하는 작업 또는 기술을 말한다. 리팩토링을 하면 코드 내부의 설계가 개선되어 코드를 이해하기가 더 편해지고, 변화에 효율적으로 대응할 수 있다. 결국 생산성은 올라가고, 코드의 품질은 높아지며, 유지보수하기 용이해지고, 견고하면서도 유연한 제품을 개발할 수 있다. 리팩토링이 절실히 필요한 코드의 특징을 나쁜 냄새라고 부르기도 한다. 대표적으로, 중복된 코드는 매우 흔하게 발견되는 나쁜 냄새다. 이런 코드는 적절한 리팩토링 방법을 적용해 나쁜 냄새를 제거해줘야 한다.

리팩토링은 개발자가 직관적으로 수행할 수 있긴 하지만, 본격적으로 적용하자면 학습과 훈련이 필요하다. 나쁜 냄새에는 어떤 종류가 있고, 그에 따른 적절한 리팩토링 방법은 무엇인지 알아보고, 충분한 연습을 해두면 도움이 된다. 리팩토링 책으로 공부하는 것을 추천한다.

디자인 패턴
디자인 패턴은 소프트웨어 설계 시 특정 상황에서 자주 만나는 문제를 해결하기 위해 사용할 수 있는 재사용 가능한 솔루션을 말한다. 디자인 패턴은 주로 객체지향 설계에 관한 것이고, 대부분 객체지향적 설계 원칙을 이용해 문제를 해결한다. 패턴의 설계 구조를 보면 대부분 비슷한데, 그 이유는 객체지향적인 설계로부터 문제를 해결하기 위해 적용할 수 있는 확장성 추구 방법이 대부분 두 가지 구조로 정리되기 때문이다. 하나는 클래스 상속이고 다른 하나는 오브젝트 합성이다.

패턴에서 가장 중요한 것은 각 패턴의 핵심이 담긴 목적 또는 의도다. 패턴을 적용할 상황, 해결해야 할 문제, 솔루션의 구조와 각 요소의 역할과 함께 핵심 의도가 무엇인지를 기억해둬야 한다. 자바를 사용하는 개발자라면 반드시 공부해야 할 주제다. GoF의 디자인 패턴 혹은 Head First Design Patterns를 추천한다. GoF는 최고의 책이니 다른 책을 먼저 공부하더라도 언젠가 한 번은 꼭 읽어보기 바란다.

템플릿 메소드 패턴
상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법이다. 변하지 않는 기능은 슈퍼클래스에 만들어두고 자주 변경되며 확장할 기능은 서브클래스에서 만들도록 한다. 슈퍼클래스에서는 미리 추상 메소드 또는 오버라이드 가능한 메소드를 정의해두고 이를 활용해 코드의 기본 알고리즘을 담고 있는 템플릿 메소드를 만든다. 슈퍼클래스에서 디폴트 기능을 정의해두거나 비워뒀다가 서브클래스에서 선택적으로 오버라이드 할 수 있도록 만들어둔 메소드를 훅(hook) 메소드라고 한다. 서브클래스에서는 추상 메소드를 구현하거나, 훅 메소드를 오버라이드 하는 방법을 통해 기능의 일부를 확장한다.

public abstract class Super {
  // 기본 알고리즘 골격을 담은 메소드를 템플릿 메소드라 부른다. 템플릿 메소드는 서브클래스에서 오버라이드 하거나 구현할 메소드를 사용한다.
  public void templateMethod() {
    // 기본 알고리즘 코드
    hookMethod();
    abstractMethod();
    ...
  }

  protected void hookMethod() { } // 선택적으로 오버라이드 가능한 훅 메소드

  public abstrace void abstractMethod(); // 서브클래스에서 반드시 구현해야하는 추상 메소드
}

// 슈퍼클래스의 메소드를 오버라이드 하거나 구현해서 기능을 확장한다. 다양한 확장 클래스를 만들 수 있다.
public class Sub1 extends Super {
  @Override
  protected void hookMethod() {
    ...
  }

  @Override
  public void abstractMethod() {
    ...
  }
}

팩토리 메소드 패턴
팩토리 메소드 패턴도 템플릿 메소드 패턴과 마찬가지로 상속을 통해 기능을 확장하게 하는 패턴이다. 그래서 구조도 비슷하다.
슈퍼클래스 코드에서는 서브클래스에서 구현할 메소드를 호출해서 필요한 타입의 오브젝트를 가져와 사용한다. 이 메소드는 주로 인터페이스 타입으로 오브젝트를 리턴하므로 서브클래스에서 정확히 어떤 클래스의 오브젝트를 만들어 리턴할지는 슈퍼클래스에서는 알지 못한다. 사실 관심도 없다.
서브클래스에서 오브젝트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드를 팩토리 메소드라고 하고, 이 방식을 통해 오브젝트 생성 방법을 나머지 로직, 즉 슈퍼클래스의 기본 코드에서 독립시키는 방법을 팩토리 메소드 패턴이라고 한다.

자바에서는 종종 오브젝트를 생성하는 기능을 가진 메소드를 일반적으로 팩토리 메소드라고 부르기도 한다. 이때 말하는 팩토리 메소드와 팩토리 메소드 패턴의 팩토리 메소드는 의미가 다르므로 혼동하지 않도록 주의해야 한다.

결국 위 방법은 상속을 사용했다는 단점이 있다. 상속 자체는 간단해 보이고 사용하기도 편리하게 느껴지지만 사실 많은 한계점이 있다.
만약 이미 UserDao가 다른 목적을 위해 상속을 사용하고 있다면 어쩔 것인가? 자바는 클래스의 다중상속을 허용하지 않는다. 단지, 커넥션 객체를 가져오는 방법을 분리하기 위해 상속구조로 만들어버리면, 후에 다른 목적으로 UserDao에 상속을 적용하기 힘들다.

또 다른 문제는 상속을 통한 상하위 클래스의 관계는 생각보다 밀접하다는 점이다. 상속을 통해 관심이 다른 기능을 분리하고, 필요에 따라 다양한 변신이 가능하도록 확장성도 줬지만 여전히 상속관계는 두 가지 다른 관심사에 대해 긴밀한 결합을 허용한다. 서브클래스는 슈퍼클래스의 기능을 직접 사용할 수 있다. 그래서 슈퍼클래스의 내부의 변경이 있을 때, 모든 서브클래스를 함께 수정하거나 다시 개발해야 할 수도 있다. 그런 변화에 따른 불편을 주지 않기 위해 슈퍼클래스가 더 이상 변화하지 않도록 제약을 가해야 할지도 모른다.

확장된 기능인 DB 커넥션을 연결하는 코드를 다른 DAO 클래스에 적용할 수 없다는 것도 큰 단점이다. 만약 UserDao 외의 DAO 클래스들이 계속 만들어진다면 그때는 상속을 통해서 만들어진 getConnection()의 구현 코드가 매 DAO 클래스마다 중복해서 나타나는 심각한 문제가 발생할 것이다.

Vol.2 스프링의 기술과 선택