All Articles

[Study] Effective Kotlin - 가독성 1

최근 많은 고민을 하고 있는 가독성 파트부터 먼저 읽었다.

해당 장을 요약하는 문장들

컴퓨터가 인식할 수 있는 코드는 바보라도 작성할 수 있지만, 인간이 이해할 수 있는 코드는 실력있는 프로그래만 작성할 수 있다. - 마틴 파울러

코틀린은 간결성을 목표로 설계된 프로그래밍 언어가 아니라, 가독성을 좋게 하는 데 목표를 두고 설계된 프로그래밍 언어입니다.

간결성은 가독성을 목표로 두고, 자주 쓰이는 반복적인 코드를 짧게 쓸 수 있게 했기 대문에 발생한 부수적인 효과일 뿐입니다.

[item 11] 가독성을 목표로 설계하라

내용

  • 가독성이란 코드를 읽고 얼마나 빠르게 이해할 수 있는지를 의미. 즉, 뇌가 얼마나 많은 관용구(구조, 함수, 패턴)에 익숙해져 있는지에 따라 다름.
  • 숙력된 개발자라면 관용구에 익숙하겠으나, 숙련자만을 위한 코드는 좋은 코드가 아님.
  • 사용 빈도가 적은 코드는 기본적으로 코드를 복잡하게 만듬. 이걸 조합해서 쓰면 복잡성은 배로 늘어남.
  • 디버깅 도구도 기본적인 구조를 더 잘 분석해줌.
  • 따라서 가독성은 ‘뇌가 프로그램의 작동 방식을 이해하는 과정’을 더 짧게 만들어주는 것이라고 이해해도 좋음.

경험

어느것이 이해하기 쉬운가?

// 1
if (person != null && person.isAdult) {
    view.showPerson(person)
} else {
    view.showError()
}


// 2
person?.takeIf { it.isAdult }
    ?.let(view::showPerson)
    ?: view.showError()

코틀린 학습 초기 혹은 특정 연산자를 새로 접한뒤에는 해당 연산자를 마구 남발하여 코드를 작성한 경험이 있다. 마치 2번 예시처럼. 당시에는 이것이 ‘코틀린스러운’ 코드인 줄 알았다. 그러나 if / else 가 훨씬 직관적이다. 코틀린스러운 것은 없다. 오히려 코틀린 언어의 목표에 위배되는 구현이었는지도 모른다.

글을 읽는 구조, 정방향

대부분 문화권에서는 기본적으로 왼쪽에서 오른쪽, 위에서 아래로 글을 읽는다. 이러한 방향을 정방향이라고 정의할 때, 코드 역시 정방향에서 벗어날수록 이해가 힘들다.

// 1
print(tasks.filter{..}.joinToString{..})

// 2
tasks.filter{..}.joinToString{..}.let(::print)

1,2 번 구현 모두 결국 최종적으로 수행되는 것은 print 이다.

그런데, 1번의 경우 tasks 관련 연산이 길어질수록 최종적으로 수행하는 연산에 대한 기억이 희미해진다. 인간이 단기간에 최대로 기억할 수 있는 공간은 5~6개 밖에 되지 않기 때문이다. 따라서 tasks 관련 연산을 쭉 읽고, 다시 앞으로 돌아가 결국 무엇이 수행되어야하는지 확인해야하는 일이 발생할 수 있고 이는 피로도 증가 및 가독성 저해를 일으킨다.

반면, 2번의 경우 정방향으로 그대로 코드를 읽어나가도 무리가 없다. 결국 최종 연산이 마지막에 위치하기 때문이다. 이처럼 정방향을 벗어나는 코드를 지양해야한다고 본다.

(같은 이유로 takeIf {..} 연산자를 그리 좋아하지 않는다. A.takeIf {..} 의 의미 자체가 뒤의 조건이 참이라면 앞의 값을 가져온다는 것인데, 역방향 순서이기 때문이다.)

물론 어떤 것이 비용을 지불할 만한 코드인지 아닌지는 항상 논란이 있을 수 있습니다. 균형을 맞추는 것이 중요합니다. - p75


[item 12] 연산자 오버로드를 할 때는 의미에 맞게 사용하라

operator 오버로드 기능 자체는 강력하다고 생각한다. 그러나 나의 경우 짧은 경험 탓인지 활용 자체를 하는 케이스를 많이 보지 못했다. 이유를 고민해봤는데, 기본적으로 연산자를 오버로딩 할 케이스가 많지 않고 제대로 하기 어렵기 때문이라고 생각한다.

컬렉션 혹은 데이터 집합에 대해 +, - 정도는 오버로딩하는 것을 상상할 수 있겠으나 그 외에는 유즈케이스가 잘 떠오르지 않는다. 그래서 가볍게 읽고 패스!


[item 14] 변수 타입이 명확하지 않는 경우 확실하게 지정하라

내가 코드리뷰 할 때 많이 보는 부분중 하나 의외로 책의 예시와 같은 상황이 자주 출현한다.

val data = getSometing()

이상적인 것은 함수의 이름을 애초에 잘 짓는 것이지만.. 때로 정말 피치못할 사정(?)으로 다소 모호한 컨텍스트를 포함한다고 치자. 그럴땐 타입을 명시해주면 좋겠다. 깃허브에서는 바로 확인이 어려울 뿐더라, IDE 에서도 직접 함수로 이동해서 확인하는 것 하나하나가 리소스라고 생각한다.