Home > Projects > microservice project > week2 > nnUNet 서비스 구현

nnUNet 서비스 구현
tech BE microservice project

개요


목적

nnUNet 서비스의 내부 기능을 구현한다.

문제 상황

Cleancode 설계 원칙에 따라, 각 모듈을 분리하려 했으나, 분리에 기준을 명확하게 정하고, 이를 기록할 필요성이 느껴졌다.

  1. I/O 기능을 분리하여 단일책임 원칙 준수
    • I/O 기능이 Feature 추출, TotalSegmentator 기능 등에 결합되어 경로 -> 실행 구조를 따르고 있다.
    • 해당 구조를 수정하지 않으면 한번에 I/O 각 기능에 실행이 아닌, 각 기능을 실행할 때마다 I/O가 실행되어야 하는 불편함이 따른다.
  2. 각 모듈의 가독성과, 유지/보수성 증가를 위한 Clean Code를 어떻게 설계해야하는가.
    • 단일책임 원칙 준수, 의존성 주입, 인터페이스 통일에 원칙을 준수하여 코드를 설계
    • 그러나 이러한 원칙에 따라 코드를 분류할 때 어떤 코드를 같은 파일에 어떤 코드를 일반화시킨 I/O 등의 모듈에 넣어야할지 기준의 모호함이 발생
    • 해당 모호함을 코드 변경 사유에 따라 정리하기 위해 각 코드들의 목적에 대한 정리가 필요.
  3. 결국 핵심은 현재 서비스를 만들 때 각 모듈 단위의 추상화를 통해서, 인터페이스를 이해하기 쉽게 정리하고, 교체를 용이하게 만드는 것

    • 변경의 이유를 분리하라 (SRP)

      같이 바뀌는 것끼리 묶고, 따로 바뀌는 건 나눈다.
      변경 이유가 다른데 같이 묶으면 나중에 다 같이 바뀌는 지옥이 됨

    • 인터페이스는 용도 기준으로 만들라

      데이터의 타입이 아니라, 역할과 목적을 기준으로 묶어야 함

      ❌ 잘못된 추상화 ✅ 올바른 추상화
      “이미지와 관련된 걸 ImageUtils에 다 넣자” “AI 모델의 입력 생성 → FeatureExtractor”
    • 구체적인 것이 아니라, 의도를 표현하라

      함수/클래스명, 모듈명은 무엇을 한다가 아니라 왜 한다를 표현

      ❌ 잘못된 추상화 ✅ 올바른 추상화
      load_image, save_image, sitk2nib DataAdapter (형식 변환의 책임)
      make_ap_image, extract_mask FeatureBuilder (모델 입력 생성의 책임)
    • 추상화는 실제 사용 사례를 최소 2개 생각하고 하라

      “지금 하나만 있을 때는 절대 추상화하지 마라” → 재사용 포인트가 최소 2개 이상일 때 추상화가 필요
      하나만 있을 때 수행하는 추상화는 다른 재사용 포인트가 생길 때 문제가 될 확률이 높다(기존의 것에 맞춰져 있을 확률이 높기 때문)

    • 인터페이스는 “최소한의 정보만 넘기도록”

      함수에 다 때려 넣음 나중에 바꾸기 힘듦 → 필요한 최소한의 데이터만 넘기고, 의도를 명확히

모듈을 리팩토링할 떄 원칙을 정하자!

원칙

  1. 재사용되는 코드는 무조건 분리하기!
  2. 각 인터페이스가 최소의 정보만으로 통신이 가능하게! 조금 비효율적이더라도 일관된 구조로 통신이 가능하게!
  3. 코드가 확장이 편하도록, 전략 패턴, 어댑터 패턴 등을 적용하기!
  4. 각 모듈별로 실제 실행이 되는 usecase 부분을 각각 작성해두고, 전체 모듈의 usecase를 조립하는 pipeline 파일과, 이를 api와 연결하는 entrypoint 설계

“핵심은 코드가 어떤 식으로 수정될 수 있을까를 예상하고, 수정이 편하도록 관리하는 것이다.”

이를 위한 기능의 정리

현재 nnUNet 서비스에 존재하는 모든 기능을 정리

기능 설명 수정 가능 시나리오 일관성 제한
gRPC 통신 gRPC를 통해 API Gateway와 통신을 수행 API Gateway와 추가적인 통신 명령이 생기거나, 제거될 수 있음 case_dir만을 사용해 통신이 수행되야한다.
nnUNet 추론 이미지를 입력받아    

Clean Code를 위한 코드의 정리

각 코드가 담당하는 계층의 분리

코드를 추상화하는 목적에는

  1. 나중에 해당 코드를 재사용하고 읽기 편하게 만드려는 목적