13.5.2.1 은닉형(Encapsulated) 아키텍처 기반 Zenoh-Flow SDK 래퍼(Wrapper) 계층 설계
Zenoh-Flow 프레임워크 아래에서 다국어(C++, Rust, Python)를 버무려 거대한 수십 개의 오퍼레이터 노드 군단을 만들다 보면, 각 언어의 날것(Raw) SDK 함수를 비즈니스 로직(AI 추론코드나 센서 제어코드) 곳곳에 직접 박아넣는 무지성 코딩이 횡행하게 된다.
“여기서 데이터를 퍼블리시해야 하니까 zenoh_flow::send(...) 를 호출하자!“라는 식의 하드코딩은, 추후 프레임워크의 메이저 통신 버전이 바뀌거나 단위 테스트(Unit Testing)를 위해 통신 모듈만 살짝 떼어내려 할 때 전체 소스 코드를 산산조각 내는 재앙의 씨앗이 된다.
본 절에서는 딥러닝/로보틱스 연구자들이 통신 인프라의 존재를 눈치채지 못한 채 오직 수학적 사상과 알고리즘에만 몰두할 수 있도록, 지저분한 Zenoh-Flow API 코드를 블랙박스 안에 욱여넣고 외부와 차단하는 은닉형 래퍼(Encapsulated Wrapper) 계층 설계 런북을 갈파한다.
1. Raw SDK 직접 호출의 파탄과 종속성(Coupling) 지옥
AI 엔지니어(Python 개발자)가 작성한 Yolo 비전 디텍터 코어 코드를 보자.
만약 이 함수 맨 마지막에 zflow_operator.send_output("bbox_out", data) 와 같은 Zenoh 특화 코드를 직접 치고 있다면 그 코드는 이미 Zenoh-Flow 라는 특정 프레임워크의 노예로 전락한 것이다. 내일 당장 이 Yolo 코드를 클라우드 RestAPI 서버에도 띄우고 싶다면? Zenoh 코드가 박혀있는 이 함수를 재사용할 방법은 없다. 코드를 복사해서 통신 부분만 다시 짜야 한다(Code Duplication). 테스트 코드를 짤 때도 마찬가지로 거짓(Zenoh Mocking) 더미를 덕지덕지 붙여야 작동한다. 어플리케이션 코어 로직이 인프라스트럭처에 종속(Tightly Coupled)되어 썩어가고 있는 것이다.
2. 인터페이스(Trait/Abstract) 매개체를 통한 래퍼(Wrapper) 캡슐화
이 치명적인 종속성을 절단하기 위해서는 도메인 로직(Yolo)과 통신 런타임(Zenoh-Flow) 사이에, 누구의 편도 들지 않는 투명한 유리벽, 즉 추상화된 인터페이스(Interface/Trait) 를 꽂아 넣어야 한다.
# [은닉형 래퍼 계층의 파이썬 아키텍처 런북]
# 1. 인프라와 무관한 순수 추상 인터페이스 (The Wrapper Contract)
class DataPortInterface:
def push_result(self, result_data):
raise NotImplementedError
# 2. 어플리케이션 도메인 코드는 오직 '인터페이스'만을 바라본다.
# (Zenoh가 무엇인지 전혀 알지 못한다. 순수 무결정 상태)
class YoloDomainLogic:
def __init__(self, output_port: DataPortInterface):
self.out = output_port
def process_image(self, image):
bounding_box = run_yolo(image)
self.out.push_result(bounding_box) # 그저 인터페이스 너머로 결과를 던질 뿐!
# 3. 인프라스트럭처 래퍼 (Zenoh-Flow 구체화 객체) - 더러운 코드는 구석에 짱박는다
class ZenohFlowPortWrapper(DataPortInterface):
def __init__(self, zflow_context):
self.ctx = zflow_context
def push_result(self, result_data):
# 오직 이 클래스 안에서만 Zenoh-Flow의 Raw API가 호출된다!
self.ctx.send_to_port("bbox_out", serialize(result_data))
3. Dependency Injection(의존성 주입)과 영원한 자유(Freedom)
위의 아키텍처를 적용하고 나면, Zenoh-Flow 의 런타임 컨테이너가 켜질 때, ZenohFlowPortWrapper 객체를 하나 찍어내어 YoloDomainLogic (비즈니스 코어)의 뱃속으로 밀어 넣어주기만 하면(의존성 주입, DI) 된다.
결과적으로 엄청난 생태계의 자유가 촉발된다.
- 테스트(TDD): AI 엔지니어가 YOLO 함수를 테스트할 때, 무거운 Zenoh 데몬을 켤 필요가 없다. 그저
push_result가 불리면 화면에print만 찍는 가짜 래퍼(MockPort)를 주입해서 1초 만에 검증을 끝낸다. - 프레임워크 스위칭: 회사 정책이 바뀌어 내일부터 Zenoh-Flow 대신 그냥 ROS2 원시 토픽으로 통신하라는 지시가 떨어졌다. 도메인 로직 코드(
YoloDomainLogic)는 단 한 줄도 고치지 않는다. 오직 래퍼 클래스만ROS2PortWrapper로 하나 덧붙여 주입하면 마이그레이션이 끝난다.
인프라스트럭처의 코드가 당신의 순결한 도메인 수학 로직을 오염시키게 내버려 두지 마라.
모든 통신 프레임워크 SDK는 본질적으로 언제든 갈아 끼울 수 있는 ’일개 소모품(Plugin)’에 불과하다. 래퍼(Wrapper) 캡슐화와 의존성 주입(DI)으로 통신 엔진의 권력을 도메인 코드로부터 철저히 은닉시키고 격리(Isolation)하는 자만이 시대를 초월하여 생존하는 강건한 아키텍처를 조각할 수 있다.