새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.
Controller,Service 구조
목표 D-day : 32 일
오늘은 Controller, Service의 역할은 어디까지인지 학습하려고합니다.
학습하게 된 계기는 제 회사의 로직은 컨트롤러에 모두 있고, 비즈니스 로직이 SQLMapper에 섞여있는 구조입니다.
위 방식에 익숙하다보니 유지보수와 확장성이 떨어진다는 것을 자주 느끼게됩니다.
유지보수와 확장성을 높이기 위해서 각 레이어의 역할을 학습해보려고 합니다.
학습 목표
- API,UI 그리고 Smart UI 정의하기
- Controller 정의 및 역할
- Service 정의 및 역할
API,UI 그리고 Smart UI
API는 애플리케이션 프로그래밍 인터페이스로 서버의 기능을 사용하기 위해 제공되는 인터페이스를 의미합니다.
API 규칙에 맞게 요청을 보내면 정상 응답과 오류에 대한 응답을 받을 수 있습니다.
UI는 사용자 인터페이스로 사용자의 입출력을 받아 관련된 API를 호출하여 사용자에게 결과를 보여주는 화면입니다.
서버에서 API는 결국 클라이언트(FE 개발자)나 다른 서버에 보여주는 인터페이스입니다.
API와 UI는 결국 사용자와 상호작용을 하기 위해 제공되는 인터페이스를 말합니다.
스프링 부트에서 Controller
는 API를 만드는 컴포넌트입니다.
그러면 Controller
는 클라이언트에게 상호작용을 하는 컴포넌트의 역할을 책임만 지면됩니다.
백엔드 개발자에게 API는 개발자의 UI라고 할 수 있습니다.
Smart UI
도메인 주도 설계(에릭 에반스)는 책에서 스마트 UI는 다음과 같은 특징을 가진다고 했습니다.
- 스마트 UI는 데이터 입출력을 UI 레벨에서 처리합니다.
- 스마트 UI는 비즈니스 로직도 UI 레벨에서 처리합니다.
- 스마트 UI는 데이터베이스와 통신하는 코드도 UI 레벨에서 처리합니다.
개발에는 정답이 없지만 오답에 가까운 패턴이 있습니다. 안티패턴이라고 하며 이렇게 개발하면 유지보수나 확장성 관점에서 좋지 못하다
라고 합니다. 스마트 UI가 안티패턴에 속합니다.
스프링 개발자에게 UI를 만드는 방법은 컨트롤러이고, 컨트롤러내에 코드에 1~3번의 코드가 있다면 안티패턴입니다.
예를 들어
@PostMapping("/board")
public ApiResponse<BoardResponse> create(@RequestBody BoardCreateRequest boardRequest){
// 우리 서비스 회원인지 검증
// API 호출자의 정보를 작성자로 입력
// 게시물의 작성 시간에 현재 시간을 입력
// 게시물의 최신 게시물 시간을 현재 시간으로 변경
}
해당 컨트롤러는 API 요청을 처리하기 위한 모든 로직이 포함되어있습니다.
핸들러는 어떤 값을 검증하고, 입력하고, 변경하고, 저장합니다.
이러한 로직은 분명 비즈니스 로직입니다.
일반적으로 UI는 사용자의 입출력을 위한 창구로만 사용되어야 합니다.
왜 문제일까?
스마트 컨트롤러에는 컨트롤러에 맞지 않은 과한 책임이 부과되어있습니다.
모든 코드가 오롯이 기능이 동작하게 만드는데 초점이 맞춰 작성되어 있습니다.
이렇게 된다면 API는 사실상 어떤 스크립트(명령어 집합)를 실행하고 응답하는 수준이 됩니다.
이러한 코드는 확장성도 떨어지며, 유지보수성도 떨어집니다. 그래서 안티패턴입니다.
회원 검증 로직은 다른 컨트롤러에서 사용할 수 있고, 게시판을 작성하는 로직도 다른 컨트롤러에서 사용할 수 있습니다.
이 로직을 분리하지 않다보니 모든 컨트롤러에 중복되어 작성되고 각 컨트롤러에 맞게 변형되다보니 어느 순간부터는 회원 검증 로직이 다 달라지거나 특정 로직이 추가되어 유지보수와 확장하기 어려워집니다.
추가로 스마트 컨트롤러 코드로 작성하면 객체지향 코드가 아닌 절차지향 프로그래밍에 가까워 집니다.
관련된 함수만 호출하고 값을 저장하고, 객체끼리 통신하는 과정이 사라지게 됩니다.
Smart UI의 장점
이 방식을 사용하면 빠르게 개발할 수 있습니다. 그래서 생산성이 높습니다.
모든 코드가 하나의 메서드에 집중돼 있으므로 이해하기도 쉽고 작성하기도 쉽습니다.
따라서 애플리케이션의 흥망성쇠가 감이오지 않은 경우 빠르게 개발하고 결과를 확인한 후 의사결정을 하려한다면 이 접근 방식이 유용합니다.
MVP(Minimum Viable Product)
최소 기능 제품을 만들 때 유용합니다.
Smart UI의 실무에 대한 생각
처음 기획된 프로젝트의 결과를 빠르게 기획자나 매니저에게 보여줘야하는 경우가 많습니다.
개발도 빠르고 어떤 개발자가 오더라도 위에서 아래로 코드를 읽기 때문에 가독성도 좋습니다.
중간에 요청사항이 오더라도 코드가 길지 않기 때문에 수정하기도 편합니다.
하지만, 프로젝트가 종료가 되고 유지보수를 해야하는 상황이 오면 이제 문제가 되는 경우가 많습니다.
컨트롤러에 3천줄, 5천줄이 되는 코드가 발생하고 여기에 중복되는 코드 발생하고 비슷한 기능이지만 특정 검증을 제외하려고 그대로 복사해서 특정 코드만 지우거나 추가하는 방식으로 만들고 유지보수하다보니 두 달만 지나도 이제는 유지보수와 확장을 하기 어려운 복잡한 코드가 됩니다..
코드가 처음에 짧다고 Smart UI로 만들고, 어느정도 개발이 완료될 때 나누지 않는다면 시기를 놓치게 된다고 생각합니다.
컨트롤러는 어디까지 책임져야할까
그러면 컨트롤러(API) 컴포넌트는 사용자의 입력을 받고, 관련된 서비스 로직을 선택해 실행할지 결정하면 됩니다.
- API 호출 방식을 정의합니다.(엔드 포인트를 정의)
- 어떤 비즈니스 로직을 실행할 것인지 결정한다.
- API 호출 결과를 어떤 포멧(
json,xml
)으로 응답할지 정의합니다.
번외 UI의 책임
API와 UI는 사용자의 요청을 받고 관련된 기능을 선택하는 역할이라고 할 수 있습니다.
그러면 UI는 어떤 책임이 있는지 확인한다면 좀더 이해가 잘 될거같습니다.
-
데이터 입력 및 검증을 합니다.
사용자가 입력한 데이터를 수집하고, 즉시 피드백을 제공하여 올바른 형식인지 확인합니다.
유효성 검사를 초기 단계에서 수행하여 서버로의 불필요한 요청을 줄입니다.
-
사용자 경험 관리를 합니다.
사용자가 쉽게 정보를 이해하고, 기능을 사용할 수 있도록 일관된 UI를 제공해야합니다.
-
서버와의 통신을 합니다.
필요한 경우 서버에 요청을 보내고, 데이터를 받아와 화면에 표시합니다. 서버의 요청을 보내는 역할을 수행합니다.
-
데이터 렌더링을 합니다.
서버에서 받은 데이터를 적절히 렌더링 하여 사용자가 쉽게 정보를 확인할 수 있도록 합니다.
-
에러 처리 및 예외 처리를 합니다.
서버에서 오류가 발생하거나 네트워크 문제가 발생했을 때 사용자에게 적절한 피드백을 제공합니다. 에러 메세지를 사용자 친화적으로 표시하여 문제를 이해할 수 있도록 합니다.
-
보안 처리를 합니다. 사용자의 데이터를 안전하게 처리하여, 보안상의 위협에 대비해야합니다.
-
상태 유지 및 저장을 합니다.
사용자의 상태를 로컬에 저장하거나, 필요시 사용자의 상태를 유지하여 더 쉽게 작업을 이어갈 수 있도록 합니다.
###
댓글남기기