「객체지향의 사실과 오해」는 프로그래머 입문자의 교과서다.
책에서는 「클린 아키텍처, 클린 소프트웨어」에서 한발 더 나아간 '협력-역할-책임'개념을 소개한다. 객체지향은 인간사회의 복사판이 아니며, 새로운 '객체들만의 세상'을 창조하는 일이다. 객체지향 어플리케이션이 실세계를 모방해야 한다는 개념은 많은 초보 프로그래머들을 '스파게티'코드로 이끌었다. 실세계를 그대로 표현하기 위한 억지스러운 연결관계(강한 연결), 굳이 필요치 않은 속성들은 프로그램의 확장성과 유지보수에 치명적인 단점으로 작용한다. 결국, 이를 쉽게 해결하는 대안으로 프레임워크( 뷰, 앵글러, 리액트, 등)를 선택하는데, 이는 결코 프로그래머 실력향상에 도움되지 않는다.
초보개발자는 스파게티 코드를 짜더라도 일단 아웃풋이 중요하다. 처음부터 설계에 신경쓰다보면 시작조차 하기 힘들다. 코드는 무조건 나와야한다.
외국어를 습득할 때 '용기'가 가장 중요한 것처럼 프로그래밍 역시 '구현'이 중요하다. 머리속에 있는 구상을 코드로 구현(아웃풋)해내는 것이야말로 프로그래머가 갖춰야 할 첫번째 자질이다. 여러가지 생각을 코드로 구현하다보면 결국 '유지보수'에 스트레스를 받게 된다. 이때 다음과 같은 상황이라면 큰 문제점을 느낀 것이다.
1) 한 부분을 수정했더니 프로그램 전체의 변동이 발생한다.
2) 특정 기능위주로 설계되어 있다. 기능이 살짝 바뀔 때마다 크게 수정해야 한다.
3) 한개의 매서드나 함수가 너무 많은 역할을 하고 있다.
4) 네이밍과 역할이 매칭되지 않고, 혼란스럽다.
5) 전역변수의 내용이 수시로 변경되고, 스코프 범위가 뒤죽박죽이다.
6) 데이터베이스 정보와 메인 엔진역할을 하는 코드가 드러나 있다.(최악::해킹위험up)
위와 같은 상황이 동시다발벅으로 발생한다면 드디어(?) 설계를 배울 단계가 온 것이다. 프로그래머는 허점이 많은 과정을 거쳐 점차 성장한다. 거대한 '진흙덩어리'같은 프로그램에 환멸을 느껴야만 객체지향 설계의 필요성을 느끼게 되고, 한 단계 발전할 수 있다.
1 역할-책임-협력
프로그래머가 되려고 특정 컴퓨터 언어를 실컷 배운다. 그리고 특정문제를 해결하기 위한 코드를 짜려 편집기를 실행한다. 그런데 막상 뭘 해야 할지 모른다. 대충 생각의 흐름대로 이벤트부터 몇개 붙여봤지만 금세 앞이 막힌다. 무엇이 문제일까?
영어를 배워서 외국인과 대화하는 상황을 생각해보자. 분명 영문법을 알고 있지만 간단한 근황토크에서부터 뭔가 막힌다. 대개 생각나는대로 말을하다보면 다음과 같은 상황이 된다.
어제 뭐했어?
갔었다. 경복궁에. 나는.
외국인과 대화할 때 막히는 이유는 문법을 몰라서가 아니라 머릿속에서 영어를 문법에 맞게 조합하느라 입이 바로 떨어지지 않기 때문이다. 프로그래밍 역시 설계를 제대로 또 많이 해보지 않은 프로그래머가 바로 코딩(구현)에 들어가면 즉시 막히게 된다. 아이디어를 그 자리에서 술술 코드로 풀어내는 방식은 '테스트주도 개발방식'인데, 이 정도가 되려면 많은 프로젝트를 통해 숙달되어야 한다. 문법이 문제가 아니다. 관련 문법을 몰라서가 아니라 어디에 연결하고, 역할을 부여하고, 관계를 만들지 모르기 때문에 구현이 느려지고, 점차 연결관계가 꼬여버린다.
하나의 세상을 만들고자 할 때는 그 세계 속에 있는 대상들의 연결관계를 먼저 파악할 필요가 있다. 또, 연결관계를 파악하기 위해서는 오고가는 메시지에 주목해야한다. 객체지향 세계에서 메시지는 곧 요청이다. 만일 메시지를 확인하고 나면 메시지를 받는 대상과 보내는 대상이 정해지고, 객체의 실체가 서서히 드러나게 된다. 객체가 하나둘씩 드러나면 속성이 정해진다. 처음부터 객체의 속성을 정하다보면 객체를 정확하게 표현하기 힘들어진다. 속성과 기능은 메시지를 주고받는 과정에서 협력과 역할 그리고 책임이 정해지면서 자연스럽게 드러나야 한다.
커피숍을 생각해보자. 손님이 매뉴판을 보고난 뒤, 커피를 주문한다. 바리스타는 주문을 받고, 커피를 만든 뒤에 벨을 울린다. 손님은 벨이 울리자 커피값을 지불하고, 커피를 받는다.
위에서 손님은 객체이며, 손님이 요청한 커피는 객체지향 세계에서 '메시지'다. 메시지를 받고, 바리스타(객체)가 커피를 만들기 시작하면, 바리스타라는 객체는 자신의 역할(커피제작)을 수행하는 것이며, 여기서 역할은 객체지향 세계에서 '메서드'다. 프로그래머는 객체지향이라는 하나의 세상을 창조해야하며, 이 세계에서 객체들은 모두 협력관계를 갖고 협력을 통해 역할을 부여받고, 책임을 다한다. 여기서 현실세계와 다른점은, 객체세계에서의 객체들은 모두 현실세계의 사람이라는 점이다.(의인화) 이들은 메시지를 받고 난 뒤부터 자율적으로 역할을 수행한다.(메서드) 이들의 협력적인 관계는 강압적이지 않고 느슨하게 짜여져 있으며, 요청받는 객체는 언제든지 변경가능하고, 각자 자신의 기능대로 맡은 책임을 처리하면 된다. 바로 이점이 절차지향과 객체지향의 가장 큰 차이점이라 할 수 있다. 객체지향 프로그래밍은 유연하고, 느슨하며 강한 연결과 관계로 이뤄져 있지 않다.
사용자가 최종적으로 인식하게 되는 시스템의 기능은 객체들이 성실히 협력해서 일궈낸 결실이다. 어플리케이션의 기능은 더 작은 책임으로 분할되고, 책임은 적절한 역할을 수행할 수 있는 객체에 의해 수행된다. 객체는 자신의 책임을 수행하는 도중에 다른 객체에게 도움을 요청하며, 결론적으로 시스템은 역할과 책임을 수행하는 객체로 분할되고 시스템의 기능은 객체 간의 연쇄적인 요청과 응답의 흐름으로 구성된 협력으로 구현된다.
객체지향 설계에서 명심해야 할 점은 객체지향 설계는 하나의 세계를 창조하는 예술이며, 적절한 객체에게 적절한 책임을 할당하는 것에서부터 시작된다는 개념이다. 책임은 객체지향 설계의 품질을 결정하는 가장 중요한 요소다. 만일 책임이 불분명한 객체가 있다면, 이들은 해당 어플리케이션의 미래 역시 불분명하게 만든다. 프로그래머가 얼마나 적절한 책임을 객체에 부여하고, 협력시키도록 하느냐에 따라 어플리케이션의 아름다움이 결정된다.
2 협력성
객체지향 설계에서 '신'과 같은 객체는 의미가 없다. 혼자서 모든 것을 처리하려는 객체는 결국 모든 것을 복잡하게 만들어버린다. 전지전능한 객체가 존재하면, 훗날 설계자조차 객체의 연결과정을 알 수 없게 된다. 객체는 협력을 해야하고, 협력을 위해서 '상태'와 '행동'을 가진다. 가령, 커피를 제조하는 바리스타가 제조 방법을 모른다는 것이 말이 되지 않는 것처럼 객체가 어떤 행동을 하기 위해 필요한 상태를 알지 못한다는 것 역시 말이 되지 않는다. 객체가 협력에 참여하는 과정에서 스스로 판단하고 결정하는 자율적인 존재가 되기 위해서는 필요한 행동과 상태를 함께 지녀야한다.
3 자율성
객체는 충분히 자유로워야 한다. 여기서 '자율'이란, 객체가 스스로 정한 원칙(책임)에 의해 요청에 따라 스스로 판단하고 결정하며 행동(역할)해야 한다는 의미다. 가령, '손님'이라는 객체가 있다면, 손님은 '주문'을 요청하는 행위와 절차를 스스로 판단하고 결정해야 한다. 만일 상점이 정한 단 하나의 원칙(두손을 위로 든다)에 의해서만 손님이 주문할 수 있다면, 해당 상점은 머지않아 경쟁자들에 의해 타격을 입을 것이다. 객체지향 설계에서는 이러한 연결을 '강한 연결'이라 부른다. '강한 연결'은 어플리케이션의 유연성을 떨어뜨리게 만드는 장본인이며, 기능 구현에만 치중되어 있기 때문에 외부변화에 취약하다.
객체들은 공동의 목표를 달성하기 위해 협력에 참여하되, 스스로의 결정과 판단에 따라 행동하는 자율적인 존재가 되어야 한다. 객체지향 설계의 핵심은 다른 객체와 조화롭게 협력할 수 있을 만큼 충분히 개방적인 동시에 협력에 참여하는 방법을 스스로 결정할 수 있을 만큼 충분히 자율적인 객체들의 공동체를 설계하는 데에 있다.
4 캡슐화
캡슐화는 객체의 자율성을 위해 반드시 필요한 과정이다. 자율성이라는 것은 내부와 외부가 명확하게 구분될 때 가능하다. 만일 외부의 요청에 의해 객체 내의 여러가지 속성과 메서드가 영향을 받게 되면 자율적이지 못하다고 할 수 있다. 따라서 객체의 사적인 부분은 객체 스스로 관리하고 외부에서 일체 간섭할 수 없도록 차단되어야 한다. 이를 캡슐화라 한다. 객체는 다른 객체가 '무엇(What)'을 수행하는지는 알 수 있지만 '어떻게(how)' 수행하는지에 대해서는 알 수 없어야 한다.
가령, 손님의 요구사항에 따라 '아메리카노'의 커피제조법이 모두 다르다면, 손님이 많은상황에서 매 주문때마다 대혼란이 발생할 것이다. 바리스타는 자신의 방법대로(자율) 커피를 만들고, 커피의 당도 조절과 같은 부분은 손님이 자유롭게 해야만 가게(어플리케이션)가 잘 돌아간다. 외부에서 일일히 알려줘야만 움직이는 프로그램은 객체지향 세계와 동떨어진 곳이다.
5 메시지
메시지와 메서드는 다르다. 메시지는 객체간의 협력을 위해 서로 도움을 요청하는 것을 말한다. 반면, 메서드는 메시지를 받은 객체가 자신의 뜻때로 역할과 책임을 다하기 위해 움직이는 행동을 의미한다. 메시지는 UML에서 '인터페이스'로 표현된다. 자바스크립트로 객체지향을 설계할 때에도 메시지는 인터페이스라 할 수 있다. 인터페이스는 '요청'이다. 따라서 인터페이스가 실행되면 객체는 어떠한 방식이건 책임에 맞는 행동(역할)을 해야한다. 즉, 어떤 객체에서 메시지를 전송하면 결과적으로 메시지에 대응되는 특정 메서드가 실행된다.
6 메시지로 시작하라
객체지향 설계를 논할 때 가장 많이 언급되는 키워드는 '클래스'다. 프로그래밍을 귀동냥으로 들었던 사람들조차 '객체지향'에서 '클래스'를 언급한다. 마치 객체지향 설계 전체가 클래스와 클래스의 상속관계에 의해 좌우되는 것처럼 묘사된다. 이는 수많은 프로그래밍 입문자들에게 선입견을 줬다.
'클래스 중심적 사고'는 프로그램 내의 '강한 연결관계'를 설정하게끔 유도한다. 클래스에 대한 강박관념 때문에 조건반사처럼 클래스부터 만들고, 클래스로부터 상속된 서브클래스를 복사한 객체를 사용하는 방식이 객체지향 설계인 것처럼 불려졌다. 이는 완전히 잘못된 설계방식이다. 객체지향 설계는 클래스가 아닌 '메시지'로부터 시작되어야 한다.
이 세상을 움직이게 만드는 건 메시지다. 메시지가 있고, 수신자 및 송신자가 존재한다. 객체는 도움을 처리할 필요가 있는 상황에서 자연스럽게 발견될 뿐 만드는 게 아니다. 설계자는 메시지를 관찰하고, 메시지를 송,수신하는 객체를 발견해서 동적인 관계(협력)를 만든다. 다시 강조하지만 설계자(프로그래머)가 집중해야 할 대상은 클래스가 아니다. 객체들간의 '관계'다. 협력 관계를 찾았을 때 비로소 역할(메서드)과 상태가 보인다. 클래스부터 설계하는 방식은 프로그램을 완전히 반대로 설계하는 것과 같다.
개발자가 주목해야 할 부분은 클래스가 아닌 객체들간의 동적인 관계이며, 객체의 역할, 책임, 협력이란 점을 명심하자.
'코드 스터디' 카테고리의 다른 글
『객체지향 사실과 오해(2)』추상화 (0) | 2019.08.28 |
---|---|
책추천 「객체지향 사실과 오해 (1)」상태 | 행동 | 캡슐화 |식별자 (0) | 2019.08.27 |
자바스크립트 심화(14) 프로미스 병렬처리 (0) | 2019.06.27 |
자바스크립트 심화(13) 프로미스 비동기 실행 (0) | 2019.06.25 |
자바스크립트 심화(12) promise 기본 사용법 (2) | 2019.06.24 |
댓글