계층형 아키텍쳐의 문제

위 그림은 일반적인 3 계층 아키텍처를 표현한다.

  1. 웹 계층에서 요청을 받아 도메인 or 비즈니스 계층에 있는 서비스로 요청을 보낸다.
  2. 서비스에서는 비즈니스 로직을 수행하고, 도메인 엔티티의 현재 상태를 조회하거나 변경하기 위해 영속성 계층의 컴포넌트를 호출한다.

이 계층형 아키텍처의 문제가 무엇인지 정리한다.

데이터베이스 주도 설계 유도

계층형 아키텍처의 토대는 데이터베이스이다.
웹 계층은 도메인 계층에, 도메인 계층은 영속성 계층에 의존하기 때문이다.
계층형 아키텍처에서는 데이터베이스의 구조를 먼저 생각하고, 이를 토대로 도메인 로직을 구현한다.

ORM 프레임워크를 계층형 아키텍처와 결합하면, 영속성 계층과 도메인 계층 간 강한 결합이 생긴다.
위와 같이, ORM 에 의해 관리되는 엔티티들은 영속성 계층에 둔다.
계층은 아래 방향으로만 접근 가능해서, 도메인 계층에서는 엔티티에 접근 가능하고 엔티티를 사용한다.
서비스는 영속성 모델을 비즈니스 모델처럼 사용하게 되는 것이다.

지름길을 택하기 쉬움

Read more

Code Smell

언제 리팩토링이 필요한지 정리한다.

Mysterious Name

함수, 모듈, 변수, 클래스 등은 이름만 봐도 무슨 일을 하고, 어떻게 사용해야하는지 명확히 알수 있어야한다.
이름만 잘 지어도, 문맥을 파악하는 시간을 줄일 수 있다.

Duplicated Code

코드가 중복되면, 볼 때마다 차이가 있는지 살펴봐야하는 부담이 있다.
만약 그 중 하나를 변경을 하게되면 다른 비슷한 코드들을 모두 살펴봐야한다.

Long Function

함수가 길 수록, 이해하기 어렵다.
짧은 함수를 읽는 사람 입장에서는 함수가 하는 일을 파악하기 위해 왔다 갔다 해야하는 비용이 든다.
하지만, 함수 이름을 잘 지어두면 본문 코드를 볼 이유가 없다.
적극적으로 함수를 쪼개고, 함수 이름은 동작 방식이 아니라 “의도” 가 드러나게 짓자.

Long Parameter List

매개 변수 목록이 길어지면, 이해하기 어려울 때가 많다.

Global Data

Read more

Mockk

Mockk 는 “mocking library for Kotlin” 이다. 간단한 사용법을 정리해보자.

Install

우선, 시작하기 앞서 dependency 를 추가해보자.

for gradle:

1
testImplementation("io.mockk:mockk:{version}")

for maven:

1
2
3
4
5
6
<dependency>
<groupId>io.mockk</groupId>
<artifactId>mockk</artifactId>
<version>{version}</version>
<scope>test</scope>
</dependency>

Simple Example

mockk 를 활용한 간단한 테스트 코드를 작성해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
fun `sum`() {
// given
val additionCalculator = mockk<AdditionCalculator>()
every { additionCalculator.calculate(1, 3) } returns 4

// when
val result = additionCalculator.calculate(1, 3)

// then
verify { additionCalculator.calculate(1, 3) }
assertEquals(4, result)
}
Read more

Spring Data REST

Spring Data repositories 위에서 hypermedia-driven REST web service 를 쉽게 만들 수 있는 Spring Data REST 에 대해 정리해보자.

Intro

multi-domain object 시스템을 위한 REST 웹 서비스를 구현하는 것은, 지루하고 반복적인 작업이고 많은 boilerplate code 를 생성한다.
Spring Data REST 는 Spring Data repositories 위에 구축되고 자동으로 REST resource 를 노출한다.

Getting started

Dependency

Spring Boot project 에 Spring Data Rest 의존성을 추가해보자.

1
2
3
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-rest")
}

URI

default 로, Spring Data REST 는 root URI 인 ‘/‘ 에 REST resources 를 제공한다.
application.properties 에 아래와 같이 base URI 를 변경할 수 있다.

1
spring.data.rest.basePath=/api
Read more

WireMock

외부 API 를 테스트할 때 유용한 도구인 WireMock 에 대해 알아보자.
WireMock 은 HTTP mock server 이다. 핵심적인 기능으로,

  • 특정 요청 (stubbing) 에 대해 미리 준비된 응답을 할 수 있고,
  • 유입된 요청을 capture 하여 verification 이 가능하다.

Setup

wiremock 을 사용하기 위해 필요한 dependency 를 추가하자.

Basic Usage

JUnit5 를 기준으로 테스트해보자. @WireMockTest 로 간단히 테스트 가능하다.
WireMockRuntimeInfo 를 통해서는, port number 나 base URL 등의 정보를 얻을 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WireMockTest
class WireMockTest {

@Test
fun `wiremock basic usage`(wmRuntimeInfo: WireMockRuntimeInfo) {
// given
stubFor(get("/static-dsl").willReturn(ok()))

// when
val testRestTemplate = TestRestTemplate()
val response: ResponseEntity<String> = testRestTemplate.getForEntity(
"${wmRuntimeInfo.httpBaseUrl}/static-dsl",
String::class.java
)

// then
assertEquals(200, response.statusCodeValue)
}
}

Stub

Read more