반응형

객체지향의 사실과 오해

 

"객체지향의 사실과 오해" 책의 3부 "타입과 추상화" 부문 리뷰이다.

 

2부에서는 객체의 정의에 대해 알아보았다. 객체는 상태와 행동을 가지고 있으며 서로 관련이 있다.

이제는 시스템 내에 있는 각 로직들을 어떠한 기준으로 합치고 나누어 객체로 만들어야 하는지 알아야 한다. 

 

 

이 2부에서 난 큰 충격을 받았다. 갑자기 추상화에 대한 일화가 나와서 당황하고 흐름이 끊기는 것 같았지만 신선한 충격을 가져다 주었다. 바로 영국이 처음에 지하철 노선도를 도입했을 때 일화이다.

 

 

처음에는 위와 같이 지형과 섞여 있는 지하철 노선도(1926)였다고 한다. (1919년에는 이것보다 더 단순했지만 설명을 위해 이 지도가 처음이라고 가정한다.) 지형(도로, 강)과 역의 위치, 역 간의 거리 모두 사실적으로 표현되어 있다. 모든 정보가 정확하지만 우리 눈에는 너무 보기가 어렵고 불편하다. 도시가 골고루 발전하지 않고 도심 중심에서 퍼지면서 개발되기 때문에 역이 특정 지역에 모여 있다. 역들이 서로 엉켜 제대로 정보를 표시해주지 못하고 있다.

 

 

1928년 지하철 노선도를 다시 그렸다. 지형 정보는 크게 중요한 것이 아니라서 얕게 표시하고 지하철 노선도만 명암을 주어 표시했다. 하지만 첫 번째 지도와 마찬가지로 도심(도시 중앙 지역)에 역이 몰려 있어 보기가 불편하다. 여러 개의 노선이 지나가는 구역들은 이름이 어떤 것인지 구별하기가 쉽지 않다. 

 

 

1933년에 이르러 디자이너 헤리 백이 새롭게 디자인하면서 이 노선도가 현재 모든 지하철 노선도에 사용되고 있다. 지하철 노선도를 보는 사람들은 지형 정보가 중요하지 않다. 역 간의 거리도 중요하지 않다. 지하철에서 딴 짓을 하며 가다보니 시간을 솔직히 신경을 안 쓰며 몇 번 정차했는지만 중요하다. 거리, 지형이라는 정보를 과감히 삭제하니 우리가 원하는 정보에 손 쉽게 다가갈 수 있다.

 

내가 현재 역에서 도착역으로 가려면 어떻게 가야 하는가?

몇 개의 정류장을 거치는가?

어떤 노선들을 사용할 수 있는가?

 

모든 요구사항을 충족시킨다. 놀라웠고 충격을 받았다.

 

나도 객체지향을 잘 안다고 생각했었다. 클래스는 틀이며 객체는 그 틀에서 나온 공산품이라고 생각하고 그에 맞게 잘 코딩하고 있었다고 생각했다. 그래서 클래스 대상 개체를 면밀히 분석하고 개체 프로퍼티들을 추가하며 만족했었다.

예를 들어 음료수를 클래스로 만든다고 가정해보자.

 

public class drink {
    // 용량
    private final int volume;

    // 유통기한
    private final String expirationDate;

    // 칼로리
    private final int calorie;

    // 구성 요소
    private final String[] content;

    // 병뚜껑
    private final boolean lid;
}

 

음료수 캔을 이리 저리 보면서 용량, 유통기한, 칼로리, 구성 요소, 병뚜껑 여부 등을 프로퍼티로 만들었다. 하지만, 이 클래스는 위 노선도와 같이 불필요한 정보를 가질 수도 있다는 것이다. 만약 이 음료수가 배틀 그라운드라는 게임에 사용된다고 생각해보자. 이 음료수에 있는 칼로리, 병뚜껑, 유통기한 항목들은 필요가 없다. 그냥 던져서 사람을 맞출 용도이니까.

 

다시 돌아가서 객체로 만드려면 어떠한 기준으로 모으고 나누어야 하는지 정해야 한다고 했다. 일단 구현하려고자 하는 시스템의 목적이 무엇인지, 요구사항이 무엇인지 확인한다. 그리고 아래와 같이 추상화한다.

 

개념들 간의 공통점은 취하고, 차이점은 버리는 일반화를 통해 단순화한다.

중요한 부분을 강조하기 위해 불필요한 세부 사항들을 제거한다.

 

목적이 있으니까 불필요한 세부사항들을 가려낼 수 있다는 점을 기억해야 한다.

 

개념은 다시 심볼, 내연, 외연으로 나뉜다. 심볼은 이름이나 명칭이라 하고, 내연은 정의를 뜻하며, 외연은 집합을 의미한다. 굳이 저렇게 나눌 필요가 있을까 싶다. 그 뒤에 나오는 "개념 == 타입(클래스)" 이라는 말이 더 중요해 보였다.

 

객체가 어떤 타입에 속하는지는 객체가 수행하는 행동에 달려있다. 그 객체들이 동일한 행동을 수행하면 동일한 타입으로 본다. 객체의 내부적인 표현 방식이 다르더라도 외부로 전달하는/전달받는 메세지가 같다면, 동일한 행동을 한다면 동일한 타입으로 본다. 결국 또 행위이다. 오로지 행위에 의해서만 분류할 수 있다.

 

이러한 타입은 클래스처럼 일반화/특수화 관계를 이루며 계층 구조를 가질 수 있다. 추상화를 수행하면서 세부 상항이지만 불필요하지 않을 때 슈퍼 타입과 서브 타입으로 분류하면 된다.

 

끝마치며...

행동/행위에 따라 객체를 분류하기 때문에 데이터를 먼저 생각하는 데이터 주도 설계가 아닌 책임 주도 설계를 해야 한다는 말이 여기서부터 나오게 된다. 앞으로 역할, 책임, 협력을 조금 더 자세히 살펴보게 된다.

반응형
반응형

객체지향의 사실과 오해

 

"객체지향의 사실과 오해" 책의 2부 "이상한 나라의 객체" 부문 리뷰이다.

 

1부까지는 객체지향이 실세계와 다르며 자율성을 가진 객체들의 협력 시스템이라는 점을 강조했다.

객체들에게 책임감을 부여하고 간섭을 하지 않으려면, 명확한 경계가 필요하다. 어떻게 객체들을 나누어야 하며 객체란 무엇인지 확실히 정의를 해두어야 설계할 때 혼란이 없다. 그렇다면 정의는 과연 무엇일까? 필자도 여러 방면으로 생각을 해보았지만, 가장 근사한 대답은 "일반적인 특징들의 집합" 이 정의라고 생각했다. (주의할 점은 성급한 일반화의 오류는 피해야 한다.)

 

그래서 이 책에서는 일단 객체들의 특징들을 쉽게 설명하기 위해 '이상한 나라의 엘리스' 동화에 나오는 엘리스를 객체로 보고 특징들을 찾아내기 시작했다. 엘리스가 모험하는 과정에서 키가 작아지고 커져야 비로소 다른 세계를 갈 수 있는데 이런 행동들은 특징점이 있다. 키라는 상태에 따라 행동을 할 수 있고 엘리스의 행동에 의해 위치라는 상태가 바뀐다. 즉 다시 말해, 행동과 상태가 서로를 참조해서 다음 행동들을 결정 짓는다.

 

게임 프로그래밍 패턴 중 "상태 패턴" 이 있는데 이와 개념이 유사하다. 행동을 했는지 여부를 조건으로 다음 행동을 결정지으면 조건을 삼은 행동이 어떤 행동에 의해 유발되었는지 모두 체크해야 하므로 아래와 같이 복잡한 구조를 띄게 된다.

 

행동의 여부로 검사를 하게 된다면...

 

F 라는 행동 다음에 G 라는 행동을 하려고 한다고 가정하자.

그럼 F 라는 행동이 어떤 행동들로 인해 순차적으로 실행이 되었는지 관련 이력들을 모두 찾아봐야 한다. A 행동으로 부터 온 것인지, C 행동으로 부터 온 것인지 말이다. 예를 들어 F 가 "B 라는 버튼을 누른다" 행동이고 G 가 "플레이어가 점프" 하는 행동이라고 해보자. 게임이 무리없이 진행이 될 것 같아 보인다. 하지만 "이 플레이어는 점프가 가능하게 만들자" 라는 요구사항이 새롭게 요구되면 지금 점프 중인지 체크를 하는 코드를 삽입할 것이다.

 

행동은 무한하며 과거의 행동들에 대한 이력들을 모두 점검해야 된다. 그러나 상태는 유한하다. (FSM)

상태를 정의하고 상태에 따라 프로그래밍한다면, 더 손쉽게 개발할 수 있게 된다.

친절하게도 객체지향의 사실과 오해라는 책에서는 객체를 정의할 때 위와 같은 특징들을 놓치지 않고 적어두었다.

 

  • 객체는 상태를 가지며 상태는 변경 가능하다.
  • 객체의 상태를 변경시키는 것은 객체의 행동이다. 행동의 결과는 상태에 의존적이다.
  • 객체는 어떤 상태에 있더라도 유일하게 식별 가능해야 한다.

 

객체의 정의가 무엇인지 파악하기 위해 위와 같이 특징들을 추출했다. 그렇다면 상태는 무엇일까?

 

상태는 객체를 표현하는 일반적인 값일 수도 있고 다른 객체일 수도 있다. 객체지향 세계는 객체가 연결되어 있는 세계이기 때문에 다른 객체들을 가지고 있을 수 있다. 하나의 독립적인 자율개체이지만 어떤 객체의 상태를 표현하는 값이 될 수도 있다. 일반적인 값들은 정적이며 프로퍼티라고 하며 객체 안에 포함된 객체들은 동적이며 프로퍼티 값이라고 한다. 객체와 객체 사이에 연결이 되어 있어야만 하나의 상태로 표현될 수 있으며 언제든지 링크를 끊을 수 있다는 특징도 있다.

 

상태는 어떤 객체가 가지고 있는 정보의 집합으로써 정적인 프로퍼티와 동적인 프로퍼티 값으로 이루어진다는 것이다.

 

상태를 설명하며 자연스레 행동의 특징이 설명되었다. 행동은 자신의 상태를 변경하는 일련의 작업이다.

그런데 객체는 내부에 다른 객체를 가지고 있을 수도 있다. 직접 내부 객체의 상태를 바꿀 수 없으므로 내부 객체에게 메세지를 전달해야 한다. 개념을 합치면 행동은 자신의 상태를 변경하는 작업 + 내부 객체에게 메세지를 보내는 작업이다.

 

폐쇄적인 세계이다보니 이상한 특징들이 있다. 내부 객체가 제공하는 행동만 메세지를 보낼 수 있다는 점이다.

그 내부 객체가 행동을 제공하지 않으면 연결 고리가 없는 셈이며 이는 곧 고립이 된다. 그래서 상태부터 고려하지 말고 행동부터 정의하고 그 행동들을 유한 상태로 만들 수 있는 상태들을 정의해야 한다라고 한다.

 

이를 책임 주도 설계. (Responsibility-Driven Design) 라고 하고 행위가 우선이 되어야 한다라는 점을 나중에 강조하기 위해 복선을 깔아둔다.

 

2부에서는 객체의 정의가 무엇인지 알 수 있었다. 하지만 아직 특징만 파악했을 뿐 어떻게 나누어야 하는지 알 수 없다.

다음 부에서 설명하게 된다.

반응형
반응형

객체지향의 사실과 오해

 

"객체지향의 사실과 오해" 책의 1부 "협력하는 객체들의 공동체" 부문 리뷰이다.

 

"객체지향은 실세계를 모방하는 것이 아니다" 라는 신선한 주제를 던지면서 시작한다.

조금 거리감이 있음에도 불구하고 많은 사람들이 실세계를 모방하는 것이 객제지향이다라고 설명하는 것은 현대 사회와 객체지향이 "협력"이라는 관점에서 매우 비슷하기 때문이다. 각 객체들이 유기적으로 협력하며 자율적으로 행동하는 우리 사회의 모습을 초점을 두어 보면 틀린 말도 아니다.

 

그래서 이 책에서는 객체지향은 시스템을 자율성을 가진 객체들의 집합으로 바라보고, 책임들을 하나씩 부여해 분할하는 행위라고 규정지었다. 각각의 객체는 상태와 행위를 지니고 있으며 스스로 그 책임을 수행하기 위해 자율적으로 방법을 선택해야 한다고 한다. 그래서 그 자율성을 해치면 안 되기 때문에 외부에서 그 객체의 상태나 행위들을 지적하거나 간섭하면 안 된다고 서술하고 있다.

 

사람 간의 관계와 매우 유사하다고 생각했다. 사람은 스스로 생각할 수 있으며 스스로 행동한다. 우리 사회는 그런 사람들과 소통하며 협력하며 지낸다. 하지만 객체지향의 세계가 현실의 세계와 다른 점은 가르침을 받는 학생이나 가르침을 전수하는 선생님이 없다는 것이다. 모두가 어른이자 팀장이며 자율적으로 생각해서 처리하는 세계이고 요청과 응답만 있는 세계라는 것이다.

 

자신의 상태는 자신이 책임지어야 하며, 맡은 바 임무는 팀의 리더처럼 스스로 해야 한다는 것이다. 여러 개의 책임을 받아 하나의 역할로써 수행한다. 인사팀장, 기술팀장, 영업팀장처럼...

 

1장에서는 현실세계에 익숙한 사람들을 위해 현실세계에서 일어날 법한 커피 마시기 사례를 들어 객체지향의 중요한 개념들인 "역할", "책임", "협력" 등을 뽑아내어 각인시켰다.

반응형

+ Recent posts