3 분 소요

Object Design Style Guide

Introduction

이 책은 지금은 계시진 않지만 회사의 동료분께서 추천해주셔서 알게된 책이다. 목차를 읽어보았는데, 기초라고 적혀 있는 일반론적인 부분은 다른 책들에게서도 읽을 수 있는 내용이라 딱히 기대가 되진 않았지만 나머지 가이드 부분들은 평소 내가 코드를 작성할 때 고민하던 부분들을 코드로 해결방법을 제시해주지 않을까 하는 기대감을 가지고 읽게 되었다.

책의 구성

매 장마다 특정한 주제를 가지로 코드를 어떻게 작성하면 좋은지에 대한 내용을 다룬다. 그리고 책안에 작성되는 코드는 현존하는 코드가 아닌 저자가 임의로 만든 코드로 작성을 하는데 문법을 굳이 모르더라도 내용을 이해하는데에는 큰 무리가 없다. 이 부분은 참신하면서도 좋은 선택이라 생각한다. 내용을 설명하는 중간중간 연습문제도 있다. 다루었던 주제에 대해 연습문제를 풀어보면서 한번더 고민해보라는 취지였던 것 같은데, 이번에 읽을 때에는 따로 연습문제를 풀지는 않았다. 가볍게 읽어보자는 느낌으로 읽은 책이라 그랬던것인데 한번더 읽으면서는 문제를 풀어봐야 겠다.

객체 다루기

이책에서 가장 인상 깊었고 많은 생각 하게 해주었던 장이 “4장 객체 다루기”였다. 얼마전까지만 해도 객체는 무조건 불변해야 한다고 생각했다. 물론 지금도 불변성을 가지는 것이 변경 가능성을 가지는 것보다 좀더 안정적으로 코드를 작성할 수 있다라고 믿고 있다.

이 장에서는 “개체”와 “값 객체”를 이야기 하는데, “개체”는 변경을 추적하고 이벤트를 기록하는 식별 가능한 객체를 말하고 “값 객체”는 교체할 수 있고 익명이며 변경이 불가능한 값을 말한다. 아마 DDD에서 말하는 도메인은 “개체”를 의미하고 “값 객체”가 여기서 말하는 “값 객체”가 아닐까 싶다.

최근 Kotlin으로 코드를 많이 작성하고 있는데, Data Class를 사용해서 불변 속성들을 정의하여 개체를 표현하려고 했었다. 그게 좋다 라고 생각을 했었고 테스트 코드 작성시에도 객체 비교나 객체 복사등이 용이해서 애용하였었다. 하지만 이 장을 읽고 난 후 내가 생각한 것들을 고치게 되었다.

우선 Data Class는 “값 객체”를 위한 것이라는 느낌을 많이 받았다. 그래서 동등성 비교나 객체 복사기능들을 기본적으로 제공해 주지 않았나 싶다.

그리고 “개체”를 표현할때에는 무조건 모든 속성의 값이 일치하는지를 알기 위한 equals 구현을 반드시 해야 하는지 고민을 하게 되었다. equals를 구현할 때 테스트를 위해서 많이 구현했었는데, 어떻게 보면 “개체”는 식별자가 동일하면 같은 “개체”일 수 있고 값에 대한 변경을 검증할 때에는 내가 원하는 값으로 변경되었는지만 테스트를 하면 되기 때문에 꼭 모든 값이 일치하는지 알아야 할 필요는 없다는 것을 알게 되었다.

함수 명명

이름을 짓는것은 참 어렵다. 사람마다 생각하는게 다를 수 있고 한국인이다 보니 영어로 내가 원하는 행위를 표현하기가 여간 쉬운게 아니다. 함수명에 파라미터의 이름을 함께 넣어줘야 할지 파라미터에 이미 이름이 있으니 단순히 행위만 표현하면될지 언제나 고민된다.

이 책에서 배운 앞으로 사용하면 좋을 것 같은 몇가지 함수 명명 가이드를 소개해 본다.

  • 확실히 값을 조회하는 함수는 getXXX라는 이름을 사용하자.

    JPA를 보면 단일 ID를 매개변수로 Entity를 조회하는 함수명이 findById인 것을 볼 수 있다. 그래서 나는 서비스 함수에도 findById라는 이름을 주곤 하였었다. 하지만 서비스 함수는 반환값이 Optional이 아니며 데이터가 없으면 예외를 발생시키기 때문에 무조건 조회한 값이 있음을 보장한다. 그러니 서비스 함수명은 getById로 사용하는 것이 더 좋아 보인다.

  • 변경 가능한 객체의 변경자 메서드는 명령 메서드여야 한다.

    객체의 상태를 변경하는 메서드는 이름이 명령형이고 객체의 내부 데이터 구조를 변경할 수 있으며 아무것도 반환하지 않는다. 예를 들면 moveLeft(steps: Int): Unit과 같이 표현하면 된다.

  • 변경 불가능 객체의 변경자 메서드 이름은 서술형이어야 한다.

    불변 객체는 새로운 값을 가진 객체를 생성하여 값의 변경을 표현한다. 그래서 변경 가능한 객체처럼 명령형을 사용하는 것보다 서술형을 사용하는 것을 추천한다. 그리고 이 함수는 반환값이 존재한다. 예를 들면 toTheLeft(steps: Int): Position과 같이 표현하면 된다.

클래스의 책임의 크기 판별 방법

흔히 SOLID에서 S(단일책임원칙)이 가장 이해하기 쉬우면서 어려운 부분이라고 말한다. 그말에 나도 공감을 한다. 객체에 알맞은 책임만 주는 것은 정말 어렵고 많이 고민해야 한다. 이 책에 내용 중 이러한 객체의 책임이 너무 크지 않은지 판단하는 기준을 제시해 준다. 물론 이것만으로 책임을 더 잘 나눌 수 있다 라고 생각하진 않지만 그래도 큰 도움이 될 것이라 생각한다.

  • 주 작업 외에 부수적인 작업도 처리함을 나타내기 위해 메서드 이름에 ‘and’가 들어가야 하는가?
  • 모든 코드 내용이 주 작업에 기여하는가?
  • 메서드에서 하는 일의 일부를 백그라운드 프로세스로 수행해야 하는가?

하향식 기능 개발

이전에도 이러한 개발 방법에 대해서 고민을 한적이 있다. 당시에는 outside in 전략이라고 불렀던 것 같다. 이때까지 개발하면서 대부분 상향식으로 기능을 개발했었다. 즉 가장 작은 구성요소를 만들고 난 후 더 큰 구성요소를 만들어가는 방식이다. 이렇게 개발하면 의존성에 대한 제약을 받지 않으면서 개발을 할 수 있으니 당연히 그렇게 개발해야 한다고 생각했다. 하지만 이 책에서도 말하지만 큰것에서 부터 만들어가는 습관을 가지면 좋다. 큰 그림부터 보면서 사용자의 시나리오를 기술하고 시스템간 또는 클래스간의 상호작용을 그려보고 세부사항들을 구현하면 작은것에서 부터 시작할때 놓치기 쉬운 것들을 더 이른 시기에 발견할 수 있다.

응용프로그램을 블랙박스로 취급하면서 서비스를 만드는 연습을 계속 해보자!

Wrap up

책을 읽어보니 다행히도 내가 기대했던 추상적인 가이드가 아닌 코드로써 구체적으로 어떻게 객체지향 코드를 작성하면 좋은지 가이드 해주는 내용으로 구성되어 있었다. 서문에서도 얘기하지만 오랜 시간이 지나 노련한 프로그래머가 된다면 이러한 구성이 불필요하다고 생각할 수 있다. 하지만 나처럼 노련한 프로그래머를 위해 노력하는 이들에게는 이 책의 내용들을 읽으면서 같은 상황에서 코드를 작성할 때 많이 참고하고 고민할 수 있어서 정말 좋은 책이라고 생각한다. 조금 더 시간이 흐른 후 다시한번 이 책을 읽어봐야겠다. 그때에는 좀더 많은 인사이트를 얻을 수 있을 것 같다.