코트는 작성할 때보다 수정할 때 더 많은 시간을 필요로 합니다. 그 이유는 해당 코드를 일고 이해하며 어디를 수정해야 하는지 찾아야 하기 때문입니다. 그렇기에 보았을 더 쉽게 이해할 수 있는 코드를 짜는 것은 중요합니다. 이번장이 가독성에서는 어떻게 해야 잘 읽히고 좀 더 이해하기 쉬운지를 주제로 이야기를 해나갈까 합니다.
코틀린은 코드를 간결한게 만들어주는 예약어와 여러 함수들을 가지고 있습니다. 이러한 부분은 코드를 간결하게 짜는 것을 도움을 주지만 어떻게 보면 가독성이 떨어지는 코드를 짜는 것도 도와줍니다. 예를 들어 일반적인 if 같은 조건문을 쓰는 코드가 있다고 생각해 봅시다 이러한 조건문은 코드 짜는 사람들에게 있어서 코틀린을 배우지 않고 다른 언어들을 배운 사람들이더라도 이러한 조건문은 더 쉽게 이해할 수 있을 것입니다.
person?.takeIf { it.isAdult }
?.let(view::showPerson)
?: view.showError()
그렇다면 위와 같은 코드가 있다면 어떨까요? 이 코드는 밑의 코드와 동일한 역할을 합니다.
if (person != null && person.isAdult) {
view.showPerson(person)
} else {
view.showError()
}
대부분의 사람들은 밑의 if문코드가 더 이해하기 쉬울 것입니다. 이렇게 단순한 코드는 구현 및 수정이 쉽습니다. 디버깅 또한 이러한 구조를 더 잘 분석해 주기 때문에 이러한 if문코드가 더 좋습니다. 또한 let은 예상치 못한 결과가 나올 수 있어 예측하기 어렵다는 단점이 있습니다. 그렇기에 takeIf코드 같은 사람들의 인지에 부하를 주는 코드의 사용을 자제해야 합니다. 그렇다고 너무 극단적으로 기본 로직을 쓸 필요는 없습니다. let은 좋은 코드를 만들기 위해 다양하게 활용되는 관용구입니다.
class Person(val name: String)
var person: Person? = null
fun printName() {
person?.let {
print(it.name)
}
}
위코드처럼 nullable 안전 호출할 수 있으며
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
데코레이터를 사용해서 객체를 wrap 할 때 같이 let 은 많은 용도로 사용됩니다. 이처럼 관용구를 이해하는데 비용이 발생하더라도, 그만한 가치가 있다면 사용해도 좋습니다. 또한 두 구조를 조합해서 사용하면 단순하게 개별적인 복잡성의 합보다 커집니다.
let과 if문의 구조들을 보면서 사람에 따라 가독성의 관점이 다르다는 것을 알 수 있습니다. 그래서 우리는 컨벤션 규칙이 필요합니다
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는 이렇게 사용하면 안 된다. 람다를 마지막 인자로 사용한다 라는 컨벤션을 적용하면 코드가 복잡해진다
- 함수 이름을 보고 동작을 유추할 수 있어야 한다. and를 다른 의미로 사용하고 있다.
- 이미 있는 것을 다시 만들 필요는 없다 문자열 결합은 이미 코틀린에 내장된 함수가 있다.
위 코드에서는 이러한 컨벤션 규칙들을 위반합니다. 다음장에서는 좋은코드를 짜는 방법들을 포스팅해 보겠습니다.
'코틀린 > Effective Kotlin' 카테고리의 다른 글
[Effective Kotlin] 12. 가독성 - 연산자 오버로드를 할 때는 의미에 맞게 사용하라 (0) | 2023.08.11 |
---|---|
[Effective Kotlin] 안정성파트를 끝내며 (0) | 2023.08.03 |
[Effective Kotlin] 10. 안정성 - 단위 테스트(Unit Test)를 만들어라 (0) | 2023.08.02 |
[Effective Kotlin] 9. 안정성 - use를 사용하여 리소스를 닫아라 (0) | 2023.08.01 |
[Effective Kotlin] 8. 안정성 - 적절하게 null을 처리하라 (0) | 2023.07.28 |