객체지향에 대하여

찰규

·

2025년 11월 11일 (16일 전)

객체지향에 대하여

객체지향 프로그래밍(Object-Oriented Programming, OOP)은 현대 소프트웨어 개발에서 가장 지배적인 패러다임 중 하나입니다. 그러나 종종 '객체(Object)'와 '클래스(Class)'라는 용어 자체에 매몰되어, 그 본질적인 철학과 강력한 메커니즘을 간과하는 경우가 많습니다. 본 글에서는 객체지향의 창시자 중 한 명인 앨런 케이(Alan Kay)의 통찰을 바탕으로, '메시지', '캡슐화', '다형성'이라는 세 가지 핵심 요소를 통해 객체지향의 진정한 의미를 탐구하고자 합니다.

1. 객체란 무엇인가: 속성과 행동의 논리적 단위

객체지향의 첫 단추는 '객체'의 정의에서 시작합니다. 객체는 우리가 다루고자 하는 문제 영역 내에서 고유한 '상태(State; 속성/데이터)'를 가지며, 정의된 '행동(Behavior; 기능/메서드)'을 수행할 수 있는 논리적인 단위를 의미합니다.

  • 상태(Properties): 객체가 보유하고 있는 데이터, 즉 객체의 현재 정보를 나타냅니다. 예를 들어, '자동차' 객체는 '색상', '모델명', '현재 속도'와 같은 속성들을 가집니다.
  • 행동(Actions): 객체가 수행할 수 있는 동작 또는 기능을 의미합니다. '자동차' 객체는 '가속하다', '정지하다', '경적을 울리다' 등의 행동을 통해 자신의 상태를 변경하거나 외부에 영향을 미칠 수 있습니다.

객체는 이처럼 상태와 행동을 포함하는 자율적인 존재이며, 이들을 통합하여 관리하는 것이 객체지향 설계의 기본 전제가 됩니다.

2. 캡슐화와 설계 원칙: '조화로운 묶음'과 '느슨한 결합'

객체의 상태와 행동을 하나의 단위로 묶는 행위는 객체지향의 중요한 원칙 중 하나인 '캡슐화(Encapsulation)' 로 이어집니다. 캡슐화는 객체의 내부 구현을 외부로부터 숨기고, 오직 정의된 인터페이스(메시지)를 통해서만 접근하도록 하여, 정보 은닉(Information Hiding)을 달성하는 메커니즘입니다.

이를 설명하는 좋은 비유는 바로 '햄버거 세트' 입니다. 우리가 햄버거 세트를 주문할 때, 개별 메뉴(햄버거, 감자튀김, 콜라)를 일일이 요청하는 대신 '빅맥 세트'라는 하나의 명칭으로 주문합니다. '빅맥 세트'라는 객체는 여러 구성 요소(속성)와 그들을 함께 제공하는 기능(행동)을 캡슐화하여, 사용자에게 단순하고 효율적인 사용 방식을 제공합니다.

하지만 캡슐화는 단순히 무언가를 묶는 것을 넘어, **'조화롭게 묶는 것'**이 중요합니다. '햄버거와 된장찌개가 세트로 묶인 경우'를 상상해본다면, 서로 이질적인 요소들의 무분별한 결합은 오히려 비효율과 혼란을 초래할 것입니다.

이것이 바로 객체지향 설계의 핵심 개념인 '응집도(Cohesion)'와 '결합도(Coupling)' 로 설명됩니다.

  • 높은 응집도 (High Cohesion): 객체 내부의 요소들이 하나의 목표를 달성하기 위해 얼마나 긴밀하게 관련되어 있는지를 나타냅니다. 햄버거 세트처럼, 객체의 속성과 행동이 공동의 목적을 지향하며 강하게 묶여 있을 때 응집도가 높다고 합니다. 이는 객체의 단일 책임 원칙(Single Responsibility Principle)과 밀접하게 연결됩니다.
  • 낮은 결합도 (Low Coupling): 객체들이 서로 얼마나 독립적으로 존재하며, 한 객체의 변경이 다른 객체에 미치는 영향이 적은 정도를 나타냅니다. 햄버거 세트의 콜라 종류가 바뀌더라도 다른 구성 요소에 영향을 주지 않는 것처럼, 객체 간의 의존성이 낮을 때 결합도가 낮다고 말합니다.

객체지향 설계의 목표는 항상 '높은 응집도'와 '낮은 결합도' 를 달성하여, 시스템의 유연성, 확장성, 그리고 유지보수성을 극대화하는 것입니다.

3. 객체지향의 세 가지 핵심 기둥: 메시징, 캡슐화, 그리고 다형성

앨런 케이는 "객체지향"이라는 용어를 만든 것을 두고 다음과 같은 아쉬움을 표했습니다.

"I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea. The big idea is messaging." ("오래 전 이 주제에 대해 '객체'라는 용어를 만들어낸 것에 대해 미안하게 생각한다. 그 용어가 너무 많은 사람들이 덜 중요한 아이디어에 집중하게 만들었기 때문이다. 진정한 큰 아이디어는 메시징이다.")

이 발언은 객체지향의 본질이 단순히 '객체'나 '클래스'를 만드는 행위를 넘어, 객체들이 서로 소통하는 방식, 즉 '메시징(Messaging)' 에 있음을 강조합니다. 메시징을 중심으로 캡슐화(Encapsulation) 와 다형성(Polymorphism, 동적 바인딩) 이 상호작용한하며 객체지향의 강력함을 이끌어냅니다.

  1. 메시징 (Messaging): 객체 간의 유일하고 직접적인 상호작용 수단입니다. 객체는 다른 객체의 내부를 들여다보거나 직접 조작하지 않으며, 오직 메시지를 통해 "요청"을 보내고 "응답"을 받습니다. 이는 마치 서로 격리된 컴퓨터들이 네트워크(LAN선)를 통해 통신하는 것과 유사합니다. "A 객체가 B 객체에게 '이 작업을 수행해 달라'고 메시지를 보내면, B 객체는 자신의 책임 하에 해당 작업을 처리하고 결과를 반환합니다." 이 과정에서 A 객체는 B 객체가 그 작업을 '어떻게' 수행했는지에 대해서는 알 필요도, 관심 가질 필요도 없습니다.
  2. 캡슐화 (Encapsulation): 객체의 내부 상태와 행동을 감추어, 외부에서는 정해진 메시지(공개된 메서드)를 통해서만 객체에 접근할 수 있도록 합니다. 캡슐화는 객체의 내부 구현을 보호하고 변경 용이성을 높이며, 객체가 메시징을 통해 상호작용하는 근본적인 이유를 제공합니다. 즉, 객체의 내부가 철저히 감춰져 있기 때문에 외부에서는 '메시지'라는 약속된 통로로만 소통해야만 하는 것입니다.
  3. 다형성 (Polymorphism, 동적 바인딩): '다양한 형태(Poly: 다형, morph: 형태)를 가질 수 있음'을 의미하며, 특히 객체지향에서는 "동일한 메시지에 대해 객체의 타입에 따라 서로 다르게 반응하는 능력" 으로 발현됩니다. 예를 들어, print()라는 동일한 메시지를 Dog 객체에게 보내면 "멍멍!" 소리를 내고, Cat 객체에게 보내면 "야옹!" 소리를 내는 것입니다. 이 다형성은 런타임 시점에 실제 호출될 메서드가 결정되는 '동적 바인딩(Dynamic Binding)' 메커니즘을 통해 구현됩니다. 메시지를 보내는 객체는 메시지를 받을 객체의 구체적인 타입에 대해 알 필요 없이, 단순히 '이러한 메시지를 처리할 수 있는 객체'라고만 알고 있으면 됩니다.

이 세 가지 요소(메시징, 캡슐화, 다형성)는 서로 긴밀하게 연결되어 시너지를 창출합니다. 캡슐화는 메시징을 가능하게 하는 토대를 마련하고, 메시징은 다형성을 통해 시스템의 유연성과 확장성을 극대화합니다. 그리고 이 모든 것은 객체 간의 '느슨한 결합' 을 달성하여 시스템의 전반적인 품질을 향상시킵니다.

4. 객체지향의 진정한 본질: 역할과 책임, 그리고 협력

결론적으로, 앨런 케이의 통찰처럼 객체지향의 진정한 본질은 '클래스'나 '객체' 그 자체보다, '메시징'을 통해 이루어지는 객체들 간의 협력 방식에 있습니다.

객체지향 설계는 "각자의 명확한 역할과 책임을 가진 자율적인 객체들이 메시지를 주고받으며 유기적으로 협력하여 복잡한 문제를 해결하는 시스템을 구축하는 사고방식" 입니다. 객체는 자신의 상태를 캡슐화하고, 필요한 기능은 메시지를 통해 다른 객체에게 위임하며, 이 과정에서 다형성을 활용하여 코드의 유연성과 재사용성을 높입니다.

따라서 우리는 더 이상 '어떤 클래스를 만들까?', '어떤 객체를 인스턴스화할까?'에만 매몰되지 않고, '객체들이 어떻게 메시지를 주고받으며 상호작용할까?' 에 집중해야 합니다. 이것이야말로 강력하고 유연하며 유지보수하기 쉬운 소프트웨어를 개발하기 위한 객체지향의 핵심 원칙이자 철학입니다.

마무리 하며

우리가 오늘 나눈 '햄버거 세트'와 '된장찌개 세트'의 비유, 그리고 앨런 케이의 "객체가 아닌 메시지가 본질이다"라는 통찰은 객체지향의 근본적인 의미를 다시 한번 되새기게 합니다. 이제 우리는 더 이상 '어떤 클래스를 만들까?', '어떤 객체를 인스턴스화할까?'라는 표면적인 질문에만 머물러서는 안 될 것입니다.

진정한 객체지향적 사고는 "각각의 객체가 어떤 역할과 책임을 가지며, 어떤 메시지를 통해 서로 유연하고 견고하게 협력할 것인가?" 라는 질문에서 시작됩니다. 이 관점으로 코드를 설계하고 바라본다면, 우리는 단순히 기능을 구현하는 것을 넘어, 변화에 강하고 확장성이 뛰어난 시스템을 구축하는 진정한 개발자로 거듭날 수 있을 것입니다.