목록분류 전체보기 (99)
안드로이드 개발자 노트
작은 인터페이스는 배우기 쉽고 유지하기도 쉬우며, 기능이 많은 클래스보다 적은 클래스가 유지보수가 쉽습니다. 어떤 수정을 하기 위해서는 클래스 전체를 이해해야 하는데, 요소 자체가 적다면 유지보수하고 테스트할 것이 적기 때문입니다. 변경을 가할 때는 기존의 것을 숨기는 것보다 새로운 것을 노출하는 것이 쉽습니다. 일반적으로 공개적으로 노출되어 있는 요소들은 이미 외부에서 사용되고 있을 것이며, 이런 요소들을 변경하면(특히나 가시성을 변경하면) 이 코드를 사용하는 모든 부분이 영향을 받기 때문입니다. 따라서 처음에는 작은 API로서 개발을 하도록 강제하는 것이 더 좋을 수 있으며, 접근 제어자를 잘 활용해서 외부에서의 임의 수정을 최소화 할 수 있습니다. // 외부에서 set 접근 가능한 경우 var el..
많은 프로젝트가 잠재적으로 불안정하다고 판단되는 외부 라이브러리 API를 랩(wrap)해서 사용합니다. 랩해서 사용하면, 다음과 같은 자유와 안정성을 얻습니다. 문제가 있다면 래퍼(wrapper)만 변경하면 되므로, API 변경에 쉽게 대응한다. 프로젝트의 스타일에 맞춰서 API의 형태를 조절할 수 있다. 특정 라이브러리에 문제가 발생하면, 래퍼를 수정해서 다른 라이브러리를 사용하도록 쉽게 변경할 수 있다. 쉽게 동작을 추가하거나 수정할 수 있다. 단점은 다음과 같습니다. 래퍼를 따로 정의해야 한다. 다른 개발자가 볼때, 어떤 래퍼들이 있는지 따로 확인해야 한다. 내부에서 사용하는 래퍼들이므로 외부의 도움을 받을 수 없다.
프로그래밍에서는 안정적이고 최대한 표준적인 API를 선호합니다. 주요 이유는 다음과 같습니다. API가 변경되면 이를 활용하는 다른 코드들에도 영향을 미친다. 사용자가 새로운 API를 배워야 한다. 버전 하지만 좋은 API를 한번에 설계할 수는 없으며, 이를 계속해서 개선하기 위해서 변경을 하게됩니다. API 제작자가 'API'또는 'API의 일부'가 불안정하다면, 일반적으로 버전을 활용해서 라이브러리와 모듈의 안정성을 나타냅니다. 일반적으로 시멘틸 버저닝(Semantic Versioning, SemVer)을 사용합니다. 이 시스템은 버전 번호를 세 번호(MAJOR, MINOR, PATCH)로 나누어서 구성합니다. MAJOR 버전: 호환되지 않는 수준의 API 변경 MINOR 버전: 이전 버전과 호환되는..
추상화를 통해 변화로부터 코드를 보호하는 행위가 어떤 자유를 가져오는지 살펴보겠습니다. 상수 리터럴을 상수 프로퍼티로 변경하면 해당 값에 의미있는 이름을 붙일 수 있으며, 상수의 값을 변경해야 할 때 훨씬 쉽게 변경할 수 있습니다. fun isPasswordValid(text: String): Boolean { if (text.length < 7) return false //... } 여기서 숫자 7은 사실 '비밀번호의 최소 길이'를 나타냅니다. const val MIN_PASSWORD_LENGTH = 7 fun isPasswordValid(text: String): Boolean { if (text.length < MIN_PASSWORD_LENGTH) return false //... } 이처럼 상수로..
계층이 잘 분리되면 어떤 계층에서 작업할 때 그 아래의 계층은 이미 완성되어 있으므로, 전체를 이해할 필요없이 해당 계층만 생각하면 됩니다. 추상화 레벨 계층 레벨이 높아질 수록 물리 장치와 프로세서로부터 멀어집니다. 높은 레벨일 수록 걱정해야 하는 세부적인 내용들이 적어져서 단순함을 얻지만, 제어력을 잃을 수 있습니다. 예를 들어 C언어는 메모리 관리를 직접 할 수 있지만, 자바는 가비지 컬렉터가 자동으로 메모리를 관리해 줍니다. 따라서 자바는 메모리 사용을 최적화하는 것이 힘듭니다. 추상화 레벨 통일 코드도 추상화를 계층처럼 만들어서 사용할 수 있으며, 이를 위한 기본적인 도구가 바로 함수입니다. 함수도 높은 레벨과 낮은 레벨을 구분해서 사용해야 한다는 원칙(Single Level of Abstrac..
정리 코틀린은 멀티 플랫폼을 지원하기 때문에 코틀린 코드를 서로 다른 플랫폼(웹 백엔드 & 프런트엔드, Android & IOS 등등)에서 공유가 가능하다. 공통 논리 또는 공통 알고리즘을 모듈화해서 서로 다른 플랫폼에서 재사용할 수 있다.
다음과 같은 제네릭 클래스가 있다고 합시다. class Cup 위의 코드에서 타입 파라미터 T는 variance 한정자(out 또는 in)가 없으므로, 기본적으로 invariant(불공변성)입니다. invariant(불공변성)라는 것은 제네릭 타입으로 만들어지는 타입들이 서로 관련성이 없다는 의미입니다. 예를 들어 Cup와 Cup, Cup와 Cup은 어떠한 관련성도 갖지 않습니다. fun main() { val anys: Cup = Cup() // Error: type mismatch val nothing: Cup = Cup() // Error: type mismatch } 만약에 어떤 관련성을 원한다면, out 또는 in이라는 variance 한정자를 붙입니다. out은 타입 파라미터를 covarian..
다음 코드처럼 프로퍼티와 파라미터가 같은 이름을 가질 수 있습니다. class Forest(name: String) { fun addTree(name: String) { //... } } 이렇게 되면 지역 파라미터가 외부 스코프에 있는 프로퍼티를 가리게되며, 이를 섀도잉이라고 부릅니다. 섀도잉 현상은 클래스 타입 파라미터와 함수 타입 파라미터 사이에서도 발생합니다. interface Tree class Birch : Tree class Sqruce : Tree class Forest { fun addTree(tree: T) { //... } } 이렇게 코드를 작성하면, Forest와 addTree의 타입 파라미터가 독립적으로 동작합니다. val forest = Forest() forest.addTree(..
아규먼트(argument)로 함수에 값을 전달할 수 있는 것처럼, 타입 아규먼트를 사용하면 함수에 타입을 전달할 수 있습니다. 타입 아규먼트를 사용하는(타입 파라미터를 갖는) 함수를 제네릭 함수라고 부릅니다. 예를 들어, slice 함수는 타입 파라미터 T를 갖습니다. public fun List.slice(indices: IntRange): List { if (indices.isEmpty()) return listOf() return this.subList(indices.start, indices.endInclusive + 1).toList() } 타입 파라미터는 컴파일러에 타입과 관련된 정보를 제공하여 컴파일러가 타입을 정확하게 추측할 수 있게 해줍니다. 제네릭은 기본적으로 List 또는 Set처럼 ..
코틀린은 코드 재사용과 관련해서 프로퍼티 위임이라는 새로운 기능을 제공합니다. 프로퍼티 위임을 사용하면 일반적인 프로퍼티의 행위를 추출해서 재사용할 수 있습니다. 대표적인 예로 지연 프로퍼티가 있으며, 코틀린의 stdlib는 lazy 프로퍼티 패턴을 쉽게 구현할 수 있게 lazy 함수를 제공합니다. val value by lazy { createValue() } 프로퍼티 위임을 사용하면, 변화가 있을 때 이를 감지하는 observable 패턴을 쉽게 만들 수 있습니다. val items: List by Delegates.observable(listOf()) { _, _, _ -> notifyDataSetChanged() } val key: String? by Delegates.observable(null..