관심사의 분리(Separation of Concerns)

게임 개발뿐만 아니라 모든 소프트웨어 개발의 핵심은 복잡성을 극복하는 것입니다. 프로그램은 작은 프로그램의 조합으로 만들어지는데, 다른 엔지니어링과 달리 이런 조합에 물리적인 제약이 존재하지 않기 때문에 훨씬 쉽게 복잡해지는 경향이 있습니다. 예를 들어, 초고층 건물이나 우주 비행선은 물리 법칙의 제약 때문에 더 복잡해지기 어렵지만, 소프트웨어는 이런 제약이 없습니다.

소프트웨어가 복잡해지면 가장 먼저 병목이 되는 건 사람입니다. 인간의 머리는 한 번에 생각할 수 있는 양에 한계가 있기 때문입니다. 인지 심리학자인 George A. Miller은 The Magical Number Seven, Plus or Minus Two라는 논문에서 인간은 아무리 똑똑해도 한 번에 처리할 수 있는 정보가 7개 정도(혹은 1,2개 더)로 제한되어 있다고 말합니다.

소프트웨어 엔지니어링에서 강조하는 원리 중 하나는 관심사의 분리(Separation of Concerns)입니다. 여러 가지를 동시에 신경 쓰면 복잡하니깐, 각각을 따로 분리해서 생각하자는 이야기입니다. Concern을 보통 관심사로 번역하고 있지만, 복잡성의 관점에서는 걱정거리로 생각할 수도 있습니다.

그런데 걱정거리는 쉽게 늘어납니다. 예를 들어, 게임 출시 전에 튜토리얼 기능을 추가한다고 합시다. 튜토리얼이라는 게 게임 전반에 걸쳐서 게임 진행 방법을 설명해야 하기 때문에, 기존 코드 여기 저기에서 Tutorial.IsTutorialMode()를 확인하고 true이면 튜토리얼 코드를 진행하고 false이면 기존 코드를 진행하는 코드가 필요하게 됩니다. 프로그램 전반에 걱정거리가 하나 추가된 셈입니다.

서버 코드도 마찬가지입니다. 요즘 출시되는 대부분의 게임은 업적 기능이 있는데, 업적 확인도 튜토리얼과 마찬가지로 하나의 기능이라기 보다는 서버 코드 전반에 걸쳐서 삽입되기 때문입니다. 플레이어가 친구를 3명 맺었으면 보상을 주는 업적이 있다고 하면, 친구 맺는 코드 입장에서는 “업적 확인”이라는 걱정거리가 하나 늘어난 셈입니다.

말하듯이 코딩하라가 생각처럼 쉽지 않은 이유도 마찬가지입니다. 아래 코드는 간단합니다. 유저 등록을 위해 필요한 절차를 말하듯이 나열하기만 하면 코딩이 끝나기 때문입니다.

function registerUser()
{
    var request = receiveRequest();
    validateRequest(request);
    canonicalizeEmail(request);
    updateDbFromRequest(request);
    sendEmail(request.Email);
    return sendResponse("Success");
}

그런데 걱정거리는 쉽게 늘어납니다. 위 코드에 예외 처리를 넣으면 어떻게 될까요? 각 함수마다 리턴 값을 확인하거나 try/catch 블록을 주렁주렁 달아줘야 합니다. 위 코드가 성능 때문에 비동기로 작성되어야 한다면 어떨까요? node.js 스타일이라면 다음 할 일을 일일이 콜백을 통해서 넘겨줘야 합니다. 위 코드가 C++로 작성되었다면 어떨까요? 이제 언제 메모리를 할당하고, 언제 해제할지 일일이 신경써야만 프로그램이 제대로 동작합니다. 인자를 넘기는 방식은 어떻게 해야 하나요? call-by-value, call-by-reference? sendEmail이 멀티쓰레드 접근에 안전하지 않아서 락을 잡아줘야 한다면? 여기에 매 100번째 등록 유저에게는 선물을 주는 이벤트를 진행한다면?

  • 기본 로직
  • 예외 처리
  • 비동기 프로그래밍
  • 메모리 할당/해제
  • 인자 전달 방식
  • 락(lock)
  • 이벤트

이렇게 간단한 코드에서도 우린 이미 인간의 인지 능력의 한계인 7개의 걱정거리에 도달했습니다. 이것보다 더 복잡해지면 대부분의 개발자는 더 이상 자기가 작성한 프로그램이 대체 어떻게 해서 돌아가는지 이해하지 못하게 됩니다. 하나의 걱정거리가 추가되면 다른 걱정거리 하나가 머리 속에서 지워지기 때문에 어디선가 문제가 생길 수밖에 없는 상태가 됩니다.

프로그래밍을 잘한다는 건 이런 수많은 걱정거리를 한 번에 처리하는 능력이 아니라, 코드에서 여러 걱정거리를 분리해 낼 수 있는 능력입니다. 우리가 알고 있는 수많은 객체지향 프로그래밍 원리, 디자인 패턴 등도 결국은 관심사 혹은 걱정거리를 분리하고 한 번에 하나씩만 생각하자는 이야기에 불과합니다. 소프트웨어 엔지니어링이란 인간의 인지 능력의 한계를 극복하기 위한 체계적인 방법론이라고 생각할 수 있습니다. 프로그래밍 언어 또한 인간의 인지 능력의 한계 내에서 복잡성을 극복하기 위한 다양한 수단을 제공하는 도구라고 생각할 수 있습니다. 프로그래밍이란 결국 복잡한 문제를 작은 문제로 나눠서 풀고, 다시 재조합하는 과정인 셈입니다.

협찬: SKP 유태원님 (아이스 까페모카) 감사합니다.

Advertisements

2 thoughts on “관심사의 분리(Separation of Concerns)

댓글이 닫혀있습니다.