'객체지향의 사실과 오해'를 읽고

이상민·2022년 1월 30일
0

독후감

목록 보기
2/2
post-thumbnail

1. 객체지향?

최근 기회가 되어 조영호님의 객체지향의 사실과 오해를 읽게 되었다. 이전에 객체지향이라하면 SOLID, 다형성, 상속, 디자인패턴 등등 단편적인 얕은 지식만 알고 있었다. 그래서 '이렇게 해라'라는 건 조금 알고 있었지만, 그걸 결국 왜 해야하고 어떤 의미가 있는지는 알지 못했다. 물론 입문서 한권을 읽었다고 바로 실무에서 객체지향적인 코드를 마구마구 작성할 수 있을리는 없다. 하지만 이 책 덕분에 객체지향의 본질이 무엇인지는 이해하게된 것 같다. 오늘은 이 책을 읽으면서 나의 관점이 바뀐 부분들 위주로 정리해본다.


2. 현실세계와 객체지향 세계

객체지향이 현실 세계를 오롯이 모방하기만 한다는 것은 오해일 뿐이다.

이전까지 나는 객체지향이란 현실세계의 사물을 코드상에서 데이터와 행동을 가진 객체로 만들어 현실세계를 복제하므로서 이해하기 쉬운 프로그래밍을 하는 것이라고 생각했다. 하지만 이는 틀리다! 예를 들어 현실 세계에서 TV는 혼자 켜질 수 없다. 리모컨을 사용하던, 켜짐 예약을 하던 사람의 동작에 의해서만 켜질 수 있다. 하지만 객체지향 세계에서는 다르다. 객체 지향 세계에서 TV는 스스로가 켜질 수 있는 행동을 가질 수 있다. 이러한 현실세계와 객체지향 세계의 차이 때문에 책에서는 '모방'이라는 단어보다 '은유'라는 단어를 선호한다. 우리의 실제 세계와 1대1로 맵핑되지는 않지만, TV라는 개념의 존재를 객체로 은유하여 이해의 어려움을 줄일 수 있다. 객체지향에서 객체는 능동적이고 자율적이다. 오해하고 있을때는 행동을 잘못된 곳에 두고는 했다

// 현실에서 Tv는 스스로 켜거나 끌 수 없지만 객체지향 세상에서는 가능하다
class Tv {

    Power power;
    
    void turnOn() {
        power = Power.ON;
    }

}

3. 클래스가 아니라 객체 중심

객체지향의 중심은 클래스가 아닌 객체이다. 클래스는 단지 동적인 객체들의 특성과 행위를 정적인 텍스트로 표현하기 위한 추상화 도구일 뿐이다.

기존에는 딱히 클래스와 객체를 분리해 생각해본적이 없었다. 오히려 분리해 생각하지 않고, 내가 작성한 클래스를 위주로 생각해 클래스 중심적으로 생각했던 것 같다.

class Counter {

    private int count = 0;
    
    void incrementCount() {
        this.count += 1;
    }

}

class Main {

    public static void mian(String[] args) {
        var counter = new Count();
        counter.incrementCount();
    }

}

위 코드에서 카운터를 증가 시켰을때 변화하는건 클래스인가? 아니다 클래스의 인스턴스인 객체에 변화가 있는 것이다. 이처럼 클래스 중심적으로 생각하는 것과 객체를 중심적으로 생각하는 것에는 뉘양스 차이가 있다. 심지어 클래스가 없는 객체지향 언어들도 있다. 대표적으로 자바스크립트 같은 프로토타입 기반 프로그래밍 언어들이 그렇다. 클래스는 도구일 뿐이고 객체지향에 중심은 객체이다.


4. 메시지 중심

객체지향의 핵심은 메시지이다.

객체간의 소통이 메시지를 통해 이루어진다는 점도 주의해야한다. 일반적으로 객체를 이야기할때 상태와 동작을 한곳에 모아둔 단위로 말한다. 물론 맞는 말이지만, 상태는 동작에 의해 결정된다는 점에 유의하자. 객체에 동작을 결정하고, 그 동작의 결과를 저장 하기 위해 상태를 정해야한다. 상태를 우선적으로 생각하면 외부로의 노출이 많아저 캡슐화가 저하되고, 객체간 메시지로 통하는 것이 아니라 상태로 통해 협력을 줄이고 따라서 재사용성도 저하된다. 객체간 연쇄적으로 메시지를 전송하고 수신하는 협력 관계를 기반으로 사용자에게 유용한 기능을 제공하는 것이 객체지향의 중심 사상이다.

// 상태 우선
class User {

    Status status;
    
    class Status {
    	ACTIVE, BLOCKED;
    }

}

class UserBlockService {
    
    public void blockUser(User user) {
        if (!user.status == User.Status.BLOCKED) {
            user.status = User.Status.BLOCKED;
        }
    }
    
}
// 메시지 우선
class User {

    private Status status;
    
    private class Status {
        ACTIVE, BLOCKED;
    }
    
    public boolean isBlocked() {
        return this.status == Status.BLOCKED;
    }
    
    public void block() {
        if (!this.isBlocked()) {
            this.status = Status.BLOCKED;
        }
    }

}

class UserBlockService {
    
    public void blockUser(User user) {
        user.block();
    }
    
}

5. 책임과 역할

책임 주도 설계에서는 어떤 행위가 필요한지를 먼저 생각하고 그 다음에 어떤 객체가 이를 수행할지를 생각한다.

어떤 객체가 어떤 행동(메시지)을 할지 정하려면 결국 해당 객체의 책임과 역할에 대해서 생각해봐야한다. 이 과정에서 추상화와 캡슐화에 대해 생각해 볼 수 있다. 추상화란 불필요한 부분을 제거하고 필요한 부분을 강조해 본질을 드러나게 하는 것이다. 복잡성을 이해하기 쉬운 수준으로 단순화하는 것으로, 목적에 따라 그 추상화 수준은 다를 수 있다. 캡슐화란 기능을 제공하면서 그 구현에 대해서는 은닉하는 것이다. 객체 단위로 보통 생각하지만 더 넓은 의미에서 모듈 또한 캡슐화를 할 수 있다.

추상화와 캡슐화의 개념은 때론 구분이 명확하지 않을 때가 있다. 이는 이 둘의 관점이 다른 것일뿐, 상호 베타적이지는 않기 때문이다. 예를 들어 JDBC는 각 벤더의 드라이버와 DB와 연결하는 것과 같이 복잡성을 단순화한 관점에서는 추상화이다. 또한 JDBC의 구현에 대해 모르더라고 사용할 수 있도록 기능을 제공한다는 점에서는 캡슐화이다.

다시 책임과 역할의 얘기로 돌아와서, 객체의 책임과 역할을 기준으로 어느정도로 추상화하고 또 캡슐화할지 결정해서 자율적인 객체를 만들어야한다. 자율적인 객체는 적절한 추상화 수준을 가지고, 높은 응집도와 낮은 결합도로 캡슐화를 증진한다. 또한 인터페이스와 구현이 분리가 되기 때문에 유연성과 재사용성이 향상된다.

여기서 또 중요한 점은 정도껏 캡슐화/추상화 해야한다는 것이다. 객체지향의 장점은 확장에 열려 있고 변경에 닫혀있는 것이지 처음부터 완벽한 프로그램을 만들기 위함이 아니다. 오히려 과도한 캡슐화/추상화로 인해 생산성이 떨어질 수도 있다.


6. 안정적인 구조를 제공하기 위한 도메인 객체

객체지향의 핵심은 어플리케이션이 앞으로 어떻게 진화할지 예측할 수 없으니, 객체간 메시지를 통한 소통을 기반으로 확장에 열려 있고 변경에 닫혀 있는 프로그램을 만드는 것이다. 그렇다면 변화가 있을 때마다 기존의 코드는 버려지고 새로운 코드를 작성해야만 하는 것일까? 기능의 변화마다 버리고 새로 작성하는 코드의 양을 줄이기 위해 안정적인 구조 위에 기능을 프로그래밍 할 수 있다. 흔히 도메인 객체라고 부르는 것이 이러한 구조 역할을 한다.

예를 들어 어떤 은행 계좌 관련된 어플리케이션이 있다고 하자. 시간이 지남에 따라 어떠한 혜택으로 인해 이체 수수료가 달라진다거나, 이체가 불가능한 시간이 바뀐다거나 아니면 계좌를 통해 대출을 받을 수 있게 된다거나, 카드와 연결해 사용한다거나 매우 다양한 기능 확장/변경이 있을 수 있다. 하지만 근본적으로 은행의 체계가 바뀌지 않는 이상, 계좌는 잔액을 확인할 수 있을 것이고 다른 계좌로 금액을 이체할 수 있을 것이다. 이런식으로 도메인의 근본적인 지식과 행동을 담는 것이 도메인 객체이다.

변화가 가능한 기능과 크게 변화하지 않을 구조를 구분하고 구조를 도메인 객체로 만드므로써 코드의 재사용성을 높이고 생산성을 높일 수 있다. 기능에 변화가 있다고 모든 코드를 새로 작성할 필요가 없다!


7. 객체지향적으로 개발하기

맨 처음에 말했듯 이 얇은 책을 한권 읽었다고 객체지향에 통달해서 완벽한 객체지향적 개발을 할 수 있을리 없다. 애초에 통달했다고 해도(그게 뭔지 모르겠지만...) 어떤 코드가 객체지향적인지는 다분히 개인마다 생각이 다를 것이다. 하지만 위에서 계속해서 생각한 객체지향의 목적과 특징에 대해 생각하면서 개발한다면, 분명히 이전보다 더 좋은 개발을 할 수 있을 것 같다.

profile
편하게 읽기 좋은 단위의 포스트를 추구하는 개발자입니다

0개의 댓글