-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
712 additions
and
723 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,39 @@ | ||
--- | ||
authors: puleugo | ||
date: Sat, 10 Aug 2024 12:00:53 +0900 | ||
date: Sun, 11 Aug 2024 12:00:07 +0900 | ||
--- | ||
|
||
# 만개의 테스트를 작성하지 마라. | ||
# 티스토리에 마진 넣는법 | ||
|
||
## 서론 | ||
|
||
* 어떤 코드가 유닛 테스트를 작성할 가치가 있는 코드인지 판별하는 방법에 대해 이야기합니다. | ||
* (어그로 죄송합니다.) | ||
티스토리는 기본적으로 css에 포함된 마진을 무시합니다. 그래서 대부분의 블로거들이 줄바꿈을 광클떄려놔서 가독성이 떨어집니다. | ||
본 글에서는 마진 제거 css인 tt\_article\_useless\_p\_margin 속성을 제거하려고합니다. | ||
|
||
## 가치있는 테스트란? | ||
## 문제 분석 | ||
|
||
단순히 테스트가 많이 작성되어 있는 것이 결코 좋은게 아닙니다. 여러분이 만약 프라모델을 조립한다고 가정했을 때, 핵심만 잘 정리된 설명서 와 별로 중요하지 않은 내용이 포함되어 있는 설명서 중 어떤 문서가 읽기 편하신가요? 아마도 무조건 전자일겁니다. | ||
대충 네트워크 및 동작 흐름 보면 이렇습니다. | ||
|
||
테스트 또한 문서이기에 **핵심만 명확하게 작성되어 있는 것이 훨씬 좋습니다**. | ||
1. 게시글 API 호출 (text/html) | ||
2. useLessPMargin.css API 호출 | ||
3. tistory에서 보내줄 html과 css를 로드 완료 | ||
4. CSSOM 마운트 | ||
5. DOM 마운트 | ||
|
||
## 테스트의 가치란? | ||
## 방법 | ||
|
||
그렇다면 우리가 **테스트의 우선순위가 떨어지는 코드**에는 무엇이 있을까요? 첫번째로 <u>너무 간단한 로직들</u>도 있을거에요. 굳이 문서를 읽지 않아도 이해할 수 있으니까요. 두번째로는 <u>의존객체가 많은 객체</u>들은 테스트하기에 너무 어려울거에요. 실제 객체를 사용할 수 없어서 Test Double을 고려해야하는 경우도 있을거고 의존하는 객체를 생성할 때 너무 많은 값을 필요로해서 ObjectMother를 필요로도 할거에요. | ||
jQeury를 사용하여 DOM 마운트 시 CSSOM을 통해 최종적으로 추가된 tt\_article\_useless\_p\_margin 클래스를 제거하였습니다. | ||
|
||
그럼 반대로 **테스트 우선순위가 높은 코드**는 무엇이 있을까요? 바로 <u>도메인 로직, 이해하기 어려운 코드, 지나치게 복잡한 코드들</u>입니다. (도메인 로직에 대해서는 다음 글에서 설명합니다.) | ||
``` | ||
<body> | ||
<!-- ... 기존 블로그 코드 --> | ||
이를 시각화하면 다음과 같습니다. | ||
|
||
![](https://blog.kakaocdn.net/dn/bfSsSB/btsI0zEZgrb/8I4ydnhESNn1FuW5GjDk11/img.png) | ||
|
||
음.. 도메인로직, 간단한 코드, 의존객체가 많고 간단한 코드는 어떻게 테스트를 작성해야할 지 알거같아요. 그런데 복잡한 코드는 테스트할 가치가 높으면서도 테스트하기 어려운데 어떻게 해야할까요. | ||
|
||
이 부분은 기존 설계가 잘못되어 있을 가능성이 높습니다. 아마도 테스트하고자 하는 객체가 너무 많은 책임을 가지고 있을 가능성이 높습니다. (웹 서비스에서는 하나의 서비스에 영속성 로직, 도메인 로직, 비즈니스 로직을 다 때려박아놨을 가능성이 높습니다.) | ||
|
||
![](https://blog.kakaocdn.net/dn/DO7oc/btsI1oWViTn/9VQRotJrE2WVczqAKEy5i0/img.gif) | ||
|
||
이런 경우에는 위와 같은 방식으로 도메인 모델이나 알고리즘 혹은 간단한 코드 쪽으로 이동하도록 리팩터링하는 것을 권장합니다. | ||
|
||
## 결론 | ||
|
||
* 단위 테스트 시에는 가성비를 생각해야한다. | ||
* 테스트의 가성비는 도메인에서의 가치와 코드의 복잡도를 보고 판단할 수 있다. | ||
|
||
### 추천 글 | ||
|
||
* 도메인 로직과 비즈니스 로직의 차이를 설명할 수 없다면 아래 글을 읽어보세요! | ||
[\[번역\] 방금 당신이 작성한 코드는 도메인 로직인가?](https://puleugo.tistory.com/204) | ||
* 테스트에 대한 확신과 가지고 싶다면 이 서적을 추천합니다! | ||
[유닛테스트 by 블라디미르 코리코프](https://link.coupang.com/a/bM9mhx) | ||
|
||
--- | ||
|
||
*이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.* | ||
<!-- jQuery 설치 --> | ||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> | ||
<!-- 지들 멋대로 margin 삭제해버리는 css 제거 --> | ||
<script type="text/javascript"> | ||
$("div").removeClass("tt_article_useless_p_margin") | ||
</script> | ||
</body> | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,85 @@ | ||
--- | ||
authors: puleugo | ||
date: Sun, 11 Aug 2024 12:00:07 +0900 | ||
date: Mon, 12 Aug 2024 12:00:24 +0900 | ||
--- | ||
|
||
# 티스토리에 마진 넣는법 | ||
# [번역] 방금 당신이 작성한 코드는 도메인 로직인가? | What is domain logic? | ||
|
||
## 서론 | ||
|
||
티스토리는 기본적으로 css에 포함된 마진을 무시합니다. 그래서 대부분의 블로거들이 줄바꿈을 광클떄려놔서 가독성이 떨어집니다. | ||
본 글에서는 마진 제거 css인 tt\_article\_useless\_p\_margin 속성을 제거하려고합니다. | ||
* 원문: [What is domain logic?](https://enterprisecraftsmanship.com/posts/what-is-domain-logic/) | Vladimir Khorikov | ||
|
||
## 문제 분석 | ||
## 도메인 로직 vs 비즈니스 로직? | ||
|
||
대충 네트워크 및 동작 흐름 보면 이렇습니다. | ||
우리는 코드를 작성하기 전에 두가지를 생각합니다. **<u>해결하고자 하는 문제</u>와 <u>해결 방안</u>입니다.** | ||
|
||
1. 게시글 API 호출 (text/html) | ||
2. useLessPMargin.css API 호출 | ||
3. tistory에서 보내줄 html과 css를 로드 완료 | ||
4. CSSOM 마운트 | ||
5. DOM 마운트 | ||
여기서 <u>실생활에서 해결하고자 하는 문제</u>가 바로 **도메인**(a.k.a. Problem Domain, Core Domain)이며 <u>해결방안</u>을 **비즈니스 로직**(a.k.a. Domain Logic, Business Rule, Domain Knowledge)이라고 부릅니다. | ||
|
||
## 방법 | ||
알고보면 쉽지만 찾아보지 않으면 대화조차 안되는 내용이라 학생 입장에는 슬프다. | ||
|
||
jQeury를 사용하여 DOM 마운트 시 CSSOM을 통해 최종적으로 추가된 tt\_article\_useless\_p\_margin 클래스를 제거하였습니다. | ||
![](https://blog.kakaocdn.net/dn/C9mmK/btsI0AKKIUq/K9lQ86u7WQek7vMJkP0Hk1/img.png) | ||
|
||
https://enterprisecraftsmanship.com/posts/what-is-domain-logic/ | ||
|
||
결론은 **도메인 로직과 비즈니스 로직은 동의어**이며 위와 같은 의미라는 것만 알면 된다. | ||
|
||
## 도메인 로직 | ||
|
||
하지만 문제 해결방안(이후 도메인로직)만이 코드에 있으면 너무 좋겠지만 우리들의 코드는 그렇지 않습니다. 예를 들면: | ||
|
||
* DB 로직: DB에 도메인 모델을 저장 | ||
* 3rd Party API 로직: 외부 서비스를 사용 | ||
* UI 로직: UI를 통해 사용자와 상호작용 하는 코드 | ||
|
||
위 같이 도메인로직이라고 부르기에는 애매모호한 코드도 있을 것입니다. 특히 Transaction Script 아키텍처 패턴을 사용하는 경우에는 더욱 그럴겁니다. *(도메인 모델에게 행위를 안주고 서비스가 전부 처리하는 패턴, DB로직이랑 도메인 로직이 짬뽕된다.) Transaction Script가 단순한 코드에서는 가독성이 좋을지 몰라요.* | ||
|
||
그런데 **도메인이 복잡해질 수록 코드 가독성은 떨어지게 돼요.** 더 자주 들어본 안티패턴으로는 [빈약한 도메인 모델](https://martinfowler.com/bliki/AnemicDomainModel.html)이 있어요. 도메인 로직과 이외의 로직을 구분한다면 도메인 모델을 추출하여 코드에서 명확하게 관심사를 분리할 수 있게 돼요. 그렇게되면 DB나 UI같은 세부 사항에 주의를 기울이지 않아도 어떤 도메인을 처리하고자 추론하는 데 필요한 인지적 부하를 줄일 수 있습니다. | ||
|
||
그러면 애플리케이션 서비스 예제에서 도메인 로직을 추출해봅시다. **도메인 로직의** **특징**은 <u>비즈니스적인 의미가 있는 결정을 내리는지 여부</u>로 알 수 있습니다. **도메인 모델**은 <u>비즈니스에 중요한 결정</u>을 하고 **그 외의 모든 코드**들은 <u>도메인 모델이 결정을 따라 어떤 작업을 수행</u>하거나 <u>도메인 모델의 결정을 위한 정보를 제공</u>해주는 것에 불과합니다. | ||
|
||
## 애플리케이션 서비스 로직에서 도메인 로직 분리하기 | ||
|
||
### 첫번째 예시: 계좌에서 현금 인출 | ||
|
||
``` | ||
<body> | ||
<!-- ... 기존 블로그 코드 --> | ||
<!-- jQuery 설치 --> | ||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> | ||
<!-- 지들 멋대로 margin 삭제해버리는 css 제거 --> | ||
<script type="text/javascript"> | ||
$("div").removeClass("tt_article_useless_p_margin") | ||
</script> | ||
</body> | ||
// Application Service | ||
private TakeMoney(amount: number): void { | ||
if(!this.atm.canTakeMoney) { | ||
throw AtmHasNotEnoughMoney('인출 불가'); | ||
} | ||
// 수수료 포함 금액 | ||
const amountWithComission = this.atm.calculateAmountWithComission(amount); | ||
this.paymentGateway.chargePayment(amountWithComission); | ||
this.atm.takeMoney(amount); | ||
this.repository.save(this.atm); | ||
} | ||
``` | ||
|
||
위 방식은 애플리케이션 서비스 계층의 일부 코드입니다. 도메인 클래스 Atm이 <u>부과할 금액을 결정</u>하고 .canTakeMoney(), .calculateAmountWithComission()를 통해 <u>결정을 위한 정보를 제공</u>받습니다. | ||
|
||
이후 애플리케이션 서비스는 그 결정을 듣고 수행하기만 합니다. paymentGatway 인스턴스를 사용하여 금액을 청구하고 데이터베이스를 업데이트합니다. | ||
|
||
### 두번째 예시: 메세지 응답 | ||
|
||
``` | ||
private chatMessageReceived(message: string) { | ||
const event AuctionEvent = AuctionEvent.from(message); | ||
const command: AuctionCommand = this.auctionSniper.process(event); | ||
if (command != AuctionCommand.None()) { | ||
this.chat.sendMessage(command.toString()); | ||
} | ||
} | ||
``` | ||
|
||
이 메서드는 애플리케이션 서비스 계층의 일부이기도 합니다. 여기서 실질적인 도메인 객체는 AuctionSniper입니다. **앱 서비스가 하는 일**은 <u>외부 세계로부터 오는 메세지를 의사 결정자가 이해할 수 있는 형식(AuctionEvent)으로 변환</u>하고 해당 메세지를 전달하고 <u>도메인 클래스의 결정에 따라 처리</u>하는 것입니다. | ||
|
||
위 두가지 코드 샘플 중 어느 것도 스스로 결정을 내리지 않으며, 둘 다 도메인 모델에 위임합니다. 이것이 바로 적절한 관심사의 분리의 모습니다. 애플리케이션 서비스 계층은 상당히 많은 코드를 포함할 수 있지만 그 중 어느것도 비즈니스에 중요한 결정을 내리는 것과는 관련이 없어야합니다. **결정을 내릴 수 있는 유일한 객체는 도메인 모델입니다.** | ||
|
||
도메인 로직을 추출했다면 다음으로 해야할 작업은 다른 모든 유형의 로직이 적절히 분리되어있는지 확인하는 것입니다. (DB 로직 등) | ||
|
||
## 요약 | ||
|
||
* 도메인 로직(비즈니스 로직, 비즈니스 규칙, 도메인 지식과 동의어)은 비즈니스에 중요한 결정을 내리는 로직이다. | ||
* 다른 모든 유형의 논리(DB, UI, 애플리케이션 로직 등)는 도메인 모델에서 내린 결정을 처리하고, 데이터를 저장하거나, 사용자에게 보여주거나, 외부 서비스에 전달하는 작업을 처리합니다. | ||
* 도메인 로직을 다른 로직과 분리하는 것은 중요하며, 전반적인 코드 베이스를 더 간당하게 유지하는 데에 도움이 됩니다. | ||
|
Oops, something went wrong.