객체지향 패러다임에서 메시지는 중요한 역할을 한다.
그 이유에 대해서 고민해보고 남겨보자.
하나의 객체는 메시지를 전송함으로써 다른 객체에 접근한다. 메시지-전송 메커니즘은 객체가 다른 객체에 접근할 수 있는 유일한 방법이다.
객체가 다른 객체에 접근한다라는 이야기는 행위를 유발한다라고 해석되어 보인다.
이를 다른 객체의 책임을 수행하도록 요청을 보내는 것은 메시지-전송 메커니즘이라고 할 수 있는 것 같다.
메시지 전송에 대한 형식은 대부분 수신자, 메시지 이름, 인자의 조합으로 구성되어 있다.
메시지를 수신받은 객체는 자신이 해당 메시지를 처리할 수 있는지 확인한다. 이는 메시지에 해당하는 행동을 수행해야 할 책임이 있다는 것이다. 따라서 메시지의 개념은 책임의 개념과 연결된다.
이러한 메시지를 처리할 수 있다면 메시지를 처리할 방법인 메서드를 선택하게 된다.
객체지향 프로그래밍 언어에서 메서드는 클래스 안에 포함된 함수 또는 프로시저를 통해 구현된다.
따라서 어떤 객체에게 메시지를 전송하면 결과적으로 메시지에 대응되는 특정 메서드가 실행된다.
다형성은 서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다르게 반응하는 것을 의미한다.
메시지는 무엇이 실행될지는 명시하지만 어떻게 실행할 것인지는 수신자가 결정한다. 메시지에는 처리 방법과 관련된 어떤 제약도 없기 때문에 동일한 메시지라고 하더라도 서로 다른 방식의 메서드를 이용해 처리할 수 있다.
엘리스의 재판이라는 협력안에서 왕이 전송한 증언이라는 메시지를 이해할 수 있다. 각 수신자인 모자 장수, 요리사, 엘리스는 왕이 전송한 메시지를 처리하기 위해 자신만의 방법을 자유롭게 선택할 수 있다. 이것은 각 수신자들이 모두 자신의 의지에 따라 책임을 수행할 수 있는 자율적인 존재이기 때문에 가능한 것이다.
이러한 동일한 메시지를 처리하는 방법은 메시지를 수신하는 수신자의 종류에 따라 달라진다.
그렇다면 다형성을 만족시키는 서로 다른 객체들은 동일한 책임을 갖고 있다는 것이다. 여기서 중요하게 보아야 한다고 강조하는 부분은 송신자의 관점이다.
메시지 송신자의 관점에서 이 객체들은 동일한 책임을 수행하기에 다형적인 수신자들을 구별할 필요가 없으며 자신의 요청을 책임을 지닌다는 점에서 공통점을 가지고 있다.
기본적으로 다형성은 도일한 역할을 수행할 수 있는 객체들 사이의 대체 가능성을 의미한다. 협력안에서 이들은 서로를 대체할 수 있다. 다만 처리하는 방법인 메서드는 달라지더라도 말이다.
이를 통해 설계를 유연하고 재사용 가능하게 만든다. 이는 송신자는 수신자의 종류를 모르더라도 메시지를 전송할 수 있다. 이는 수신자의 종류를 캡슐화한다. 따라서 송신자에게 영향을 주지 않고 수신자를 자유롭게 추가하고 삭제할 수 있음을 뜻한다.
이전의 보았던 객체의 타입을 생각해보면 객체의 행동에 따라 객체의 타입이 정해진다고 했다. 이를 다형성이라는 주제에서 생각해보면 동일한 행동을 하는 서로 다른 객체들은 동일한 객체의 타입이라고 할 수 있다.
다형성은 송신자와 수신자 간의 객체 타입에 대한 결합도를 메시지에 대한 결합 도로 낮춤으로써 당성 된다. 객체지향이 유연하고 확장 가능하고 재사용성이 높다는 명성을 얻게 된 배경에는 다형성이라는 강력한 무기가 있었기 때문이다.
(내가 정녕 이 무기를 활용하고 있었는지 고민해야할 때다.)
송신자가 수신자에 대해 매우 적은 정보(메시지를 수신하고 처리할 것이라는 정보?)만 알고 있더라도 상호 협력이 가능하다는 사실은 설계의 품질에 큰 영향을 미친다.
그 이유는 송신자는 수신자가 메시지를 이해한다면 누구라도 상관하지 않기에 수신자를 다른 타입 객체로 대체하더라도 송신자는 알지 못한다 따라서 송신자에 대한 파급효과 없이 유연하게 협력을 변경할 수 있다.
또한 협력이 수행되는 방식을 확장할 수 있다. 송신자에게 아무런 영향을 미치지 않고서도 수신자를 교체할 수 있기 때문에 협력의 세부적인 수행방식을 쉽게 수정할 수 있다.
확장하기 위해선 단지 새로운 유형의 객체를 협력에 넣기만 하면 된다.
그리고 협력이 수행되는 방식을 재사용할 수 있다. 협력에 영향을 미치지 않고서도 다양한 객체들이 수신자의 자리를 대체할 수 있기 때문에 다양한 문맥에서 협력을 재사용할 수 있다.
즉 협력 자체는 수신자 역할을 할 수 있는 객체가 존재하는 곳에서 전부 재사용이 가능하다.
무엇이 재사용성이 높고 유연하고 확장가능하게 만들까? 다형성을 지탱하는 메시지이다.
다형성이란 동일한 메시지를 서로 다른 객체가 자신만의 방법으로 메시지를 수신 및 처리하는 과정인데 여기에는 메시지라는 중요한 소스가 존재한다.
메시지는 송신자와 수신자 사이의 결합도를 낮춘다. 그 이유는 송신자는 오직 메시지를 바라본다. 수신자가 메시지를 이해하고 처리해줄 것이라는 사실만 알아도 충분하다.
수신자와 송신자는 메시지로 결합되어 있고 이 두 객체 사이의 낮은 결합도가 바로 설계를 유연하게 만드는 비결이다.
이렇게 까지 메시지를 강조하는 것으로 보아 메시지는 객체지향의 핵심이라 할 수 있을 것 같다.
클래스 기반 객체지향 언어를 바라볼 때 객체지향 설계를 해야 한다면 이전에 나는 클래스에서 무엇을 어떻게 해야 하는지 두 가지를 처리하려고 했던 것 같다. 근데 이것이 "오해"였다.
난 이 객체가 해야할 책임을 정의해야 했고 협력을 찾아야 했고 어떤 메시지를 송수신할지 정했어야 했다....
클래스가 실제로 코드를 구현하기 위해 사용하는 추상화 도구인 것도 사실이다. 다만 객체지향에서는 클래스가 아닌 객체들이 주고받는 메시지로부터 강력함이 나온다고 한다.
애플리케이션이 클래스를 통해 만들어지지만 결국 클래스 내부엔 메시지가 존재하게 된다. 그리고 애플리케이션에서 중요한 역할을 맡는 것은 클래스가 아닌 객체이다.
따라서 클래스를 정의하는 것이 먼저가 아닌 객체들의 속성과 행위를 식별하는 것이 우선이며, 클래스는 객체의 속성과 행위를 담는 프레임일 뿐이다.
정적인 클래스들의 집합으로 애플리케이션을 구성할 것이 아니라 메시지를 주고 받는 객체들의 집합으로 바라보는 시선이 객체지향의 첫걸음으로 보인다.
이를 간단하게 정리할 수 있는 문구가 있다.
" 진정한 객체지향 패러다임으로의 도약은 개별적인 객체가 아니라 메시지를 주고받는 객체들 사이의 커뮤니케이션에 초점을 맞출 때 일어난다 "
그렇지 않을까? 커뮤니케이션에 사실 상 달성해야할 목표가 있기 때문에 더 넓은 시야를 볼 수 있는 계기가 될 수 있다고 생각한다. 협력이라는 환경에서 객체가 다른 객체에게 제공해야 하는 메시지에 대해 고민하자.
스프링 웹 프레임워크에는 사용자의 요청을 처리할 수 있는지 검사하는 부분과 해당 요청을 처리하는 핸들러라는 개념이 있다.
사용자의 요청을 처리하는 핸들러를 찾는 객체는 핸들러를 찾으라는 메시지를 받아 처리할 수 있는 핸들러를 찾아 반환하고 송신자는 그 결과를 통해 요청을 처리할 수 있는 객체에게 요청을 처리해달라고 메시지를 전달한다.
훌륭한 객체지향 설계는 어떤 객체가 어떤 메시지를 전송할 수 있는가와 어떤 객체가 어떤 메시지를 이해할 수 있는가를 중심으로 객체사이의 협력 관계를 구성하는 것이다.
요즘이야 어노테이션 기반 맵핑이 사실상 표준으로 자리매김하였지만 과거에는 불가능했다. 스프링은 시대를 읽고
이를 빠르게 반영했다.
빠르게 반영할 수 있었던 이유는 훌륭한 객체지향 설계가 바탕이 된다고 생각된다.
송신자는 수신자가 메시지를 어떻게 처리하는데 관심을 두지 않는다. 얇은 끈인 메시지로 이루어져있기 때문인데
이를 통해 수신자 역할을 하는 핸들러에 어노테이션을 기반으로 요청을 처리하는 새로운 객체를 만들어 끼워넣기에 이러한 유연한 확장이 가능했다.
메시지를 중심으로 설계하는 방법인 책임-주도 설계를 하기위한 조언 중 하나는 메시지를 결정하기 전까지는 객체에 관해 고민하지 말아야 한다는 점이다.
메시지를 결정하는 시점에서는 어떤 객체가 메시지를 수신할 것인지를 알 수 없기 때문에 당연히 메시지 송신자는 메시지를 수신할 객체의 내부 상태를 볼 수 없다. 따라서 메시지 중심의 설계는 메시지 수신자의 캡슐화를 증진시킨다.
그리고 송신자는 수신자의 내부 상태를 미리 알 수 없기에 느슨한 결합이 형성된다.
'독서에서 한걸음' 카테고리의 다른 글
Clean Code .Part4 (0) | 2022.04.09 |
---|---|
Clean Code .Part3 (0) | 2022.04.07 |
Clean Code .Part 2 (0) | 2022.04.06 |
도메인 (0) | 2022.04.01 |
자율적인 책임 (0) | 2022.03.29 |
댓글