코틀린 스터디/이펙티브 코틀린

아이템11) 가독성을 목표로 설계하라

막이86 2024. 3. 5. 15:33
728x90

이펙티브 코루틴을 요약한 내용입니다

  • 개발자가 어떤 코드를 작성하는 것보다 읽는 데 많은 시간을 소모한다
    • 오류를 찾기 위해 코드를 작성할 때보다 오랜 시간 코드를 읽게 됨
  • 프로그래밍은 쓰기보다 읽기가 중요함
  • 항상 가독성을 생각하면서 코드를 작성

인식 부하 감소

  • 가독성은 사람에 따라 다르게 느낄 수 있음
  • 일반적으로 ‘경험’과 ‘인식에 대한 과학’으로 만들어진 어느 정도의 규칙이 있음
// 구현 A
if (person != null && person.isAudult) {
	view.showPerson(person)
} else {
	view.showError()
}

// 구현 B
person?.takeIf { it.isAdult }
		?.let(view::showPerson)
		?: view.showError()
  • A와 B 코드중 어떤 것이 좋을까?
    • B가 짧다는 이유로 B를 골랐다면 좋은 대답은 아님
    • B는 읽고 이해하기 어려움
  • 가독성이란 코드를 읽고 얼마나 빠르게 이해할 수 있는지를 의미
  • 코틀린 초보자에게는 A코드가 더 읽고 이해하기 쉬움
    • 일반적인 관용구를 사용
  • B코드는 코틀린에서 일반적으로 사용되는 관용구
    • 경험이 많은 코틀린 개발자라면 그래도 쉽게 읽을 수 있음
    • 숙력된 개발자만을 위한 코드는 좋은 코드가 아님
  • A코드는 수정하기 쉬움
// 구현 A
if (person != null && person.isAudult) {
	view.showPerson(person)
	view.hideProgressWithSuccess()
} else {
	view.showError()
	view.hideProgress()
}

// 구현 B
person?.takeIf { it.isAdult }
		?.let {
			view.showPerson(it)
			view.hideProgressWithSuccess()
		} ?: run {
			view.showError()
			view.hideProgress()
		}
  • A 코드는 디버깅도 더 간단함
  • 일반적이지 않고 창의적인 구조는 유연하지 않고, 지원도 제대로 받지 못함
  • A 코드와 B코드 실행 결과가 다름
    • let은 람다식의 결과를 리턴
    • showPerson이 null을 리턴하면 두번째 구현 때는 showError도 호출
  • 기본적으로 ‘인지 부하’를 줄이는 방향으로 코드를 작성
  • 가독성은 뇌가 프로그램의 작동 방식을 이해하는 과정을 더 짧게 만드는 것
    • 익숙한 코드는 더 빠르게 읽을 수 있음

극단적이 되지 않기

  • let으로 인해 예상하지 못한 결과가 나올 수 있기 때문에 let을 절대로 쓰면 안된다로 이해하는 사람들이 꽤 많음
    • let은 좋은 코드를 만들기 위해서 다양하게 활용되는 관용구
  • 안전 호출 let을 사용 예
class Person(val name: String)
var person: Person? = null

fun printName() {
	person?.let {
		print(it.name)
	}
}
  • let 을 많이 사용하는 예
    • 연산을 아규먼트 처리 후로 이동시킬 때
    • 데코레이터를 사용해서 객체를 랩할 때
    students
    	.filter { it.result >= 50 }
    	.joinToString(separator = "\\n") {
    		"${it.name} ${it.surname}, ${it.result}"
    	}
    	.let(::print)
    
    var obj = FileInputStream("/file.gz")
    	.let(::BufferedInputStream)
    	.let(::ZipInputStream)
    	.let(::ObjectInputStream)
    	.readObject() as SomeObject
    
  • 디버그하기 어렵고, 경험이 적은 코틀린 개발자는 이해하기 어려운 코드
    • 하지만 비용을 지불할만한 가치가 있으므로 사용해도 괜찮음

컨벤션

  • 사람에 따라서 가독성에 대한 관점이 다름
  • 필자가 생각하는 코틀린으로 할 수 있는 최악의 코드
val abc = "A" {"B"} and "C"
print(abc) // ABC

operator fun String.invoke(f: () -> String): String = this + f()
infix fun String.and(s: String) = this + s
  • 여러 규칙들을 위반
    • 연산자는 의미에 맞게 사용해야 함
      • invoke를 이런한 형태로 사용하면 안됨
    • “람다를 마지막 아규먼트로 사용한다” 컨벤션을 여기에 적용하면 코드가 복잡해짐
      • invoke 연산자와 이러한 컨벤션을 적용하는 것은 신중해야함
    • 현재 코드에서 and라는 함수 이름이 실제 함수 내부에서 이뤄지는 처리와 맞지 않음
    • 문자열을 결합하는 기능은 이미 언어에 내장되어 있음
      • 이미 있는 것을 다시 만들 필요는 없음
728x90