본문 바로가기

기술블로그

[띵동] Typescript 기반 범용 Domain NPM모듈 개발기


0. 들어가며

온디맨드 딜리버리 서비스인 띵동은 현재 사용자들이 사용하는 앱과 회사에서 운영을 위해 사용하는 웹, 가맹점주들이 사용하는 웹, 앱 등으로 구성되어있으며 모두 Javascript언어 기반에 Typescript와 React(React Native)로 개발되어있습니다.

수십, 수백개의 테이블이 유기적으로 연동되어 비즈니스로직을 구성하고 여러 구성원들이 함께 참여해서 개발하는 프로젝트이다보니 데이터를 일관성있게 관리하는데에 어려움이 생기는 일을 종종 경험하고는 합니다.

이미 규모가 너무 커져버린채로 잘 동작하고 있는 서비스에 대해 함부로 데이터를 건드리기 두렵다보니 각자 임의로 새로운 key값을 추가해서 관리가 어려워지거나,

사실 대부분의 기능은 근본적으로 데이터에 대한 CRUD(Create, Read, Update, Delete)임에도 불구하고 결과적으로는 같은 동작을 각자가 선호하는 방식으로 구현하다보니 중복되는 코드가 발생하고 유지보수가 어려워지는 문제가 발생하고 있습니다.

이에 각 플랫폼 개발자들간, 또 더 나아가 개발팀 전체에서 일관성있는 비즈니스 로직 설계를 위해 범용적으로 사용할 수 있는 공통 모듈을 구성하는것이 좋겠다는 판단이 들었습니다.


1. 도메인 정의

위 문제를 해결하기 위해 JSON 데이터 상태로 비즈니스 로직을 구현하기 보다 는 범용적으로 사용할 수 있는 공통 Domain을 설계하고 해당 Domain에서 제공하는 method들을 활용해서 데이터를 수정하는 방식으로 서비스를 개발해야겠다는 생각이 들었습니다.

 

개괄적인 아이디어는 다음과 같습니다. Typescript를 기반으로 한 abstract class인 Domain을 정의하고 서비스에서 필요한 주요 데이터들은 이 Domain을 상속받은 class로 구현합니다. 각 class는 구성원들의 합의하에 정의된 멤버 변수들과 method들을 가지고 있기 때문에 비즈니스 로직을 구현할 때는 class에서 제한하고 있는 방식을 사용하도록 강제할 수 있습니다.

 

2. 테스트 코드 작성 & git hook 테스트 자동화하기

이렇게 작성된 Domain들은 사내에서 범용적으로 사용하게 되는 기반이 되는 코드인 만큼 안정성과 명확성이 보장되어야 합니다.

Jest를 이용해 테스트 케이스를 *.test.ts파일에 작성했습니다.

 

FAQ Domain test cases

 

테스트 케이스가 존재하면 서비스 배포 이전에 버그를 조기에 탐지하고 수정이 가능해져서 덕분에 개발자들이 보다 로직 구현에만 집중할 수 있게 도와줍니다.

 

지속적으로 유지보수가 필요한 대규모 서비스는 번거롭더라도 테스트 케이스 작성을 습관화 해야합니다.

 

테스트가 모두 성공하면 로직에 대한 최소한의 안정성을 보장받을 수 있습니다.

 



테스트 케이스를 작성하고 수정된 코드가 commit, push될 시에는 자동으로 테스트를 한 후 commit이나 push가 되도록 husky를 사용해 hook을 걸었습니다.

 

// package.json{
..."husky": {
"pre-commit": "npm run test",
"pre-push": "npm run test",
}...
}

 

package.json에 commit, push 이전에 npm script를 먼저 수행하도록 설정했습니다.

 

3. 빌드, 프로젝트에 적용하기

Typescript compiler를 통해 해당 코드들을 빌드합니다. 프로젝트들 중에는 Typescript로 개발된 프로젝트도 있고 vanilaJS를 사용하고 있는 프로젝트도 있기 때문에 tsconfig.json 파일에 sourceMap option을 주어서 .map파일과 .d.ts파일을 함께 생성합니다.

.map파일은 js코드와 ts파일 소스의 관계를 매핑시켜주고
.d.ts파일은 빌드된 js모듈의 타입을 typescript에서 사용할 수 있도록 타입을 정의해줍니다.

이제 빌드된 코드를 사내 공용 git repository에 upload하고 각 프로젝트에서는 해당 코드를 npm을 통해 모듈로 내려받아 사용합니다.

 

Domain Order

 


정의된 class를 기반으로 인스턴스를 생성하면 이렇게 사용 가능한 변수들과 method들을 자동완성으로 보여줍니다. 이제 프로젝트 참여자들은 api call등을 통해 데이터(주로 json format)를 받으면 공용 Domain을 통해 인스턴스로 만들고 정의된 멤버 변수와 메서드를 사용해 일관성있는 로직을 구현합니다.

부가적으로 자동완성 덕분에 생산성도 향상된다는 장점이 있습니다:)


4. 맺으며

이번 프로젝트를 진행하면서 직접 Typescript 개발환경을 세팅하고, 비즈니스 로직을 객체지향적으로 설계해보고, 범용적이며 안정적으로 서비스를 빌드 및 배포하는 경험을 하면서 많은 것을 배웠습니다.

무엇보다 협업하고 있는 프로젝트에서는 지속적인 유지보수가 가능하도록 중복을 줄이고 재사용성을 높이는 것이 중요하다는 것을 느꼈습니다.

아직은 회사에서 사용하고 있는 모든 데이터들을 전부 Domain화 시키지 못해서 비교적 유연하게 자유도가 높은 형태로 설계되어있지만(예를 들면 정의하지 않은 멤버 변수도 Domain에 추가가 가능함) 앞으로 더 엄밀하고 탄탄한 구조로 발전시켜 나갈 계획입니다.