-
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
713 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,85 +1,89 @@ | ||
--- | ||
authors: puleugo | ||
date: Mon, 12 Aug 2024 12:00:24 +0900 | ||
date: Mon, 19 Aug 2024 21:32:38 +0900 | ||
--- | ||
|
||
# [번역] 방금 당신이 작성한 코드는 도메인 로직인가? | What is domain logic? | ||
# 개발자의 이상적인 해커톤 준비 방법 | ||
|
||
## 서론 | ||
|
||
* 원문: [What is domain logic?](https://enterprisecraftsmanship.com/posts/what-is-domain-logic/) | Vladimir Khorikov | ||
[KAIST GDSC](https://gdsc-kaist.github.io/)에서 개최하는 스파클링톤에 참여하게 되었다. 모교에서 해커톤을 2회 주최한 경험은 있어도 100% 참여자로써의 해커톤 경험은 처음이라 많은 기대를 하고 있다. 해커톤 개최 경험자로써 개발자의 이상적인 준비를 이야기해보고자 한다. | ||
|
||
## 도메인 로직 vs 비즈니스 로직? | ||
협업에 관한 내용도 개발 실력보다도 아주아주 중요하지만 개발 이야기만 해도 할 말이 많기 때문에 이번 글에서는 생략하겠다. | ||
|
||
우리는 코드를 작성하기 전에 두가지를 생각합니다. **<u>해결하고자 하는 문제</u>와 <u>해결 방안</u>입니다.** | ||
## 해커톤 참여자는 이래야 한다. | ||
|
||
여기서 <u>실생활에서 해결하고자 하는 문제</u>가 바로 **도메인**(a.k.a. Problem Domain, Core Domain)이며 <u>해결방안</u>을 **비즈니스 로직**(a.k.a. Domain Logic, Business Rule, Domain Knowledge)이라고 부릅니다. | ||
해커톤은 스펙보다는 <u>재미, 협업 능력 향상, 무료 피자와 콜라를 목표</u>로 하는 것이 옳다. 번뜩이는 아이디어를 빨리 구현해야 하는데 <u>대용량 트래픽, 확장성 같은 경험을 채우고 싶어서 해커톤에 참여하는 것이라면 그다지 좋은 팀원으로 평가되지는 않을 것</u>이다. | ||
|
||
알고보면 쉽지만 찾아보지 않으면 대화조차 안되는 내용이라 학생 입장에는 슬프다. | ||
그렇다면 <u>어떤 개발자가 좋은 해커톤 팀원</u>일까? 의존하지 않아도 되는 팀원이다. 다음은 이번 해커톤에서 모집된 직무들이다. (4인 1팀) | ||
|
||
![](https://blog.kakaocdn.net/dn/C9mmK/btsI0AKKIUq/K9lQ86u7WQek7vMJkP0Hk1/img.png) | ||
![](https://blog.kakaocdn.net/dn/L4cxZ/btsI7GSb1k3/2kjkxdbGTP3OfDZqwJKFPk/img.png) | ||
|
||
https://enterprisecraftsmanship.com/posts/what-is-domain-logic/ | ||
노드는 직무, 간선은 의존성이다. 채도는 의존도라고 보면 된다. 해커톤 내의 변수가 많으니 이 그래프가 절대적 지표는 아니다. | ||
의존성이 있으니 <u>백엔드 개발자 관점에서 어떤 것에 집중해야할 지</u> 생각해 보자. | ||
|
||
결론은 **도메인 로직과 비즈니스 로직은 동의어**이며 위와 같은 의미라는 것만 알면 된다. | ||
* <u>기획자와 협업할 때</u>, 해결해야 하는 문제와 솔루션을 확실하게 이해해야 한다. <u>확실한 이해를 위해 많은 의사소통</u>을 해야 한다. 개발부의 의존성은 전적으로 당신에게 향해있다는 것을 명심하라. | ||
* <u>디자이너와 협업할 때</u>, UI에 따라 내가 어떤 정보를 프론트엔드에게 제공해야 하는지, 사용자의 스토리에 따라 어떤 정보가 필요할지도 계속 생각해야 한다. 디자인에 따라 처리해야 하는 알고리즘을 서버에서 처리할지 프론트에서 처리할 지도 이후 회의해야 한다. | ||
* <u>프론트엔드 개발자와 협업할 때</u>, **빠르게 API를 제공**해야 한다. 사용자와 직접 의사소통하므로 가장 잔손이 많이 가는 작업을 맡으실 텐데 API 제공이 늦어진다면 그만큼 프론트엔드 개발자의 부담이 커진다. | ||
|
||
## 도메인 로직 | ||
다들 밤을 새우며 정신적으로 피곤해질 수밖에 없다. 해커톤을 개최하면서 싸우는 팀도 꽤나 봤어서 이를 방지하기 위해 좋은 팀원이 되는 것이 중요하다. 결국 <u>참여자 모두 재밌고 행복하기 위해 존재하는 해커톤</u>이니까. | ||
|
||
하지만 문제 해결방안(이후 도메인로직)만이 코드에 있으면 너무 좋겠지만 우리들의 코드는 그렇지 않습니다. 예를 들면: | ||
## 백엔드라면 이것을 준비하라. | ||
|
||
* DB 로직: DB에 도메인 모델을 저장 | ||
* 3rd Party API 로직: 외부 서비스를 사용 | ||
* UI 로직: UI를 통해 사용자와 상호작용 하는 코드 | ||
먼저, **보일러 플레이트를 준비하라**. 보일러 플레이트는 <u>거의 변경 없이 바로 사용 가능한 반복되는 코드</u>를 말한다. 나한테만 도움 되는 것이 아니라 <u>프론트엔드 개발자에게 도움 될</u> 것이다. 예시를 들자면: | ||
|
||
위 같이 도메인로직이라고 부르기에는 애매모호한 코드도 있을 것입니다. 특히 Transaction Script 아키텍처 패턴을 사용하는 경우에는 더욱 그럴겁니다. *(도메인 모델에게 행위를 안주고 서비스가 전부 처리하는 패턴, DB로직이랑 도메인 로직이 짬뽕된다.) Transaction Script가 단순한 코드에서는 가독성이 좋을지 몰라요.* | ||
1. API 문서(e.g. 스웨거) | ||
2. DB 세팅 및 ORM | ||
3. 배포되어 있는 AWS, S3 컨테이너: 프론트엔드가 서버를 클론해서 로컬에서 작업하는 것은 말도 안 된다. | ||
4. <u>E2E 테스트</u>: 단일, 결합 테스트는 미리 작성해도 거의 의미 없다. 어차피 기획이 나오면 변경될 내용이다. 해커톤 진행 시에도 E2E 테스트 외에는 개발이 완료되면 진행하자. | ||
5. Docker Compose를 활용한 빠른 3rd Party 확장 | ||
6. 서버 자동 배포 | ||
7. 게시글 작성 | ||
8. 파일 업로드 | ||
9. 채팅 기능 | ||
10. ~~인증~~: 필요로 할 때 아니면 추가하지 말자. 보안 해커톤 같은 경우가 아니라면 프로젝트 개발 속도만 떨어뜨리는 족쇄다. | ||
|
||
그런데 **도메인이 복잡해질 수록 코드 가독성은 떨어지게 돼요.** 더 자주 들어본 안티패턴으로는 [빈약한 도메인 모델](https://martinfowler.com/bliki/AnemicDomainModel.html)이 있어요. 도메인 로직과 이외의 로직을 구분한다면 도메인 모델을 추출하여 코드에서 명확하게 관심사를 분리할 수 있게 돼요. 그렇게되면 DB나 UI같은 세부 사항에 주의를 기울이지 않아도 어떤 도메인을 처리하고자 추론하는 데 필요한 인지적 부하를 줄일 수 있습니다. | ||
특히 <u>E2E 테스트를 강조하는 이유는 당신의 신뢰성</u>을 보여주기 때문이다. 해커톤에는 부담도되고 긴장도 되고 즐겁기도 평소와 다른 흥분한 상태일 것이다. 그런 상황에서 내 <u>작은 실수가 크게 느껴질 수 있다</u>. | ||
|
||
그러면 애플리케이션 서비스 예제에서 도메인 로직을 추출해봅시다. **도메인 로직의** **특징**은 <u>비즈니스적인 의미가 있는 결정을 내리는지 여부</u>로 알 수 있습니다. **도메인 모델**은 <u>비즈니스에 중요한 결정</u>을 하고 **그 외의 모든 코드**들은 <u>도메인 모델이 결정을 따라 어떤 작업을 수행</u>하거나 <u>도메인 모델의 결정을 위한 정보를 제공</u>해주는 것에 불과합니다. | ||
이를 E2E 테스트가 검증해 줄 것이다. 스웨거 배포, API 동작 확인 등 프론트엔드 개발자에게 보여질 부분을 테스트하라. 또한 망각의 동물인 우리에게 테스트를 먼저 작성함으로써 제약사항이나 팀원끼리 정한 솔루션을 망각하는 실수를 줄일 수 있다. | ||
|
||
## 애플리케이션 서비스 로직에서 도메인 로직 분리하기 | ||
두 번째로는 **오픈소스와 외부 API를 사용해 보라.** 해커톤에서 해결해야 하는 방법이 단순히 솔루션만 있다고 해결되지는 않는 경우도 많다. 이런 경우에는 "데이터"나 "복잡한 알고리즘"이 필요할 수 있다. 이런 부분은 오픈소스와 외부 API가 제공해 줄 것이다. 카카오의 구름톤의 교육에서 항상 빠지지 않고 나오는 주제이다. | ||
|
||
### 첫번째 예시: 계좌에서 현금 인출 | ||
사용방법을 읽어보는 것 또한 비용이다. 미리 할 수 있는 것은 해커톤 전에 한번 정도 사용해 보는 것이 옳다. | ||
|
||
``` | ||
// 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>받습니다. | ||
* [한국 공공데이터](https://www.data.go.kr/) | ||
* [국가 별 공공테이터](https://opendatainception.io/) | ||
* [Data.gov](https://data.gov/): 미국 정부의 공공 데이터 포털로, 경제, 환경, 교육 등 다양한 카테고리의 데이터를 제공 | ||
* [awesome-public-datasets](https://github.com/awesomedata/awesome-public-datasets) | ||
|
||
이후 애플리케이션 서비스는 그 결정을 듣고 수행하기만 합니다. paymentGatway 인스턴스를 사용하여 금액을 청구하고 데이터베이스를 업데이트합니다. | ||
외부 API는 이를 참고하라. | ||
|
||
### 두번째 예시: 메세지 응답 | ||
* [Rapid API](https://rapidapi.com/hub) | ||
* [Public API](https://github.com/public-apis/public-apis) | ||
* [API Layer](https://apilayer.com/) | ||
* [ChatGPT API](https://platform.openai.com/docs/api-reference/introduction) | ||
|
||
``` | ||
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()); | ||
} | ||
} | ||
``` | ||
Node.js계열을 사용한다면 Nest.js 웹 프레임워크도 권장한다. 의존성을 Module 단위로 관리하기 때문에 보일러플레이트의 추가 기능 관리에 효율적이다. | ||
|
||
이 메서드는 애플리케이션 서비스 계층의 일부이기도 합니다. 여기서 실질적인 도메인 객체는 AuctionSniper입니다. **앱 서비스가 하는 일**은 <u>외부 세계로부터 오는 메세지를 의사 결정자가 이해할 수 있는 형식(AuctionEvent)으로 변환</u>하고 해당 메세지를 전달하고 <u>도메인 클래스의 결정에 따라 처리</u>하는 것입니다. | ||
세 번째로는 시제품(MVP)을 개발한다는 생각으로 프로젝트를 개발하여야 한다. | ||
|
||
위 두가지 코드 샘플 중 어느 것도 스스로 결정을 내리지 않으며, 둘 다 도메인 모델에 위임합니다. 이것이 바로 적절한 관심사의 분리의 모습니다. 애플리케이션 서비스 계층은 상당히 많은 코드를 포함할 수 있지만 그 중 어느것도 비즈니스에 중요한 결정을 내리는 것과는 관련이 없어야합니다. **결정을 내릴 수 있는 유일한 객체는 도메인 모델입니다.** | ||
![](https://blog.kakaocdn.net/dn/bd00Jf/btsI9hXP3iw/aQBhNRJMii23zw0QcSAgpk/img.png) | ||
|
||
도메인 로직을 추출했다면 다음으로 해야할 작업은 다른 모든 유형의 로직이 적절히 분리되어있는지 확인하는 것입니다. (DB 로직 등) | ||
올바른 MVP | ||
|
||
## 요약 | ||
자동차라는 MVP를 만들 때는 자전거부터 시작하는 게 아니라, 최소한 자동차가 구현되어야 한다. | ||
|
||
* 도메인 로직(비즈니스 로직, 비즈니스 규칙, 도메인 지식과 동의어)은 비즈니스에 중요한 결정을 내리는 로직이다. | ||
* 다른 모든 유형의 논리(DB, UI, 애플리케이션 로직 등)는 도메인 모델에서 내린 결정을 처리하고, 데이터를 저장하거나, 사용자에게 보여주거나, 외부 서비스에 전달하는 작업을 처리합니다. | ||
* 도메인 로직을 다른 로직과 분리하는 것은 중요하며, 전반적인 코드 베이스를 더 간당하게 유지하는 데에 도움이 됩니다. | ||
1. 1번 케이스, 4단계까지 진행될 때까지 협업이 불가능하다. | ||
2. 2번 케이스, 우리가 만들고자 하는 기능을 확실하게 알라. <u>이동수단이라면 1단계로도 충분</u>하다. <u>자동차라면 바로 4단계를 만들어라.</u> | ||
3. 3번 케이스, 1단계부터 바로 <u>목표였던 자동차를 만들었다</u>. | ||
|
||
3번 케이스가 MVP다. 많은 개발자들이 2번으로 착각하고 있는데 MVP는 <u>최소 기능</u> 제품이다. 굳이 최소 기능을 여러 번 분리해서 개발할 이유가 있을까? 바로 시제품을 만드는 것을 목적으로 하라. MVP는 변경될 여지가 적다. | ||
|
||
더 중요한 것은 4단계에서는 동작하는 것이 확실하지만 1-3단계까지는 완벽하게 동작하지 않아도 된다는 점이다. 적절한 결과물(e.g. json)부터 빨리 프론트엔드에게 제공하여 개발이 진행되도록 하자. 프론트엔드 개발자도 서버의 API 처리 부분보다는 UI를 먼저 만들라. | ||
|
||
네 번째로는 Git 버저닝 전략이다. 대부분의 개발자들이 Git Flow를 사용하는데 <u>빠른 개발을 해야 하는 해커톤에서는 Github Flow 전략을 권장</u>한다. Git Flow는 대규모 팀에서 적합한 반면 Github Flow는 1-3인 정도의 소규모 팀 | ||
|
||
<u>Github Flow는 Main 브랜치 + n개의 기능 브랜치로 관리하는 방법</u>이다. 운영 관련 브랜치가 포함된 Git Flow보다 훨씬 개발속도가 빠를 것이다. | ||
|
Oops, something went wrong.