조화로운 소통의 기술
사거리 도로를 생각해 보죠. 동서남북에서 수많은 자동차, 오토바이, 보행자들이 각자의 목적지를 향해 움직이고 있습니다. 만약 교통신호등이 없다면 어떻게 될까요? 각 차량과 보행자가 서로 직접 소통하거나 눈치를 봐야 할 겁니다. "제가 먼저 갈게요", "아니요, 저부터요", "잠깐만요, 보행자가 지나가고 있어요!"
상상만 해도 아찔하고 보행자가 건널 수 조차 없을 듯합니다. 수십 대의 차량이 서로 직접 대화해야 한다면, 필요한 소통 연결고리는 기하급수적으로 늘어날 듯합니다. 10대의 차량이 있다면 45개의 연결고리가, 20대라면 190개의 연결고리가 필요합니다.
하지만 현실에서는 그렇지 않습니다. 모든 참가자들은 단 하나의 존재와만 소통합니다. 바로 교통신호등입니다. 차량들은 서로 직접 대화하지 않고, 신호등의 지시에만 따릅니다. 빨간불이면 멈추고, 초록불이면 갑니다. 간단합니다.
복잡한 다자간 소통을 단순한 일대다 소통으로 바꿔, 전체 시스템의 복잡도를 획기적으로 줄이는 것이 '중재자 패턴(Mediator Pattern)'입니다.
1980년대 후반 객체지향 프로그래밍이 주목받기 시작했지만, 동시에 새로운 문제가 드러났습니다. 객체들이 서로 직접 소통하면서 생기는 "스파게티 코드" 현상입니다. - “스파게티 코드(Spaghetti Code)”는 복잡하고 얽히고설킨 구조 때문에 이해하기 어렵고 유지보수가 힘든 코드를 뜻하는 말입니다. 마치 면발처럼 코드가 이리저리 얽혀 있어서 어디가 어디를 참조하는지 한눈에 파악하기 어렵다는 의미로 붙여진 이름입니다. -
예를 들어, GUI 애플리케이션에서 버튼, 텍스트 필드, 리스트박스가 서로 상호작용해야 하는 상황을 생각해 보죠. 버튼을 누르면 텍스트 필드의 내용이 바뀌고, 텍스트 필드가 바뀌면 리스트박스가 업데이트되어야 합니다. 전통적인 방식으로는 각 컴포넌트가 다른 모든 컴포넌트를 직접 참조해야 했습니다. 10개의 컴포넌트가 있다면 무려 45개의 연결고리가 필요합니다.
이런 복잡성은 유지보수의 악몽입니다. 하나의 컴포넌트를 수정하면 관련된 모든 컴포넌트를 찾아서 수정해야 했고, 새로운 컴포넌트를 추가하는 것은 거의 불가능에 가까웠습니다. 소프트웨어가 커질수록 이런 문제는 기하급수적으로 악화됩니다.
1994년, GOF는 이 문제를 해결하기 위해 교통신호등, 항공관제탑, 전화교환대 등 복잡한 시스템을 조율하는 중재자들의 역할을 관찰합니다. 이들은 모두 다자간의 복잡한 소통을 일대다의 단순한 소통으로 바꾸는 공통점이 있었습니다.
특히 Gamma는 스위스 취리히 대학에서 박사과정 중 ET++라는 GUI 프레임워크를 개발하면서 이 패턴의 필요성을 절감했다고 회고했습니다. 수많은 GUI 컴포넌트들이 서로 얽혀있는 복잡성을 해결하기 위해 중재자 개념을 도입했고, 이것이 후에 디자인 패턴으로 정립된 것입니다.
중재자 패턴은 단순히 기술적 해결책이 아니라, "분리와 중앙화", "조정과 협력"이라는 핵심 아이디어는 오늘날 마이크로서비스 아키텍처와 이벤트 드리븐 시스템의 기초가 되었습니다.
채팅방 시스템을 예를 들어 만들어보겠습니다.
// 중재자 인터페이스
interface ChatMediator {
void sendMessage(String message, User user);
void addUser(User user);
}
// 사용자 추상 클래스
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void send(String message);
public abstract void receive(String message);
public String getName() { return name; }
}
// 일반 사용자
class ChatUser extends User {
public ChatUser(ChatMediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(name + "이(가) 메시지를 보냅니다: " + message);
mediator.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println(name + "이(가) 메시지를 받았습니다: " + message);
}
}
// 채팅방 (중재자 구현체)
class ChatRoom implements ChatMediator {
private List<User> users = new ArrayList<>();
@Override
public void addUser(User user) {
users.add(user);
System.out.println("� " + user.getName() + "님이 채팅방에 입장했습니다");
}
@Override
public void sendMessage(String message, User sender) {
// 발신자를 제외한 모든 사용자에게 메시지 전달
for (User user : users) {
if (user != sender) {
user.receive("[" + sender.getName() + "] " + message);
}
}
}
}
// 채팅 시스템 데모
public class ChatDemo {
public static void main(String[] args) {
// 중재자 (채팅방) 생성
ChatRoom chatRoom = new ChatRoom();
// 사용자들 생성 및 채팅방 입장
User alice = new ChatUser(chatRoom, "Alice");
User bob = new ChatUser(chatRoom, "Bob");
User charlie = new ChatUser(chatRoom, "Charlie");
chatRoom.addUser(alice);
chatRoom.addUser(bob);
chatRoom.addUser(charlie);
System.out.println("\n 채팅 시작!");
System.out.println("-".repeat(40));
// 대화 시뮬레이션
alice.send("안녕하세요!");
bob.send("안녕하세요 Alice님!");
charlie.send("모두 안녕하세요!");
alice.send("오늘 날씨가 좋네요 �");
}
}
위 코드에서 핵심은 ChatRoom 클래스입니다. 이 중재자가 없었다면 각 사용자는 다른 모든 사용자를 직접 알고 있어야 합니다. Alice가 메시지를 보내려면 Bob과 Charlie의 참조를 각각 가지고 있어야 하고, 새로운 사용자가 들어올 때마다 모든 기존 사용자들의 코드를 수정해야 합니다.
하지만 중재자 패턴을 사용하면서 각 사용자는 오직 채팅방과만 소통합니다.
3명의 사용자가 서로 직접 소통한다면 6개의 연결고리가 필요합니다. 하지만 중재자를 사용하면 3개의 연결고리만 있으면 됩니다. 100명의 사용자라면? 직접 소통 방식은 4,950개의 연결이 필요하지만, 중재자 방식은 100개면 충분합니다.
각 사용자는 다른 사용자가 누구인지, 몇 명인지 알 필요가 없습니다. 단지 채팅방에 메시지를 보내기만 하면 됩니다. 새로운 사용자가 입장하거나 기존 사용자가 퇴장해도 다른 사용자들의 코드는 전혀 영향받지 않습니다. 모든 변경사항은 중재자에서만 처리됩니다.
메시지 필터링, 로깅, 권한 검사 등의 부가 기능을 중재자에서 일괄적으로 처리할 수 있습니다. 각 사용자에게 이런 기능을 개별적으로 구현할 필요가 없습니다.
복잡한 조직에서 모든 사람이 모든 사람과 직접 소통한다면 혼란만 가중될 것입니다. 성공적인 조직들은 명확한 소통 체계를 가지고 있습니다. 팀장, 프로젝트 매니저, 부서장 같은 중재자들이 정보를 필터링하고 조정해서 전달합니다.
개인적인 관계에서도 마찬가지다. 가족 내에서 문제가 생겼을 때, 모든 구성원이 서로 직접 따지기보다는 가장 중립적이고 지혜로운 사람이 중재 역할을 하는 것이 효과적입니다.
중재자는 단순히 메시지를 전달하는 것이 아니라, 상황에 따라 적절히 해석하고 조정합니다. 마치 스마트홈 허브가 수면 모드와 외출 모드에 따라 같은 움직임 감지를 다르게 처리하는 것처럼, 좋은 리더는 상황을 읽고 팀원들의 행동을 조율해야 합니다.
중재자 패턴의 가장 큰 장점 중 하나는 확장성입니다. 새로운 구성원이 추가되어도 기존 관계망을 건드리지 않습니다. 이는 네트워킹에서도 중요한 원리이며, 좋은 네트워커는 다양한 사람들을 연결해 주는 허브 역할을 하며, 이를 통해 모든 사람이 더 큰 가치를 얻을 수 있습니다.