TL;DR

  1. 코드 품질은 안전하고, 고장나지 않으며, 생각한 대로 잘 동작하는데 목표를 둡니다.
  2. 위 4가지 목표를 달성하기 위해서는 적절한 추상화가 중요합니다.
  3. 문제를 적절히 예측하며 에러와 응답을 다뤄야 합니다.

시작

추천 받은 책

이 책은 동료분이 읽으신다고 알려주신 책입니다. 모호했던 코드 품질의 개념이라던지, 좋은 코드를 짜는 방법에 대한 논의를 잘 정리한 것 같다는 느낌을 받았습니다. 이에 약 1달이라는 기간동안 출퇴근 시간에 읽으며 공감했던 내용을 정리해 봅니다. 스타트업 3년차의 눈으로 바라본 좋은 코드에 대한 의견은 마지막에 정리했으니, 제 의견만 궁금하시다면 끝 쪽만 읽으시면 됩니다.

코드 품질의 목표

코드 품질

이 책에서 코드 품질은 위 4가지 기준으로 평가됩니다.

모호한 개념이다 보니 처음엔 정의 조차 모호하다는 느낌을 받았습니다. 하지만 책의 상세한 설명에서 작가의 의도를 조금씩 알게되었고, 지금은 가장 어울리는 기준이라고 생각하게 되었답니다. 궁금하시다면 책을 한번 빌려서 보시는 것도 추천드립니다.

  1. 안전한
  2. 고장나지 않는
  3. 잘 동작하는
  4. 예측 대로 동작하는

좋은 코드의 조건

책에서는 위 4가지 기준의 달성을 확인하기 위한 6가지 조건을 제시합니다. 아래 항목들에 대해 보다는 어떻게에 대한 내용을 하나씩 풀어가서 의도는 명확하진 않습니다. 단, 충분히 잘 설명을 해주어 어떤 조건이 어떤 기준을 평가하는데 사용되는지 미루어 짐작할 수 있게 합니다.

제가 가장 감명깊게 본 항목은 2. 예측 가능성3. 모듈화를 입니다.

  1. 읽기 쉬워야 한다.
  2. 예측 가능해야 한다.
  3. 오용하기 어렵다.
  4. 모듈화 되어 있다.
  5. 재사용/일반화가 가능하다.
  6. 테스트가 용이하고, 제대로 했다.

감명 깊게 읽은

예측 가능성

예측 가능하다는 어떤 정의를 따라갈까요?

책에서는 특정 코드의 세부 동작과 응답이 의도한대로 동작하는 정도를 예측 가능성이라고 풀어갑니다.

세부 동작의 경우 우리가 의도한 동작을 하는지, 의도하지 않은 동작이 대비되어 있는지를 논합니다. 이는 우리가 a + b를 계산할때 a가 숫자가 아닌 경우, 둘다 숫자인 경우 등을 다 대비했는지에 대한 관점입니다. 한마디로 예외 처리를 얼마나 잘했는가에 대한 의견이라고 봤습니다.

한편으로 응답은 얼만큼 응답이 우리의 의도를 잘 나타내는가에 대한 내용을 다룹니다. 특히 Null값과 관련해 Null 안전성을 지원하는 언어와 아닌 언어를 나눠 올바른 응답에 대해 고민하게 합니다.

Null

Null값은 흔히 비어있는 값이라는 의도로 사용됩니다. 이 의도 속에는 에러 상황이 포함되어 있어 Null값의 의미가 중복되는 어려움을 만나기도 합니다. 이 문제에 현명하게 접근하기 위해서는 사용하는 언어가 Null 안전성을 지원하는지 여부를 고려해야 합니다.

Null 안전성

Null 안전성은 특정 객체가 Null이 될 수 있음을 컴파일러 단에서 가려주는지 여부를 말합니다. 흔히 Dart 나 Kotlin은 Null 안전성을 지원한다고 하고, JAVA, Javascript 등은 그렇지 않다고 합니다. Null 안전성을 지원할 경우, 의도적으로 Null값을 사용할 수 있습니다. Null인 경우를 사용처가 대비해야만 컴파일러가 코드를 컴파일을 해줍니다.

응답 타입

Null 안전성을 지원하지 않는 경우, Optional 타입이나 응답 타입을 갖추는 것이 좋습니다. Optional 타입의 예시는 JAVA의 Optional객체가 있습니다. 응답 타입의 경우 Rust가 그 예시 언어입니다. 사용 사례로 빈 객체를 응답으로 쓸 때, 실제 조회 결과가 빈 객체인지 아니면 의도한 실패로 빈 객체가 넘어 갔는지 표현하는 경우가 있습니다.

아래는 임시로 만들어 본 응답타입의 예입니다.

1
2
3
4
5
interface IResponse<T> {
  success: boolean;
  data: T
  msg: null | string;
}

모듈화

모듈화는 코드를 논리적인 단위로 나누는 행위 전반을 의미합니다.

저는 보통 요구사항과 코드의 중복이라는 관점에서 모듈화를 하곤 합니다. 하지만 항상 선택은 섣부르고 재작업의 신호탄이 되었던 것 같습니다. 요구사항은 변화무쌍하고 중복이라고 생각했던 코드는 논리적으로 하는일이 다르기도 했습니다.

책에서는 이런 제게 요구사항이 변할 수 있음을 인지하고 모듈화를 진행하라고 말합니다. 그 구체적인 방법으로 Composite 패턴의 사용을 제안합니다.

Composite 패턴

Composite 패턴은 의존성 주입을 통해 의도한 동작을 실현시키는 패턴입니다. 의존성 주입은 특정 인터페이스를 구현하는 객체를 생성 시에 입력해 주는 것을 말합니다. 이 방법으로 런타임에 의존성을 주입받아 사용할 수 있고, 이덕에 다양한 활용이 가능합니다.

이해를 돕기위해 간단한 예로 합체로봇을 들어보겠습니다. 어릴적 가지고 놀던 5개 로봇을 합체해 만드는 합체로봇을 떠올려 봅시다. 가끔 팔 두짝에 다른 작은 로봇을 붙여 새로운 능력을 가진 합체로봇을 만들기도 합니다. 이런 합체로봇이 바로 Composite 패턴을 이용했다고 볼 수 있습니다.

장점과 단점

런타임에 원하는 동작을 수행하는 도구를 주입받아 사용할 수 있다는게 가장 큰 매력인 것 같습니다. 또한 상속을 사용하는 것 보다 쉽게 변경에 대응하기 편하다는 느낌을 받아왔습니다.

다만 이 역시 좋은 설계가 우선되어야 해서 자칫 잘못된 요구사항 분석으로 작업량이 오히려 늘어날 수 있음을 인지해야 합니다. 팔만 분리하게 했는데 팔에 팔 관절도 분리하고 싶으면 또 그걸 나눠야 겠죠? 작업량이 배가됩니다.

종합적으로 Composite 패턴은 좋은 코드를 짜는데 도움이 되는 패턴이라고 생각합니다.

3년차 허수(?)의 관점으로 보는

좋은 품질의 코드는

머리 속으로 돌려볼 수 있는 코드

저는 동작을 상상할 수 있는 코드가 좋은 품질의 코드라고 생각합니다.

그림 없이 머릿속으로 코드를 돌려보기 위해서는 코드의 역할들이 명확 해야합니다. 예측 가능하게 로직과 응답을 구성하고 잘 분류해 놓는다면 상상하기 더욱 쉬울 것입니다. 그 결과 오류의 탐색 및 기능의 추가가 더 원할해 질 가능성이 높아진다고 생각합니다. 그래서 상상할 수 있는 코드를 작성하고자 노력해야 합니다.

좋은 코드 짜는 방법은

먼저 도식화하고 개발하기

좋은 구조 아래 좋은 코드가 생성됩니다.

코드를 짜기 전 도식화를 통해 내가 만들 로직을 상상하기 쉽게 만드는 것은 좋은 코드를 짜는 방법 중 하나입니다. 이는 생각보다 쉽지 않은데, 빨리 결과를 내고 싶다는 조바심이 크기때문입니다. 이런 자신을 잘 다스려 상상을 그림으로 그려내면, 더 좋은 코드를 짤 수 있다고 생각합니다.

탈고하기

탈고는 논리를 돌아보는 과정입니다.

우리가 작성한 코드는 몇가지 의도를 가지고 나타냅니다. 하지만 위에서 서술했듯 구현에 매몰되다보면 의도를 정확히 해석해 내지 못하는 코드가 생성됩니다. 이런 상황은 좋은 품질의 코드를 생성하고자 하는 우리의 목적에 반하는 결과를 만듭니다. 그렇기 때문에 코드를 짜고 난 뒤, 목적을 잘 달성했는지 탈고하는 과정은 중요합니다. 쉽지 않지만, 그렇기에 했을 때 득이 많은 방법이라고 생각합니다.

정리

지금까지 제가 책에서 공감했던, 관심있게 봤던 내용들과 좋은 코드에 대한 제 생각을 풀어보았습니다. 제가 잘못 파악한 내용이 있거나 잘못 작성한 내용이 있다면, 부담없이 댓글 부탁드려요!

읽어 주셔서 감사합니다. 아래는 이 글의 키워드를 정리한 것입니다.

키워드 정리

  • 좋은 품질의 코드
    • 읽기 쉽고, 예측가능하며, 잘 동작하고, 안전한 코드.
  • 좋은 코드의 조건
    1. 읽기 쉽다
    2. 예측 가능하다.
    3. 오용하기 어렵다.
    4. 재사용/일반화가 가능하다.
    5. 테스트가 용이하고, 제대로 한다.
  • 예측하기 쉬운 코드
    • 세부동작을 예측하기 쉽게 하기
    • 응답의 의도를 예측할 수 있게 하기
      • Null 안전성
  • 모듈화
    • 재사용 가능하게 하기
    • Composite패턴 쓰기