스터디/이펙티브코틀린

아이템 24 - 제네릭 타입과 variance 한정자를 활용하라

제네릭 타입(T)에 한정자 out과 in이 붙은 경우 다음과 같이 생각하자. out : T는 반환 타입으로만 사용할 수 있다. in: T는 타입 매개변수로만 사용할 수 있다. variance: 가변성, 차이 여기서 variance 한정자는 out과 in 키워드를 의미한다. out: 공변성(covariant)으로 만든다. 자바의 extends와 유사하다. 상한을 지정한다. out 한정자를 사용하면서 발생하는 차이는 아래 코드로 설명한다. class Cup fun main() { val anys: Cup = Cup // 컴파일 에러, 서로 관련이 없는것으로 취급 } class Cup fun main() { val anys: Cup = Cup // Any를 기반으로 하는 모든 타입을 허용 } in: 반변성(c..

2023.05.14 게시됨

스터디/이펙티브코틀린

아이템 23 - 타입 파라미터의 섀도잉을 피하라

아래는 프로퍼티와 파라미터가 같은 이름을 가지는 섀도잉을 나타낸다. 이 경우 함수 내에서 섀도잉으로 인해 프로퍼티를 가르키게 된다. class Forest(val tree: Tree) { // (1) fun addTree(tree: Tree) { // (2) println(tree) // (3) -> (1)을 바라본다. } } 제네릭에 대한 이해가 부족할 때 아래와 같이 사용하여 섀도잉이 되면 원치않은 방향으로 파라미터가 사용될 수 있다. class Forest { // (1) fun addTree(tree: T) { // (2) // 여기서 tree의 T(2)는 T(1)와 서로 다른 타입이기 때문이다. // 이름을 바꾸던가 하나만 사용하도록 하자. } } class Forest { // (1) fun ..

2023.05.14 게시됨

스터디/이펙티브코틀린

아이템 21 - 일반적인 프로퍼티 패턴은 프로퍼티 위임으로 만들어라

지연 프로퍼티 lazy 프로퍼티는 이후에 처음 사용하는 요청이 들어올 때 초기화되는 프로퍼티를 의미한다. 지연프로퍼티를 java에서 구현하려면 복합한 과정이 필요한데 코틀린은 프로퍼티 위임을 이용하여 간단하게 구현할 수 있다. val value by lazy { createValue() } Delegates.observable을 이용하면 프로퍼티 위임을 사용하면 변화를 감지하는 옵저버 패턴도 쉽게 만들 수 있다. var catchedChessPeices: List by Delegates.observable(listOf()) { _, old, new -> checkKingDied(new) } 위와 같이 프로퍼티 위임 메커니즘을 사용하면 뷰, 리소스 바인딩, 의존성 주입, 데이터 바인딩 등 다양한 패턴을 만..

2023.05.14 게시됨

스터디/이펙티브코틀린

아이템 19 - knowledge를 반복하여 사용하지 말라

프로젝트에서 이미 있던 코드를 복사해서 붙여넣고 있다면, 무언가가 잘못된 것이다. 이를 “knowledge를 반복하여 사용하지 말라” 라고 표현하기도 하고 Don’t Repeat Yourself인 DRY 규칙으로 표현하기도 한다. 그런데 이를 잘못 이해하는 경우가 있다. Knowledge 프로젝트를 진행할 때 정의한 모든 것이 Knowledge(=의도적인 정보)이다. 알고리즘의 동작 방식, UI 형태, 우리가 원하는 결과등이 모두 의도적인 정보이다. 가장 중요한 두 가지 Knowledge를 뽑으면 다음과 같다. 로직: 프로그램이 어떻게 동작하는지, 어떻게 보이는지 공통 알고리즘: 원하는 동작을 하기 위한 알고리즘 둘의 차이점은 시간에 따른 변화이다. 비즈니스 로직은 시간이 지나면서 같이 변하지만 공통 알..

2023.05.03 게시됨

스터디/이펙티브코틀린

아이템 17 - 이름 있는 아규먼트를 사용하라

코드에서 아규먼트의 의미가 명확하지 않은 경우는 모든 코드를 작성하다 느낄 수 있는 부분이다. val text = (1..10).joinToString("|") // `|`이 무엇을 의미하는지? joinToString에 대해 알고 있다면 구분자라는 것을 알 수 있지만 아니라면 이해하기 힘들 수 있다. 파라미터가 명확하지 않은 경우에는 이름있는 아규먼트(named argument)를 이용하여 명확하게 만들자. val text = (1..10).joinToString(separator = "|") separator를 변수로 선언하여 사용해도 좋지만 아래와 같은 문제가 발생 할 수 있다. 실제로 코드에서 사용되는지 확신 할 수 없다. (사실 이건 IDE가 다 알려주니 큰 문제가 되지 않는다.) 변수를 잘못 만..

2023.04.27 게시됨

스터디/이펙티브코틀린

아이템 16 - 프로퍼티는 동작이 아니라 상태를 나타내야 한다

코틀린의 프로퍼티는 자바의 필드와 비슷해 보이나 다른 개념이다. var: name: String? = null get() = field?.toUpperCase() set(value) = { if(!value.isNullOrBlank()){ field = value } } 위와 같이 파생 프로퍼티라 불리는 var를 사용해서 만든 프로퍼티는 위와같이 게터와 세터를 정의할 수 있다. 이 때 field는 데이터를 저장하는 백킹(backing) 필드에 대한 레퍼런스이다. 백킹 필드는 따로 만들지 않아도 디폴트로 생성된다. 단, val를 이용한 읽기 전용 프로퍼티의 경우 생성되지 않는다. 프로퍼티는 필드가 필요하지 않다. 개념적으로 접근자라고 생각하면 된다. 따라서 val의 경우 getter, var의 경우 get..

2023.04.27 게시됨

스터디/이펙티브코틀린

아이템 15 - 리시버를 명시적으로 참조하라

무언가를 더 자세하게 설명하기 위해서, 명시적으로 긴 코드를 사용할 때가 있듯이 리시버도 명시적으로 적어주는 것이 좋다. 단지, 짧게 적을 수 있다는 이유만으로 리시버를 제거하지 말자. 여러 개의 리시버가 있는 상황에는 명시적으로 적어주는 것이 좋다. 여러 개의 리시버 특히 스코프 내부에 둘 이상의 리시버가 있는 경우, 리시버를 명시적으러 적어주도록 하자. 이를 지켜주면 코드를 오해하고 작성하거나, 의도하지 않은 방향으로 코드가 동작하는걸 미연에 방지할 수 있다. AS-IS class Node(val name: String) { fun makeChild(childName: String) = create("$name.$childName") .apply { print("Create $name") } fun ..

2022.03.25 게시됨

스터디/이펙티브코틀린

아이템 14 - 변수 타입이 명확하지 않은 경우 확실하게 지정하라

앞장에서도 계속해서 언급해왔듯이 프로그래밍은 쓰기보다 읽기가 중요하다. 따라서 가독성을 위해 코드를 설계할 때 읽는 사람에게 중요한 정보를 숨겨서는 안된다. 코드를 읽으면서 숨겨진 변수 타입을 확인하기 위해 함수 내부로 일일히 들어가서 확인해야 한다면 당연히 가독성은 떨어질 수 밖에 없다. 사람이 작업을 위해 잠깐 동안 기억할 수 있는 기억력의 총량은 그리 크지않다. 다시 말해 한정된 사람의 메모리 자원을 쓸데없이 낭비하는 것은 좋지 않다. 물론 매번 변수타입을 명확하게 하라는 것은 아니지만 적절히 가독성을 위해서 변수타입을 명확하게 지정해 주도록 하자. 그러면 타입 안정성까지 덤으로 얻어 갈 수 있다. (아이템 4 - inferred 타입으로 리턴하지 말라)

2022.03.25 게시됨

스터디/이펙티브코틀린

아이템 13 - Unit? 을 리턴하지 말라

The type with only one value: the Unit object. This type corresponds to the void type in Java. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/ Unit은 공식문서에서 볼 수 있듯 한가지 값을 가질 수 있는 타입을 나타내는 객체이다. Java에서 void 와 비슷한 타입으로 볼 수 있다. (자바의 void 는 값을 가지지 않지만..) Unit? 는 Unit 이나 null 값을 가질 수 있다. 그래서 이를 이상하게 사용하면 마치 Boolean 처럼 사용할 수 있다. 그렇게 사용하지마라 ~처럼 사용한다는 것 자체가 의도를 벗어난 행위를 하는것이다. 예측하기 어려운 오류를 만들 수..

2022.03.25 게시됨

스터디/이펙티브코틀린

아이템 12 - 연산자 오버로드를 할 때는 의미에 맞게 사용하라

연산자 오버로딩은 그 이름의 의미에 맞게 사용하자. 큰 힘에는 큰 책임이 따른다. 코틀린에서 ! 연산자는 boolean의 반대를 나타내는 not 연산을 의미한다. 이런 연산자를 팩토리얼을 표현하기 위해 아래와 같이 표현한다면 다음과 같다. 10 * !6 그리고 위 코드를 not으로 읽어보면 아래와 같이 된다. 10 *6.not() 오버로딩을 이런식으로 활용하면 혼란스럽고 오해의 소지가 있다. 코틀린의 모든 연산자는 별칭이다. 즉, 본래의 이름이 있기 때문에 그 의미를 벗어나도록 오버로딩하면 안된다. 분명하지 않은 경우 그런데 오버로딩을 한 연산자가 이름의 뜻을 제대로 의미하는지(관례를 충족하는지) 확신이 들지 않을 때가 있다. 아래의 경우 * 는 함수를 여러번 실행시키는 의미로 사용되었다. 3 * pri..

2022.03.25 게시됨