JAVA/JAVA | Spring 학습기록

[220221] 호호 스터디_ 객체지향과 디자인 패턴 Chapter 2

kth990303 2022. 2. 21. 22:19
반응형

데일리 미팅에서 호호 크루가 '객체지향과 디자인 패턴' 책 스터디를 주최하여 참여를 신청했다 :)

 

앞으로 호호 스터디를 통해 객체지향과 디자인패턴 책을 읽고 배우며 느낀 점들을 여기에 기록할 듯하다.

끝까지 완독하고 나면, 독후감 카테고리에 따로 포스팅을 작성할 예정이다.


객체지향을 선택한 이유

절차지향은 데이터 중심으로 이루어진다.

그리고 각 프로시저들이 그 데이터를 여러가지 방식으로 조작한다.

프로시저가 다른 프로시저를 사용할 수도 있고, 같은 데이터를 사용할 수도 있다.

데이터를 중심으로 로직을 작성하다보니, 많은 로직에서 동일한 데이터를 사용할 때도 있다.

그러나 위 경우의 문제점은, 요구사항이 수정됐을 때 발생한다.

일단 같은 데이터를 다루는 프로시저들이 많다보니, 데이터 타입이나 의미 변경이 발생하면 수정해야 할 프로시저도 많아진다. 거기에, 프로시저가 다른 프로시저를 사용하고 있었다면... 상상만 해도 끔찍하다. (뒤에서 설명하겠지만, 이를 '의존'이라고 부른다.)

 

또한, 동일한 데이터를 프로시저들이 서로 다른 의미로 사용하기 때문에,

다른 사람들이 내 코드를 봤을 때, 혹은 업무를 인수인계할 때 훨씬 많은 비용이 들 수 있다.

 

이렇게 현실세계에선 수많은 요구사항이 발생하기 때문에, 우리는 변경에 유연한 객체지향적 설계를 공부해보자.


객체의 책임과 메시지

객체가 갖는 책임의 크기는 작을수록 좋다.

책임이 많을 수록, 많은 프로시저가 데이터를 공유해서 사용해버리기 때문이다.

즉, 절차지향 방식과 다를게 없어진다.

 

예를 들어 모든 역할과 책임이 main에 있다고 해보자.

이는 코드 가독성도 떨어지고, 재사용성도 떨어지며, 요구사항이 추가될 때 로직이 복잡해지거나 섞여서 혼란을 야기할 수 있는 방법이다.

 

만약 객체가 갖는 책임의 크기가 작아진다면,

특정 요구사항이 발생했을 때, 그 요구사항에 해당되는 클래스의 메소드만 수정해주면 된다.

규모가 큰 프로젝트라 하더라도, 모든 코드를 이해할 필요 없이, 메시지를 수신하는 클래스는 수정하지 않아도 되고, 메시지를 보내주는 입장의 클래스만 수정해주면 되는 셈이므로 비용이 훨씬 적어진다.

 

이렇게 객체의 크기를 역할에 맞게 작게 만드는 것이 너무나도 중요하다보니,

SOLID 원칙 중 하나인 '단일 책임 원칙(SRP)'이라는 이름의 원칙으로도 생겨나게 됐다.

 

이는 5장에서 자세히 다룰 예정이다.


객체 협력을 통한 의존성

앞에서 봤듯이, 한 객체가 다른 객체를 생성하거나, 다른 객체의 메소드를 호출할 때, 의존성이 존재한다고 표현한다.

의존하는 객체에서 변경이 발생한다면, 당연히 그 객체에서도 변경이 불가피하기 때문에

의존성이 높아질수록 변경에 유연하지 못한 구조가 되며, 당연히 비용이 증가할 수밖에 없다.

 

어떤 요구사항이 있더라도, 결국 모든 클래스를 수정해야되는 경우이다.

특히 위 그림처럼 순환 참조하게 되는 의존이 발생할 경우,

변경에 굉장히 취약한 구조가 될 수밖에 없다.


의존성을 줄이기 위한 캡슐화

이제 의존성이 높으면 유연하지 못한 구조가 된다는 것을 알게 됐으니,

의존성을 낮추기 위해 어떻게 하면 좋을지 생각해보자.

 

대표적인 방법으론, 캡슐화가 존재한다.

캡슐화는 객체가 내부적으로 어떻게 기능을 구현하는지를 감추는 것이다.

캡슐화를 통해 어떻게 의존성이 낮아질 수 있을까?

 

이해를 돕기 위해, 간단하게 예시를 들어보자.
당신은 헬스장을 이용하는 운동광이다. 헬스장 입장에선, 당신의 만료일이 지나면 더 이상 헬스장을 무단으로 이용하지 못하게 출입을 막으려 할 것이다. 

책에 있는 코드와 동일하나, 클래스 명만 바꾼 것이다.

이 코드는 Gym 객체에게 회원 만료일자가 지났는지 확인하는 책임을 부여한 것이다.

지금은 코드 규모가 작고, 우리가 직접 짠 코드이기 때문에 아래와 같은 생각을 할 수도 있다.

 

이 정도면 알아보기도 쉽고, 만약 요구사항 추가되더라도

그냥 코드 몇 줄 추가하면 될거같은데? 뭐가 문제지...

 

그렇지만, 실무에서는 요구사항이 절대로 위 상황처럼 적지 않다.

만약 회원만료 여부 체크 요구사항이 수정/추가됐고, 이후에 또 추가요구사항으로, 만료되었을 때의 처리 요구사항도 수정/추가된 상황이라면?

 

서로 다른 요구사항이지만, Gym 객체의 isExpired() 메소드에게 두 역할을 모두 부여했기 때문에 두 요구사항 모두 isExpired() 메소드 수정이 불가피한 상황이다.

이러한 경우, 어느 하나의 요구사항을 수정할 때 다른 역할의 로직도 수정해야할 가능성이 크다.

같은 메소드 안에 여러 역할로직이 존재하기 때문이다.

 

그리고 만약 다른 사람이 당신의 코드를 작성하는 업무를 인수인계받아 이어서 작성해야될 경우,

위처럼 getter 메소드를 연달아서 작성하거나, 의존성이 높거나, 여러 역할이 섞여있을 경우 코드를 이해하기 매우 어려워진다.

당장 내가 1달 전에 작성한 코드도 기억이 잘 나지 않아 유지보수하라 하면 어려울 수 있는데,

남이 작성한 코드는 잘 기억나겠는가?

 

이제 같은 요구사항을 지킨 다른 코드를 살펴보자.

Member 객체에게 만료일이 지났는지 확인하는 역할을 부여하였다.

캡슐화를 지킨 좋은 코드다.

물론 이렇게 생각할 수도 있다.

 

아니, 어차피 만료일자 요구사항 수정되면 isExpired() 고쳐야되는 건 똑같잖아..

뭐가 다르다는거야!!

 

하지만 잘 생각해보자.

이번에 isExpired() 메소드 코드를 작성할 때, 앞의 코드처럼 Gym에서 member에게 의존하면서 왔다갔다하면서 작성할 필요가 없었기 때문에 더 편하게 작성할 수 있었다.

 

그뿐만이 아니다. 만약 여기서 다른 요구사항인데, 그 요구사항에서도 만료일이 지났는지 확인해야되는 요구사항이 추가됐다고 하자.

이 경우, Gym 객체는 Member의 만료일이 지난 것을 어떻게 체크했는지는 전혀 관심이 없다.

오직, Member의 만료일이 지났는지 확인받기만 하면 된다.

따라서 추가된 요구사항대로 코드를 작성하려할 때, member에게 메시지를 던지고 확인받기만 하면 되지, isExpired() 메소드의 구현로직을 복붙하면서 만료일자 확인로직 구현을 따로 할 필요가 없다.

 

또한, Gym 객체에게 존재했던 Member 객체에게의 의존성이 사라진 것을 확인할 수 있다.

member.isExpired() 메소드를 사용했으니 의존한 것이 아니냐고 물을 수도 있다.

그렇지 않다.

만료일이 지났는지 확인하는 작업은 Member에게, 지났을 경우 그 로직을 처리하는 것은 Gym 객체에게.

각각 하나의 역할만 부여한 것이다.

즉, 변화에 유연한 코드가 만들어진 것이다.

캡슐화를 지키기 위해 만들어진 법칙

캡슐화를 잘 지켰는지 확인하기 위해 만들어진 체크리스트이다.

Tell, Don't Ask는 말 그대로 객체에게 값을 꺼내지 말고, 메시지를 통해 물어보라는 의미이다.

앞의 코드 예시를 들자면, Gym 객체에게 Member의 만료일을 확인하여 오늘 날짜와 비교해 만료일이 지났는지 체크하지 말고, Member에게 만료일이 지났는지 물어보는 메시지를 보내라는 것이다.

(현실에선 Member가 거짓말로 안지났다고 말할 수도 있긴 하지만...)

 

즉, getter 메소드를 통해 객체의 자율성을 제한하기보단, 메시지를 던짐으로써 객체의 책임과 자율을 보장해주자는 것이다.

이는 우아한테크코스 프리코스 2주차 피드백에서도 강조됐던 부분이다.

 

그리고 데미테르의 법칙 (디미터 법칙)을 코드에서 지켰는지 확인하는 것만으로도 캡슐화 여부를 확인할 수 있다.

예를 들어 getter 메소드가 연달아 있는 경우는 참조하는/전달받은 객체의 객체에 접근하는 것이므로 데미테르의 법칙 위반이다. 이 경우, 의존성도 높아지기 때문에 변경에 유연하지 않은 구조가 된다.


난 Chapter 2, Chapter 5 발표를 담당하게 되었다.

 

따라서, 오늘 포스팅할 내용은 사실상 2월 28일에 스터디에서 발표할 자료나 마찬가지이다.

그럼에도 공개 범위를 공개로 해 놓는 이유는,

경쟁하는 구도가 아니기 때문에 발표자료를 미리 오픈한다고 전혀 손해보는 게 아니며,

팀원들이 발표자료(포스팅)를 먼저 보면 오히려 발표에 대한 이해도가 높아져 피드백이 활발할 것이라 생각하기 때문이다 :)

 

이 책을 예전에 읽었을 때는 잘 읽히지 않는 느낌인데다가, 왜이리 당연한 얘기를 하냐는 느낌이었는데,

확실히 스터디라는 책임감이 생긴데다가, 우테코 미션을 통해 코드 보는 관점이 많이 달라졌기 때문인지 잘 읽히고 더 많이 생각해볼 수 있게 됐다.

 

확실히 우테코를 통해 고통받다보니 내 실력도 한층 업그레이드가 됐나보다 :)

 

 

반응형