Notice
Recent Posts
Recent Comments
Link
Archives
Today
Total
관리 메뉴

카레제육 블로그

GopherCon Korea 2024 - 고언어 프로젝트 가이드 A-Z, 변규현 본문

Daily

GopherCon Korea 2024 - 고언어 프로젝트 가이드 A-Z, 변규현

kare jeyuk 2024. 10. 14. 18:33

10월 12일에 이루어진 고퍼콘에 대한 요약 내용이다. 세션에 직접 참여하지는 못했지만 온라인 영상을 통해 내용을 확인할 수 있었다.

첫 번째 세션 당근의 채팅 리드 변규현님의 내용은 아래와 같다.

고언어 프로젝트 가이드 A-Z

먼저 프로젝트 규모에 따른 접근 방식에 대해서 두 가지로 분류하여 진행 방법에 대해서 설명하였다.

1. 큰 프로젝트와 작은 프로젝트

- 작은 프로젝트: 트래픽이 적고, 기능이 단순하며, 빠른 개발이 필요한 경우
- 큰 프로젝트: 복잡한 비즈니스 로직과 많은 의존성이 있는 경우

 

-- 작은 프로젝트 개발 방법으로, 단순하게 접근하고 필요한 것에만 집중하여 기본 라이브러리 활용과 불필요한 복잡성을 피할 수 있는지 검토하라는 것이었다. 예시) 간단한 CLI 도구를 만들때, cobra를 사용하지 않고 기본 라이브러리로 구현

-- 큰 프로젝트(엔터프라이즈 애플리케이션) 개발 방법으로, 도메인 주도 설계(DDD) 원칙 적용과 레이어 아키텍처 사용이 있다.

예) 핸들러(handler/handlerFunc)

handler 방식의 장점

  • 쉬운 복잡한 상태 관리
  • 의존성과 상태가 구조체 필드로 명시적으로 표현되어 명확한 구조
  • 확장성 측면에서 관련 쉬운 메서드 추가
  • 쉽게 다른 인터페이스 구현
  • 복잡한 로직 구조화 용이

HandlerFunc 방식의 장점

  • 간단한 핸들러 빠르게 작성 가능
  • 의존성 주입이 쉽고 클로저 활용 가능
  • 함수형 프로그래밍 가능. 함수 조합과 고차 함수 활용 용이.
  • 빠른 프로토타이핑 가능
  • 작은 애플리케이션이나 마이크로서비스에 적합
  • 단순한 함수는 의존성 모킹이 쉬워 테스트 코드 작성 용이

2. 엔터프라이즈 서비스를 위한 코드 패턴

Domain Driven Design으로 작성하는 레이어 분리: Presenter, Handler, Usecase, (Service), Repository, (Recorder)

  • 기능 위주의 로직을 비즈니스 위주의 로직으로 분리
  • 변경사항 발생 시, 해당 부분의 로직을 중점적으로 개선할 수 있음
  • bounded Context로 특정 도메인 모델이 적용되는 명확한 경계를 구분
  • 각 서비스는 자신의 도메인에 가장 적합한 기술 스택을 선택
  • 점진적 업그레이드와 리펙토링 가능

2-1. Presenter

  • 다양한 클라이언트에 대한 서로 다른 Presenter 만들 수 있음 (예: admin, web, mobile, etc ... )
  • API 버전 관리 용이
  • 민감 정보를 클라이언트에 노출하지 않도록 제어하는데 용이
  • 도메인 모델이 프레젠테이션 계층에 의존하지 않음
  • 필요한 경우 번역이나 로케일에 따른 데이터 변환 용이

2-2. Handler

  • Handler는 HTTP/gRPC 요청 처리와 응답 생성에만 집중
  • 비즈니스 로직은 usecase에 위임
  • 프레젠테이션 계층(Handler)과 애플리케이션 계층(Usecase)이 명확히 구분됨
  • Usecase를 *Mocking하여 Handler를 독립적으로 테스트하기 쉬움
    *실제 객체를 모방하는 가짜 객체를 만들어 사용하는 기법

2-3. Usecase

  • Service 또는 Repository를 의존성으로 받아 사용함 느슨한 결합을 유지
  • 순수한 도메인 객체를 사용
  • 단일 메서드에 여러 Service 또는 repository를 조합하여 복잡한 비즈니스 로직 구현
  • Repository 인터페이스를 Mocking하여 Usecase 테스트 코드 작성 용이

2-4. Service

  • 무거운 계층을 Service 계층으로 분리함으로써 Usecase의 복잡성을 줄일 수 있음
  • 여러 Usecase에서 공통으로 사용되는 복잡한 로직을 Service로 분리하여 코드 재사용성을 높임
  • Usecase는 흐름 제어와 조정에 집중하고, Service는 구체적인 비즈니스 로직 구현에 집중
  • 필요한 경우에만 Service를 도입함으로써 불필요한 추상화를 피하고, 시스템의 유연성을 유지
  • 복잡한 로직을 독립적인 Service로 분리하여 단위 테스트에 용이

2-5. Repository

  • 비즈니스 로직과 데이터 접근에서 Repository는 데이터 접근 로직만을 담당
  • 상위 계층(Usecase 등)이 구체적인 데이터 저장 방식을 알 필요가 없음
  • 도메인 모델을 반환함으로써, Repository가 도메인 계층에 의존하게 되어 의존성 역전 원칙을 따름
  • 도메인 로직이 인프라 세부사항으로부터 독립적이게 함
  • Repository를 쉽게 Mocking하여 테스트가 용이

2-6. Recorder

  • DynamoDB의 특정 API나 쿼리 언어 추상화
  • 상위 계층(Repository, Usecase 등)은 DynamoDB의 세부사항을 알 필요가 없음
  • 데이터 모델(Key-Value 또는 Document 모델) 로직을 중앙화
  • DynamoDB의 특성(예: 파티션 키, 정렬 키 등)을 고려한 최적화된 쿼리를 구현
  • 추후 다른 데이터베이스로 마이그레이션해야 할 경우, recorder 레이어만 수정하면 됨

3. 각 레이어에서의 테스트 코드

Fake Implementations - counterfeiter

  • 복잡한 인터페이스에 대해서도 빠르게 Mocking 객체를 생성할 수 있다. - go generate 명령어를 사용
  • 자동 생성된 모의 객체는 일관된 구조와 네이밍 규칙을 따름 (fake라고 붙은 객체를 인터페이스에 맞게 생성)
    인터페이스의 변경사항을 자동으로 반영할 수 있어, 모의 객체가 항상 최신 상태를 유지
  • 메서드 호출 횟수, 반환값, 에러 등을 쉽게 조작 가능

의존성을 넣어주고 모킹하고 싶은 인터페이스에 아래와 같이 제너레이트 주석을 추가한다.

그 다음, 파일이 있는 디렉토리에서 아래와 같이 명령어를 수행한다.

4. 앱 릴리즈를 위해 꼭 붙이는 도구

  • APM: Datadog을 활용해 함수 단위, 각 서비스 호출 단위까지 전부 측정
  • Error Monitoring: Sentry 또는 Datadog을 통해 앱에서 발생하는 에러를 발견
  • Metric Collection: Prometheus를 통해 메트릭이나 서버 상태를 모니터링
    ** Datadog과 Prometheus를 혼용하는 이유는 인프라 사이즈가 어느 정도 큰 경우 자체 운영하는 인프라의 클러스터나 앱 단위 모니터링 관리가 필요하고 로그 서비스 연동에도 용이

4-1. Application Performance Monitoring

  • 애플리케이션, 인프라, 네트워크 전반에 걸친 통합된 가시성을 확보
  • 성능 문제를 즉시 감지하고 대응 가능
  • 마이크로서비스 아키텍처에서 전체 경로 추적에 용이

위와 같이 내부 로직이 어디를 호출하고 있는지 알 수 있다. 가운데가 서비스의 중심이고, 어디서 호출을 받아 해당 로직이 트리거되는지 확인할 수 있다.

각각의 호출되는 포인트는 Flame Graph로 확인할 수 있다. 네모는 각 서비스가 실행된 시간이고, 위아래 평행으로 보이면 병렬 실행된 내용이다. 이것으로 애플리케이션의 병목지점을 찾을 수 있다. (APM은 데이터독 이외에 오픈소스 핀포인트 등..)

 

4-2. Error Monitoring

  • 실시간으로 에러를 감지하여 큰 문제로 확대되기 전에 대응
  • 에러로 인한 서비스 중단이나 성능 저하를 최소화
  • 비정상적인 접근 시도나 취약점 악용을 조기에 발견

각각의 에러 케이스에 대해서 태깅 해둔다면, 케이스 스터디에 크게 도움이 된다. 어느 디바이스의 유저인지 어느 서버에서 발생하는지 어느 서버의 옵션은 무엇인지, 어느 서버의 버전에서 발생하는지 등 추적

 

4-3. Prometheus & Log Service 연동

  • Prometheus Metric을 통해 인프라 단위 스케일링에 대해서 대응 및 장애 지점 파악에 편리
  • 로그서비스를 연동함으로써 원자적으로 API 호출에 대한 디버깅 가능

결론

고언어로 작은 서비스부터 엔터프라이즈 서비스까지 모두 운영할 수 있다.