SEB_BE_43 / 23.02.02 회고

rse·2023년 2월 3일
0

코드스테이츠_BE_43

목록 보기
27/65

오늘

  • spring 프레임워크

프레임워크란?

소프트웨어의 구체적인 부분에 해당하는 설계와 구현을 재사용이 가능하게끔 일련의 협업화된 형태로 클래스들을 제공하는 것. 이라고 정의한다.

한마디로 틀 이라고 생각하면 더 쉽다.

정해진 틀 안에서 정해진 규정에 맞게 사용할 수 있는 것이다.

장점

  • 효율적으로 코드 작성 가능
    아무것도 없는 상황에서 코드를 작성하는것과, 기본 구조가 만들어져 있는 상황에서 코드를 작성하는것은 많은 차이가 있다. 또, 개발자가 애플리케이션의 핵심 로직을 개발하는 것에 집중할 수 있도록 해준다.
  • 정해진 규약이 있어 애플리케이션을 효율적으로 관리할 수 있다.
    우리가 사용하는 Framework의 규약에 맞게 코드를 작성하기 때문에, 유지보수가 필요한 경우 더 빠르고 쉽게 문제점을 파악해 수정할 수 있다.
    동시에 내가 작업했던 코드를 다른사람이 수정할 경우에도 이미 Framework에 규약에 맞게 작성된 코드이기 떄문에, 빠르게 코드를 파악하고 수정하기 용이하다.

단점

  • 내가 사용하고자 하는 Framework에 대한 학습이 필요.
  • 자유롭고 유연한 개발이 어렵다.
    Framework에 규약을 벗어나기 어려움.

Framework 와 library

Framework와 library의 차이점은 제어권을 누가 가지고 있느냐 이다.

Library란 애플리케이션을 개발하는 데 사용되는 일련의 데이터 및 프로그래밍 코드를 말한다.

Library는 개발자가 짜 놓은 코드내에서 필요한 기능이 있으면 해당 라이브러리를 호출해서 사용 할 수 있다. 한마디로 애플리케이션 흐름의 주도권이 개발자에게 있는 것.

Framework는 메서드 내의 코드를 개발자가 짜놓으면 Framework가 알아서 애플리케이션의 흐름을 만들어낸다. 그러므로 이 경우는 주도권이 Framework에게 있다.

그렇기에 Framework은 개발자가 애플리케이션의 핵심 로직을 개발하는 것에 집중할 수 있도록 해준다.

Spring Framework 특징

이 그림은 spring 삼각형 이라는 유명한 그림이다.

POJO (plain old java object)

POJO 프로그래밍이란 POJO를 이용해서 프로그래밍 코드를 작성하는 것을 의미한다.
하지만 단순히 순수 자바 객체만을 사용해서 프로그래밍 코드를 작성한다라고 해서 POJO 프로그래밍이라고 볼 수는 없다.

밑에 규칙을 보자.

  • Java나 Java의 스펙(사양)에 정의된 것 이외에는 다른 기술이나 규약에 얽매이지 않아야 한다.

위의 코드를 보면 자바에서 제공하는 기능만 사용하여 getter, setter만 가지고 있는 코드이다. 해당 클래스의 코드에서는 Java 언어 이외에 특정한 기술에 종속되어 있지 않은 순수한 객체이기 때문에 POJO라고 부를 수 있다.

  • 특정 환경에 종속적이지 않아야 한다.
public class MessageForm extends ActionForm{ 
	
	String message;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
	
}

public class MessageAction extends Action{ 
	
	public ActionForward execute(ActionMapping mapping, ActionForm form,
		HttpServletRequest request, HttpServletResponse response)
        throws Exception {
		
		MessageForm messageForm = (MessageForm) form;
		messageForm .setMessage("Hello World");
		
		return mapping.findForward("success");
	}
	
}

출처 : 코드스테이츠

ActionForm 클래스는 과거에 Struts라는 웹 프레임워크에서 지원하는 클래스이다.
첫번째 클래스에서는 Struts라는 기술을 사용하기 위해서 ActionForm을 상속하고 있다.
두번째 클래스 역시 Struts 기술의 Action 클래스를 상속 받고있다.

이렇게 특정 기술을 상속 해서 코드를 작성하게 되면 나중에 애플리케이션의 요구사항이 변경되서 다른 기술로 변경하려면 Struts의 클래스를 명시적으로 사용했던 부분을 전부 다 일일이 제거하거나 수정해야 할 것이다.

또, 자바는 다중 상속을 지원하지 않기 때문에 ‘extends’ 키워드를 사용해서 한 번 상속을 하게되면 상위 클래스를 상속받아서 하위 클래스를 확장하는 객체지향 설계 기법을 적용하기 어려워지게 된다.

한마디로 특정 환경에 맞춰서 쓰는 것이 아니고, 어디서든 쓸 수 있게 만들어야 한다는 것이다.

그리고 이건 객체지향 설계 5가지 기본 원칙(SOLID) 중 하나인 S.

  • 단일 책임 원칙 (Single responsibility principle)
    과 연관되어있다.

Spring 은 POJO 프로그래밍을 지향하는 프레임워크다.

그리고 최대한 다른 환경이나 기술에 종속적이지 않도록 하기 위한 POJO 프로그래밍 코드를 작성하기 위해 Spring 에서는 IoC/DI, AOP, PSA 세가지 기술을 지원하고 있다.

지원하는 기술.

IoC (Inversion of Control)

아까 Framework와 Library의 차이점으로 주도권을 설명했었다.

Library는 개발자에게, Framework는 Framework에게 주도권이 있다.

이 주도권이 뒤바뀐 것을 IoC라고 한다. = 제어역전

위 코드를 보면 main() 메서드 안에서 출력이 실행되고 있는 것을 알 수 있다.

실행 순서를 보면 main() 호출 -> system 클래스 -> static 멤버 변수인 out의 println()을 호출한다.

이 코드는 개발자가 작성한 코드를 순차적으로 실행하고 있다. 이것이 일반적인 애플리케이션의 제어 흐름이다.

그런데 이걸 웹으로 생각해보자

서블릿 기반의 애플리케이션을 웹에서 실행한다고 한다면

아까 콘솔 애플리케이션은 main()을 실행시키고 실행이 종료된다. 그런데 웹 사이트는 계속 사용하기 때문에 종료되서는 안될 것이다.

main() 메서드처럼 애플리케이션이 시작되는 지점을 엔트리 포인트(Entry point)라고 한다.

서블릿 컨테이너의 경우, 클라이언트의 요청이 들어올 때마다 서블릿 컨테이너 로직(service() 메서드) 이 서블릿을 직접 실행시켜 주기 때문에 main() 이 필요하지 않다.

이 경우 서블릿 컨테이너가 서블릿을 제어하고 있기 때문에 주도권이 서블릿 컨테이너에게 있다.

Spring에서는 IoC를 적용하기 위해 DI를 사용한다.

한마디로 정리하자면 IoC(제어 역전) = 결과 / DI는 IoC(제어 역전)을 만들기 위한 수단(방법).

그리고 IoC를 사용하면 무언가를 수정하려고 할 때 필요한 부분만 찾아서 수정하기 편하다. 고 한다.

DI (Dependency Injection)

Dependency Injection = 해석하면 의존성 주입.

예방접종하러 병원에 가면 주사를 통해 우리 몸에 약물을 주입한다.
라고 생각하면 된다.

의존성 주입이란
객체간의 의존성을 말한다.

만약 A,B 두개의 클래스를 만들고 A에서 B의 메서드 기능을 사용해야한다면
A 클래스내에서 B 클래스에 구현되어있는 메서드를 호출해줘야 할 것이다.

이럴경우 A 클래스는 B 클래스에 의존한다. 라고 한다.

여기서 B 클래스의 메서드가 A 클래스에서 빠진다면 (의존하지 못한다면) A 클래스는 로직이 완성되지 않기 때문에 A 가 B에게 의존하는게 맞다.

아래 코드를 보자.

위에 두 클래스가 카페 주문을 위한 클래스라고 한다면 MenuController가 클라이언트에게 요청을 받는 Endpoint 역할을 하고 있고, MenuService 클래스가 MenuController 클래스가 전달 받은 클라이언트의 요청을 처리하는 역할이라고 나눌 수 있다.

그리고 MenuController 클래스가 MenuService 클래스에게 의존하고 있다는 것을 알 수 있다.

클라이언트 측면에서 서버의 엔드포인트(Endpoint)란 
클라이언트가 서버의 자원(리소스, Resource)을 이용하기 위한 끝 지점을 의미.

위 코드를 설명하자면 Menu를 보기위해 MenuController 클래스에서 MenuService 클래스의 객체를 생성한 후 MenuService 클래스의 메서드를 호출해주고 있다.

이렇게 클래스 끼리는 사용하고자 하는 클래스의 객체를 생성해서 참조하게 되면 의존 관계가 성립된다.

아직 의존 관계만 성립됬지 의존성 주입은 하지 않았다.

아래 코드로 의존성 주입을 보자.

아까 위에서는 MenuService의 기능을 사용하기 위해 MenuController에서 MenuService의 객체를 new 키워드로 직접 생성한 반면에 여기서는 MenuController 생성자로 MenuService의 객체를 전달 받고 있는 것을 확인할 수 있다.

이처럼 생성자를 통해서 어떤 클래스의 객체를 전달 받는 것을 ‘의존성 주입’ 이라고 한다.
생성자의 파라미터로 객체를 전달하는 것을 외부에서 객체를 주입한다라고 표현을 하는 것.

또 다른 예시로 베스킨라빈스 파인트 아이스크림을 들어보자.

위 코드로 보면 현재 파인트에는 바닐라, 핑크스푼 비긴즈, 루나 치즈케이크 세 가지 맛이 담겨 있다. 그런데 위 코드를 실제상황에 맞춰서 생각하면 파인트를 사러 갔는데 이미 맛이 다 채워져서 나오는 것이다. 내가 다른 맛이 먹고 싶어도, 한가지 맛으로 가득 채우고 싶어도 그러지 못한다는 의미이다.

그리고 지금 Pint 클래스 생성과 동시에 아이스크림도 new를 통해 같이 생성되고 주입되고 있다.

만약 내가 아몬드 봉봉, 쿠키앤크림, 이상한나라의 솜사탕으로 맛을 변경하고 싶다면 바닐라, 핑크스푼 비긴즈, 루나 치즈케이크를 다 변경해줘야 할 것이다. 그리고 밑에 생성자도.

그런식으로 하나하나 변경해야하는게 예제에서는 하나지만 여러개가 된다면 아마 많이 힘들 것이다.

또 제일 중요한 문제점이 있는데 Pint 클래스에 아이스크림 맛 3가지가 각각 객체로 있다.

그런데 여기서 한가지의 맛이라도 사라진다면 Pint 클래스는 완성이 되지 않기에 동작을 하지 않을 것이다. 즉 Pint는 각각의 아이스크림 객체에 의존중 이라는 것을 알 수 있다.

SOLID의 원칙 중 D = DIP(Dependency Inversion Principle) 의존 역전 원칙 을 보면
상위 레벨 모듈은 하위 레벨 모듈에 의존하지 않는다. 둘 다 추상화에 의존해야 한다.

라고 적혀 있다. 이게 무슨 말인지 다시 베라 예제를 보자.

Pint는 고수준 모듈이다. 그런데 바닐라, 핑크스푼 비긴즈, 루나 치즈케이크는 저수준 모듈인데 현재 고수준 Pint 모듈이 저수준에 의존하고 있다. 그렇기에 맛을 변경하려면 Pint의 코드를 변경해야 하므로 저수준 모듈의 위해 고수준의 모듈이 변경 되야 된다는 것이다.

그럼 DI를 적용하면 어떨까

코드를 보면 Icecream 이라는 인터페이스를 구현해서 Icecream 안에 값을 넣어주고 있다.

그리고 Pint 클래스도 더 이상 저수준 모듈에 의존하고 있지 않다. main에서 맛을 담아준 뒤 Pint 클래스 객체를 생성 하면서 Icecream의 객체 favorite 을 전달인자로 받고 있다.

즉 Pint가 Icecream 이라는 인터페이스에 의존중인것. 그리고 저수준모듈인 각각의 아이스크림들도 고수준의 Icecream 인터페이스에 의존 중인 것을 알 수 있다.

Pint는 3가지의 아이스크림을 담고 섞는 기능(역할)이 있다면 Icecream 이라는 인터페이스는 각각의 모든 아이스크림을 담을 수 있다. 즉 Pint보다 기능(역할)이 더 많다고 볼 수 있겠다.
Icecream 이라는 인터페이스가 Pint보다 고수준이라고 볼 수 있음.

아까 DI를 적용하기 전에는 고수준이 저수준에게 의존 중이였지만 지금은 제어 역전이 되어 고수준이 저수준을 받아주고 있다.

또 다른 예시로는 2+1 행사가 있다. (이건 같이 부트캠프 듣는 수강생이 말하셨던 예시인데 참고하면 좋을 것 같아서...) 2+1 == 파인트 , 행사 물품 == 아이스크림 으로 생각하면 되겠다.

AOP (Aspect Oriented Programming)

애플리케이션의 핵심 업무 로직에서 로깅이나 보안, 트랜잭션 같은 공통 기능 로직들을 분리하는 것

공통 관심 사항(Cross-cutting concern)

애플리케이션을 개발하다보면 애플리케이션 전반에 걸쳐 공통적으로 사용되는 기능들이 있는데, 이러한 공통 기능들에 대한 관심사를 말한다.

핵심 관심 사항(Core concern)

애플리케이션의 주목적을 달성하기 위한 핵심 로직을 말한다.

핵심 관심 사항에 반대되는 개념으로 공통 관심 사항을 부가적인 관심사항 이라고도 한다.

커피 주문을 위한 애플리케이션이라면,

커피 전문점의 주인이 고객에게 제공하는 커피 메뉴를 구성하기 위해 커피 종류를 등록하는 것과 고객이 마시고 싶은 커피를 주문하는 기능은 애플리케이션의 핵심 관심 사항에 해당된다.

하지만 커피 주문 애플리케이션에 아무나 접속하지 못하도록 제한하는 애플리케이션 보안에 대한 부분은 애플리케이션 전반에 공통적으로 적용되는 기능이기 때문에 공통 관심 사항에 해당된다.

AOP의 특징

  • 코드의 간결성 유지
  • 객체 지향 설계 원칙에 맞는 코드 구현
  • 코드의 재사용

PSA(Portable Service Abstraction)

객체지향 프로그래밍 세계에서 어떤 클래스의 본질적인 특성만을 추출해서 일반화 하는것을 추상화(Abstraction)라고 한다.

클라이언트가 추상화 된 상위 클래스를 일관되게 바라보며 하위 클래스의 기능을 사용하는 것이 바로 일관된 서비스 추상화(PSA)의 기본 개념.

애플리케이션에서 특정 서비스를 이용할 때, 서비스의 기능을 접근하는 방식 자체를 일관되게 유지하면서 기술 자체를 유연하게 사용할 수 있도록 하는 것을 PSA(일관된 서비스 추상화)라고 한다.

이 기능이 필요한 이유는 어떤 서비스를 이용하기 위한 접근 방식을 일관된 방식으로 유지함으로써 애플리케이션에서 사용하는 기술이 변경되더라도 최소한의 변경만으로 변경된 요구 사항을 반영하기 위함.

profile
기록을 합시다

0개의 댓글