1291.45 행동 트리의 모듈성 원칙
1. 모듈성의 정의
모듈성(modularity)이란, 시스템을 독립적으로 설계·구현·테스트·교체할 수 있는 자기 완결적(self-contained) 단위인 **모듈(module)**로 분해하는 설계 원칙이다. 소프트웨어 공학에서 모듈성은 복잡한 시스템의 관리 가능성(manageability)을 확보하기 위한 근본적 원칙으로 확립되어 있으며, Parnas(1972)에 의하여 “정보 은닉(information hiding)“의 개념과 함께 체계화되었다.
행동 트리(Behavior Tree, BT)에서 모듈성이란, 트리를 구성하는 각 노드 및 서브트리가 다른 노드나 서브트리의 내부 구현에 의존하지 않고 독립적으로 기능하며, 트리 내의 임의의 위치에 삽입·제거·교체될 수 있는 구조적 속성을 의미한다.
2. 행동 트리에서 모듈성이 성립하는 구조적 근거
2.1 통일된 노드 인터페이스
행동 트리의 모듈성은 모든 노드가 동일한 인터페이스를 준수한다는 사실에 의하여 성립한다. 행동 트리의 어떤 노드든, Tick을 입력으로 수신하고 세 가지 반환 상태(Success, Failure, Running) 중 하나를 출력으로 생성한다.
\text{Node}: \text{Tick} \rightarrow \{\text{Success}, \text{Failure}, \text{Running}\}
이 통일된 인터페이스에 의하여, 제어 흐름 노드(Sequence, Fallback, Parallel 등)는 자식 노드의 구체적 유형이나 내부 구현에 무관하게 동일한 규칙으로 자식을 관리할 수 있다. 자식 노드가 단일 조건 노드이든, 수백 개의 노드로 구성된 복잡한 서브트리이든, 부모 노드의 관점에서는 동일한 인터페이스를 통하여 상호작용한다. 이는 객체 지향 설계에서의 **다형성(polymorphism)**과 구조적으로 동등하다.
2.2 트리 구조에 의한 계층적 캡슐화
트리(tree) 자료 구조는 본질적으로 계층적 캡슐화(hierarchical encapsulation)를 지원한다. 트리 \mathcal{T}의 임의의 내부 노드 v를 루트로 하는 서브트리 \mathcal{T}_v는 그 자체로 유효한 행동 트리이며, \mathcal{T}_v의 내부 구조는 v의 부모 노드에 대하여 완전히 은닉된다.
이 성질을 형식적으로 표현하면 다음과 같다. 서브트리 \mathcal{T}_v와 \mathcal{T}_w가 동일한 인터페이스를 준수할 때, \mathcal{T}_v를 \mathcal{T}_w로 대체하여도 부모 노드 이상의 트리 구조에는 어떠한 수정도 요구되지 않는다.
\mathcal{T}[\mathcal{T}_v \leftarrow \mathcal{T}_w] \text{ 는 } \mathcal{T} \text{의 부모 구조를 변경하지 않음}
이 대체 가능성(substitutability)은 행동 트리 모듈성의 핵심적 형식적 속성이다.
2.3 전이 규칙의 부재
유한 상태 머신(FSM)에서 모듈성이 제한되는 근본적 원인은
상태 간 전이 규칙(transition rule)이 전역적 의존 관계를 형성한다는 데 있다. 새로운 상태를 추가하면, 기존 상태들과의 전이 관계를 명시적으로 정의하여야 하며, 이는 기존 모듈의 수정을 수반한다.
행동 트리에서는 이러한 명시적 전이 규칙이 존재하지 않는다. 제어 흐름은 트리의 계층 구조와 제어 흐름 노드의 의미론(semantics)에 의하여 암묵적으로 결정된다. 따라서 새로운 노드를 추가하거나 기존 노드를 제거할 때, 다른 노드의 정의를 수정할 필요가 없다. 이 특성은 행동 트리의 모듈성을 상태 머신 대비 구조적으로 우월하게 만드는 근본적 요인이다.
3. 모듈의 단위: 노드와 서브트리
3.1 노드 수준의 모듈성
행동 트리에서 가장 기본적인 모듈 단위는 개별 노드(node)이다. 각 노드는 다음과 같은 자기 완결적 속성을 갖는다.
- 단일 책임(single responsibility): 하나의 노드는 하나의 행동 실행 또는 하나의 조건 평가만을 담당한다.
- 내부 상태 캡슐화: 노드의 내부 상태(IDLE, RUNNING, SUCCESS, FAILURE)는 노드 자체에 의하여 관리되며, 외부에서 직접 조작되지 않는다.
- 독립적 생명 주기: 노드는
onStart(),onRunning(),onHalted()등의 콜백을 통하여 자신의 생명 주기를 독립적으로 관리한다.
BehaviorTree.CPP 4.x에서는 모든 노드가 TreeNode 기반 클래스를 상속하며, tick() 가상 함수를 오버라이드하여 구체적인 동작을 정의한다. 이 상속 구조는 노드 수준의 모듈성을 객체 지향적으로 구현한 것이다.
3.2 서브트리 수준의 모듈성
복잡한 행동 단위는 여러 노드를 포함하는 **서브트리(subtree)**로 캡슐화된다. 서브트리는 단일 노드와 동일한 인터페이스를 제공하므로, 부모 노드의 관점에서 서브트리와 단일 노드는 구별되지 않는다.
서브트리 모듈화의 구체적 사례로, 이동 로봇의 “장애물 회피 주행” 행동을 하나의 서브트리로 정의하는 경우를 고려할 수 있다.
SubTree: ObstacleAvoidanceNavigation
├── ReactiveFallback
│ ├── Sequence
│ │ ├── Condition: 장애물 감지
│ │ └── Action: 회피 기동
│ └── Action: 경로 추종
이 서브트리는 내비게이션 임무, 탐사 임무, 순찰 임무 등 장애물 회피가 필요한 모든 상위 트리에 삽입될 수 있다. 서브트리의 내부 구조(ReactiveFallback, Condition, Action의 배치)는 이를 사용하는 상위 트리에 대하여 완전히 은닉된다.
BehaviorTree.CPP에서는 XML 기반 행동 트리 정의에서 <SubTree> 태그를 통하여 서브트리를 참조하며, 블랙보드 포트(blackboard port)를 통하여 서브트리와 부모 트리 간의 데이터를 교환한다. 이 포트 기반 인터페이스는 서브트리의 입출력을 명시적으로 정의하여 모듈 경계를 명확히 한다.
4. 모듈성의 정량적 평가
4.1 결합도와 응집도
소프트웨어 공학에서 모듈성의 품질은 **결합도(coupling)**와 **응집도(cohesion)**의 두 지표로 평가된다.
- 결합도: 모듈 간의 상호 의존 정도를 나타낸다. 결합도가 낮을수록 모듈성이 우수하다.
- 응집도: 단일 모듈 내부의 구성 요소들이 하나의 목적에 집중하는 정도를 나타낸다. 응집도가 높을수록 모듈성이 우수하다.
행동 트리에서 노드 간의 결합도는 반환 상태의 전파와 블랙보드를 통한 간접적 데이터 공유로 제한된다. 노드 간의 직접적 함수 호출이나 상태 참조는 발생하지 않으므로, 결합도가 구조적으로 최소화된다.
행동 트리와 유한 상태 머신의 결합도를 비교하면 다음과 같다. 유한 상태 머신에서 n개의 상태가 존재할 때, 최악의 경우 전이 규칙의 수는 O(n^2)에 달하며, 각 전이 규칙은 출발 상태와 도착 상태 간의 직접적 의존 관계를 형성한다. 반면, 행동 트리에서 n개의 노드가 존재할 때, 노드 간의 의존 관계는 부모-자식 관계인 간선(edge)의 수에 비례하며, 이는 O(n)이다.
| 아키텍처 | 모듈 간 의존 관계 수 | 결합도 특성 |
|---|---|---|
| 유한 상태 머신 | O(n^2) (최악) | 전역적, 양방향 |
| 행동 트리 | O(n) | 계층적, 단방향 |
4.2 변경 영향 범위의 국소성
모듈성의 실용적 지표로서 **변경 영향 범위(change impact scope)**를 고려할 수 있다. 행동 트리에서 특정 서브트리를 수정할 때, 수정의 영향은 해당 서브트리의 경계 내부에 국한된다. 서브트리의 반환 상태 패턴이 변경되지 않는 한, 부모 노드 이상의 트리 구조는 영향을 받지 않는다.
이 국소성(locality)은 대규모 로봇 시스템에서 팀 단위 병렬 개발을 가능케 하는 실용적 기반이다. 서로 다른 팀이 독립적으로 서브트리를 개발하고, 최종적으로 이들을 상위 트리에 통합하는 개발 방식이 자연스럽게 지원된다.
5. 모듈성을 보장하기 위한 설계 지침
행동 트리의 구조적 모듈성을 실효적으로 활용하기 위하여, 다음과 같은 설계 지침이 권장된다.
5.1 기능적 응집에 따른 서브트리 분해
하나의 서브트리는 하나의 기능적 목표(functional goal)에 대응하여야 한다. 예를 들어, “장애물 회피”, “충전소 복귀”, “물체 파지” 등 각각의 자율 행동을 독립된 서브트리로 정의한다. 서로 다른 기능적 목표에 속하는 노드들을 하나의 서브트리에 혼합하면 응집도가 저하되어 모듈성의 이점이 감소한다.
5.2 블랙보드 포트를 통한 명시적 인터페이스 정의
서브트리와 외부 간의 데이터 교환은 블랙보드 포트를 통하여 명시적으로 정의하여야 한다. 서브트리가 전역 블랙보드의 임의의 키에 직접 접근하면, 서브트리와 외부 간의 암묵적 의존 관계가 형성되어 결합도가 증가한다.
BehaviorTree.CPP 4.x에서는 서브트리의 입력·출력 포트를 XML에서 명시적으로 선언하여, 서브트리의 데이터 의존 관계를 투명하게 관리할 수 있다.
<SubTree ID="NavigateToGoal"
target_pose="{goal_pose}"
result="{nav_result}" />
이 선언에서 target_pose는 입력 포트이고 result는 출력 포트이며, 서브트리의 데이터 인터페이스가 명확히 드러난다.
5.3 노드의 부작용 최소화
개별 노드는 자신의 기능 범위를 초과하는 부작용(side effect)을 최소화하여야 한다. 하나의 액션 노드가 블랙보드의 다수의 키를 동시에 수정하거나, 외부 시스템의 상태를 광범위하게 변경하면, 해당 노드의 교체나 제거 시 예측 불가능한 파급 효과가 발생할 수 있다.
6. 모듈성의 한계와 보완
행동 트리의 모듈성에도 한계가 존재한다. 블랙보드를 통한 데이터 공유는 노드 간의 암묵적 데이터 의존 관계를 형성할 수 있으며, 이는 트리의 노드 수가 증가할수록 추적이 어려워진다. 특히, 동일한 블랙보드 키를 다수의 노드가 읽고 쓰는 경우, 데이터 경쟁(data race)과 유사한 논리적 충돌이 발생할 가능성이 있다.
이러한 한계를 보완하기 위하여, BehaviorTree.CPP 4.x에서는 서브트리별 독립 블랙보드(scoped blackboard)를 지원한다. 각 서브트리는 자신만의 블랙보드 인스턴스를 가지며, 부모 트리의 블랙보드와는 포트를 통하여서만 데이터를 교환한다. 이 범위 지정(scoping) 메커니즘은 전역 블랙보드의 무분별한 공유로 인한 결합도 증가를 방지한다.
7. 참고 문헌
- Colledanchise, M., & Ögren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
- Colledanchise, M., & Ögren, P. (2017). “How Behavior Trees Modularize Hybrid Control Systems and Generalize Sequential Behavior Compositions, the Subsumption Architecture, and Decision Trees.” IEEE Transactions on Robotics, 33(2), 372–389.
- Faconti, D. (2022). BehaviorTree.CPP 4.x Documentation. https://www.behaviortree.dev/
- Iovino, M., Scukins, E., Styrud, J., Ögren, P., & Smith, C. (2022). “A Survey of Behavior Trees in Robotics and AI.” Robotics and Autonomous Systems, 154, 104096.
- Parnas, D. L. (1972). “On the Criteria To Be Used in Decomposing Systems into Modules.” Communications of the ACM, 15(12), 1053–1058.
버전: 2026-03-31