1. 디자인패턴 - Composite Pattern

참고 - 모든 IT 스타트업에서 꼭 작성해야 하는 프론트엔드 단위 테스트가 있다? (로깅, 단위 테스트, 그리고 의존성 주입)

  • 동일한 인터페이스의 함수(or 객체)를 하나의 함수로 추상화한다.
  • Composite 은 객체를 트리 구조로 구성한 다음, 이러한 구조를 개별 객체처럼 작업 할 수 있게 하는 구조적 패턴이다.
  • 해당 패턴을 사용하여 공통 인터페이스를 통해 각 객체를 모두 동일하게 처리할 수 있다. 메서드를 호출 할 때 객체 자체가 요청을 트리 아래로 전달한다.

🤔 프론트엔드에서 언제 사용 할 수 있을까?

  • 어떤 이벤트에 대해 A라는 함수를 호출 해야 한다.
  • 그런데, 추후에 해당 이벤트에 대해 B라는 함수도 호출 해야 할 수 있다.

이 때마다 이벤트에 A,B,C…와 같은 함수를 계속 추가해야할까? 심지어 함수 A와 B의 역할이 동일하다면? (역할은 동일하나 사용처는 다를 수 있다. 예를들어 로깅시스템을 여러개 도입할 수도 있다.)

이럴 때 Composite Pattern을 사용하여 동일한 인터페이스의 여러 함수를 하나의 공통된 함수로 추상화 할 수 있다.

해당 패턴의 장점은?

  • 특정 함수/인터페이스에 대한 의존하지 않는다. 결국 해당 함수를 사용하는 컴포넌트의 결합도가 낮아진다.
  • 따라서, 함수가 추가되거나 제거되어도 기존의 코드를 수정 할 필요가 없다.
  • 테스트코드 작성이 수월해진다.

2. CLI의 ---dry-run 옵션

  • dry run 은 ‘실탄을 사용하지 않는 전투 연습’ 이라는 뜻이다. 소프트웨어 공학에서는 ‘모의 테스트’를 의미한다.
  • CLI의 맨 뒤에 --dry-run 을 붙이면 실제로 해당 CLI 가 생성되지는 않고, 해당 CLI를 실행했을 때 어떤 결과가 일어나는지 보여준다.

Nx 를 사용하여 라이브러리나 앱을 생성할 때 해당 옵션을 사용하여 실제로 어떤식으로 파일구조가 생성될지 미리보면 실수 예방에 매우 좋다. 커맨드라인 실행전에 --dry-run을 옵션을 붙이는 습관을 들이면 좋을 것 같다.


3. Zod에 대해 알아보기

최근에 Kent C Dodds가 라이브코딩을 하면서 Input 을 구현할 때, Zod를 사용하여 Validation을 구현하는 것을 봤다. Zod가 뭘까? 타입스크립트만으로는 부족한걸까?

  • 알다시피 타입스크립트는 사용자 Input이나 API 응답데이터를 검증하지는 못한다.
  • 따라서 Zod를 사용하여 타입스크립트의 API 스키마 검증을 하고, Input Validation을 하여, 런타임 에러를 최소화 시킬 수 있다.
    • 즉 타입스크립트의 한계점을 극복하기 위한(?) 도구라고 생각할 수 있겠다.
  • 물론 이 모든걸 타입스크립트만으로 할 수 있지만 이를 더 편리하게 사용 할 수 있게 해주는 라이브러리라고 생각하면 될 것 같다.

🤔 Zod는 언제 사용해야할까?

그러면 모든 API 요청에 Zod를 사용하여 응답 스키마에 대한 validation을 해야할까? 빠르게 구현해야하는 상황이고, 이미 백엔드 개발자들과 응답값에 대한 합의 및 서버 측 테스트가 모두 끝난 상황이라면 굳이 필요할까?

  • 당연히 서버측에서도 예기치 못한 응답값을 뱉어줄 가능성은 충분히 있다. 또한 서버측 API 스키마의 변경과 프론트엔드측에서 해당 스키마 변경에 대한 대응의 시점이 맞지 않을 수 있다. 이런 상황들을 고려했을 때, 유효성 검사를 한번 더 하는 것은 손해될게 없다.
  • 하지만, 유효성 검사 레이어를 중간에 두는 것은 그만큼 리소스가 소모되는 일이다. 따라서 써드파티 라이브러리와 같이 API 스키마의 변동사항을 예측/대응 할 수 없는 경우에만 사용하는게 비용적인 측면에서 합리적일 것이라고 생각한다.

4. 추상화에 대한 고민

문득 Next.js의 특정 버전에서만 사용 할 수 있는 코드를 작성하다보니 그런 생각이 들었다. 추후에 버전을 올리거나, 다른 SSR 프레임워크로 마이그레이션을 해야하면, 이 코드들은 전부 폐기되거나 수정되어야겠는데?

따라서, 추후 알 수 없는 프로젝트의 미래를 위해서 특정 프레임워크/라이브러리/특정 버전에 의존적인 코드는 최소한 덜어내는게 좋을 것 같다는 결론에 이르렀다. 그리고 덜어내는 방법은 바로 추상화라고 생각했다.

해당 코드에 어떤 프레임워크의 어떤 버전이 와도 최소한의 변경만으로 대응이 되는 추상화를 해야하는 것이 바람직할 것이라고 생각했다.

근데 그러면 리액트도 추상화 시키란 말이냐!

아니다, 리액트와 같은 프레임워크는 마치 프로그래밍 언어처럼 해당 어플리케이션을 만드는 코어 계층이다. 따라서 왠만하면 변하지 않을 것이며 따라서 이에 대한 추상화는 불필요하다고 생각한다. 만약 리액트에서 타프레임워크로 이전해야 한다면 아예 새로 만드는 편이 나을 것이다.

하지만, 코어 계층 위에 있는 프레임워크 혹은 라이브러리들은 언제든 변경 될 수 있다.

그러면 모든 라이브러리에 사용 코드를 추상화 시키란 말이냐!

이것도 아니다. 예를들어 Styled Component와 같은 CSS 라이브러리나, Date js와 같은 유틸성 라이브러리는 추상화의 이점이 없다고 생각한다.

그 이유는, 첫번째로 해당 라이브러리와 비슷한 라이브러리들과 사용방법/지원하는 기능의 범위 등이 유사하기 때문이다. 두번째로 위와 같은 유틸성 라이브러리는 어플리케이션의 핵심 기능과는 거리가 멀기 때문이다. 즉, 말그대로 CSS라던지, 유틸과 같은 어플리케이션에서 아주 작은 단위의 기능을 담당하기 때문에 타라이브러리로 마이그레이션 했을 때 어플리케이션 내에서 영향을 받는 범위가 적다. 따라서 이와 같은 라이브러리에 대한 추상화는 큰 이점을 가지지 못한 채 리소스 낭비로 귀결 될 수 있다.

따라서 추상화 시켜야 할 프레임워크/라이브러리는

  • 코어 계층이 아니되,
  • 추후에 다른 라이브러리로 변경 될 때 지원 기능의 범위나 사용방법이 매우 달라질 수 있으며
  • 어플리케이션의 핵심 기능과 밀접하게 연결 되어 있을경우

라고 생각한다. 그리고 이는 Next.js 와 같은 프레임워크가 아닐까..생각해본다. 😵‍💫

그 외 좋았던 글