액터 구조에 대한 한계점을 다시 접하게 되었다. 물론 당장 회사에서 발생한 것은 아니다. 그냥 들었다. 액터 구조 사용한 곳의 끝이 좋았던 적이 없었다고. 물론 난 아직 끝을 보지 않은 듯 하다. 하지만 한계점은 알고 있다. 이 액터 구조는, Rust와 만나면서 개발자의 생산성을 향상시킨다. 좋은거 아니냐고? 반은 좋고 반은 나쁘다. 통제해줄 사람이 없으면, 정말 개발자라는 족속들은 지맘대로 개발하는 특성이 있다. 그리고 보통 문서를 작성하는걸 싫어한다. 이직을 밥먹듯이 하는걸 당연히 하면서, 인수인계는 전혀 신경쓰지 않는 것이다. 그게 개발자다. 결국 적당한 실력으로 마음대로 만들어 올린 액터로 떡칠된 서비스는 유지보수 난이도가 굉장히 높아지게 된다.
그럼 액터 구조를 버리면 되는거 아니냐고? 그러기에는 액터 구조가 가져다주는 생산성과 그에 기반한 매출 성장을 무시할 수가 없다. 액터를 버리기 위해 Rust를 버리려고 하니, 성능을 포기할 수 없고, C++을 도입하자니, 숙련된 비싼 개발자를 구하는 것이 또 부담이며, 지금의 개발인력들을 재교육할 시간적 여유가 없다. 결국은 현실에 일부 타협하며 이래저래 좌충우돌을 겪어야 하는 것이 기술자들의 숙명인 것이다. 최소한 이래저래 삽질할 시간을 벌어다 줄 안정적인 캐시카우를 만들 때까진 말이다.
그럼 남은 방법은 액터 구조를 디버깅하는 방법을 개선하는 것, 그리고 문서화를 강제하는 시스템을 만들어가는 것이다. 그 중에서 당장 빠르게 할 수 있는 것은 전자다.
새 버전은 5.0.0. README 업데이트 두글자 더해 5.0.1이다. 아주 간단한 아이디어였는데, 지하철에서 회사로 걸어가던 중 갑자기 떠올랐다. 메시지 send를 하는 부분에 어떤 액터로 가는지가 표시되면 되는 것. 액터 타입을 send할 때 직접 어딘가 쓰면 되는 것이다. 그럼 그 타입의 정의를 타고 갈 수가 있다. 그럼 그곳에 있는 액터의 구성과 로직을 살펴볼 수가 있는 것이다. 그래서 Actor trait의 제네릭에 기존의 message, result, error 타입을 표시하던걸, trait 내 type 으로 정의하도록 바꿨다. 그리고 ActorSystem에서 send 함수 사용 시 message와 result 타입을 제네릭으로 사용하는 대신 actor 타입을 사용하도록 바꿨다. 그럼 actor_system.send(msg)를 사용할 때, actor_system.send::<MyActor>(msg)로 이용하면 된다. 이렇게 하면 여기서 MyActor를 타고 액터를 따라가서 디버깅할 수 있다.
물론 한계점은 여전히 있다. 액터 주소 체계를 중구난방으로 관리하면 대참사가 벌어진다. 4.x.x 버전부터는 broadcast 기능을 지원하는데, 여러 액터 타입에서 같은 메시지 타입을 이용하고, 액터 주소 필터링에 함께 걸릴 수 있는 구조라면, 표면적으로 제네릭으로 이용한 액터의 로직은 따라갈 수 있지만, 숨겨진 그 액터는 알 길이 없다(눈으로 정적 분석을 하는 수밖에 없다). 다만 이 문제는 그래도 4.x.x 버전보단 이번이 개선되기는 했다. 최소한 메시지 타입이 다른 경우 바로 컴파일 에러를 뱉을 것이기 때문이다.
어? 주소 체계 관리를 빡세게 만드는 뭔가를 만들면 되려나. 하지만 이건 더 잡고 있으면 모처럼 휴식 사이클을 돌리고 있는데 다 망치고 밤을 새버릴 것 같아서 멈추도록 하겠다.