시작하게 된 계기
안녕하세요, 똑닥에서 Frontend
개발을 하고 있는 이태홍입니다.
똑닥에는javascript
를 사용할 때typescript
를 사용하고 있습니다.
하지만 각각 별도로 작업을 하다 보니 서로 각자에게 맞는 타입을 작성해서 사용하고 있었습니다.
그래서 왜? 굳이?
라는 생각을 하게 됩니다.
그래서 한번 하나로 통일해서 써볼 수 있게 해볼까?
라는 생각으로 시작하게 됩니다.
Backend , Frontend 공통 IDL 적용해 보자!
기존 문제점
우리는 회사를 입사하기전 회사에 진행 방식에 대해서 여러가지 이상적인 상상을 하게 됩니다.
가령 아래와 같이? 👀
기획에 맞추어 (디자인팀,기술팀) 일사불란하게 병렬적으로 움직이는 모습~! 👍🏻
하지만 회사에 입사해 현실을 마주하면 좌절하게 될지도...?
이러한 상황속 반복적인 작업을 줄이고 일에 효율성을 높이는 일은 필수적이라고 봤습니다.
앞서 언급드리렸던 것처럼 Backend
와 Frontend
는 같은 api
속 다른 type
을 바라보고 있는 단점이 있었습니다.
이러한 문제는 설계가 공통 type
을 정의하는데에 중복적인 type
을 반복적으로 선언하고, 비슷한 type
들이 지속적으로 늘어나고, 미친듯한 파편화가 발생될 우려 등 여러 문제점을 야기할 수 있습니다.
또한 Frontend
에서 선제적으로 작업을 진행하게 될때 예상되는 type
으로 response
가 내려오지 않았을때 설계해놓은 로직을 재설계 하고 컴포넌트의 분리를 처음부터 다시 시작해야하는 상황이 발생될 여지가 있습니다.
그렇기에 공통적으로 운영하는 type
은 우리의 작업을 많은 부분에서 간소화 시킬 수 있었습니다.
IDL 이란?
IDL 🙄?
이름 모를 축약어처럼 생긴 녀석은 뭘 뜻하는 걸까? 🧐
MDN 정의
인터페이스 정의 언어(Interface Description Language, IDL) 는 특정 프로그래밍 언어와 별도로 지정된 객체의 인터페이스에 사용되는 일반 언어입니다.
이와 같이 특정 객체에 대한 정의를 할 때 사용되는 것이라고 알 수 있습니다.
IDL 의 장점
- 언어 중립성: IDL은 어느 한 언어에 국한되지 않기 때문에, 다양한 프로그래밍 언어로 작성된 컴포넌트 사이의 통신을 가능하게 합니다.
- 플랫폼 중립성: IDL은 플랫폼에 의존하지 않기 때문에, 다양한 운영 체제에서 실행되는 컴포넌트 사이의 통신을 가능하게 합니다.
- 코드 재사용성: IDL은 인터페이스를 명확하게 정의하기 때문에, 코드 재사용성을 높일 수 있습니다.
- 개발 효율성: IDL은 인터페이스 정의를 자동화하여 개발 효율성을 높일 수 있습니다.
다른 곳들은 어떻게 정의하고 있을까? 🤔
여러 사례를 찾아보다 마음에 들었던 사례를 찾아보게 됬습니다. 그건 바로 강남언니의 기술 블로그 사례 였습니다.
첫 내용부터 강렬한 단어가 꽃히더라고요
프론트엔드 주도로 인터페이스를 설계한다
바로 이 글을 보자마자 이거다! 라고 생각하고 읽었던거 같습니다. (정말 단순해...🫠)
자세히 읽어보니 강남언니는 Google Protocol buffers를 도입한것으로 보였습니다.
선택한 이유는 다음과 같았습니다.
- 다양한 언어로 Generate 할 수 있습니다
- 무엇보다 인터페이스 작성이 매우 쉽습니다.
여기서 우리의 환경을 생각했을 때
1번
의 경우 같은typescript
를 사용했기에 굳이?2번
의 경우 쉽다는 가정은 러닝커브를 넘어서 익숙해 졌을때의 얘기가 아닌가 생각했습니다.
그래서 간단하게 별도의 프로젝트로 만들어 type
만 정의하는 ts
파일을 만드는것으로 시작하기로 마음 먹었습니다.
이 부분에 대해 백엔드와 협의가 필요했기에 설득 하는 시간이 필요했고, 마감 회의때 발의하여 안건을 올렸고
이후 협의를 진행하는 회의를 통해 Frontend
가 먼저 선행하여 type
을 작성하고,
Backend
가 PR
을 통해 내용을 확인 후 이를 사용하는 것으로 협의를 진행했습니다.
설계 방식은 다음과 같습니다.
Interface.ts
1. 모듈 폴더
- 모듈 단위 (
login
,treatment
,hospital
등) 으로 폴더를 생성합니다. - 폴더 하위에는
interface.ts
파일과models.ts
파일을 생성합니다.
예제
배럴 파일(index.ts)
에선 path
설정을 위해 정의한 interface.ts
파일과 models.ts
파일을 export
합니다.
2. HTTP API 인터페이스 작성 방법
interface InterfaceKeyModel {
[`${HTTP_METHOD} /${VERSION}/${CATEGORY}/${UNITKEY}/${CATEGORY}`] : Record<'req'| 'res', any>
}
이와 같은 형식으로 key
를 정의하고, 그에 맞는 request
모델과 response
형식의 모델을 작성합니다.
3. 주석 작성 방법
/**
* 기본 설명 작성
* - default true
* @before-ref GET https://test.example.com/api/v1/hospitals => items
* @authenticationPrincipal('Basic' | 'Bearer') // Basic or Bearer 인증 방식을 사용하여 정보를 가져옵니다.
* @NOTE 추가적인 설명이 필요할 때 작성
* @new-type 과거 API에 없던 새로운 key를 작성할 때 작성
*/
이와 같이 기본 설명 작성
, 기본값 지정(default)
, 이전 api 사용 주소(@before-ref)
, 인증 방식(@authenticationPrincipal)
, 추가설명(@NOTE)
, 과거 api 없던 새로운 타입(@new-type)
필요에 맞는 것들을 위와 같은 형식에 맞게 작성합니다.
이를 통해 과거 api를 새로운 api가 작성 될때 손쉽게 이해 할 수 있고, 보다 빠르게 작업을 진행할 수 있습니다.
Models.ts
1. 타입 별칭 (Type Alias) 작성
타입 별칭은 type
키워드를 사용하여 작성합니다. 타입 별칭은 기존 타입을 새로운 이름으로 지정하는 데 사용됩니다. 예를 들어:
type MyType = string | number;
2. 제네릭 타입 (Generic Type) 작성
제네릭 타입은 type
키워드와 <T>
구문을 사용하여 작성합니다. 제네릭 타입은 타입이나 인터페이스를 정의할 때, 그 타입이나 인터페이스에 포함될 다른 타입을 나중에 지정할 수 있게 해줍니다. 예를 들어:
type MyGeneric<T> = T[];
3. Base Type
기본적으로 쓰이는 공통 타입들을 정의해 놓았습니다.
QNA
프로젝트 관리는 어떻게 하나요?
별도의 repository 로 분리되어 운영하고 있으며
submodule 형태로 직접 사용하기도 하고,
private npm git packages 를 사용해서 운영하기도 합니다.
마치며
지금까지 똑닥에서 도입 후 모두가 만족(?)하고 있는 IDL의 히스토리에 대해 소개드렸습니다. (저는 많이 뿌듯한건 안비밀~)
IDL을 이용하여 다음과 같은 효과를 얻었습니다.
Backend
와Frontend
의type
을 통일화 했습니다.- 이를 통해 이중작업되는 요소를 줄어들었습니다.
- 인터페이스에 대한 히스토리 파악이 용이 해졌습니다.
- 클라이언트와 서버 간 통신 규약을 공통적이게 명시 했습니다.
혹시 비슷한 문제 상황을 겪고 있는 팀이라면, 이번 글을 통해 조금이나마 해결에 도움이 되셨으면 좋겠습니다.
마지막으로 Frontend
에서는 이 외에도 빠르고 효율적인 개발을 위해 또 다른 여러 도구와 방식들을 채택하고 있습니다.
재미있게 이글을 읽으셨다면, 다른 개발 블로그 글도 같이 읽어주시고, 채용공고에 많은 관심 부탁드립니다. 🙇🏻♂️