Chapter 2 κ°λ μ±
λ§ν΄ νμΈλ¬(Martin Flowler), <리νν°λ§>
μ»΄ν¨ν°κ° μΈμν μ μλ μ½λλ λ°λ³΄λΌλ μμ±ν μ μμ§λ§,
μΈκ°μ΄ μ΄ν΄ν μ μλ μ½λλ μ€λ ₯ μλ νλ‘κ·Έλλ¨Έλ§ μμ±ν μ μλ€.
μ½νλ¦°μ κ°κ²°μ±μ λͺ©νλ‘ μ€κ³λ νλ‘κ·Έλλ° μΈμ΄κ° μλλΌ, κ°λ μ±(readability)μ μ’κ² νλ λ° λͺ©νλ₯Ό λκ³ μ€κ³λ νλ‘κ·Έλλ° μΈμ΄μ΄λ€.
μ½νλ¦°μ μ¬μ©νλ©΄ κΉ¨λνκ³ μλ―Έ μλ μ½λμ APIλ₯Ό μ½κ² μμ±ν μ μλ€.
μ½νλ¦°μ μ°λ¦¬κ° μνλ κ²μ μ¨κΈ°κ±°λ κ°μ‘°ν μ μκ² νλ κΈ°λ₯μ λ§μ΄ μ 곡νλ€.
Item 11 κ°λ μ±μ λͺ©νλ‘ μ€κ³νλΌ
λ‘λ²νΈ C λ§ν΄(Robert C. Martin)
κ°λ°μκ° μ½λλ₯Ό μμ±νλ λ°λ 1λΆ κ±Έλ¦¬μ§λ§,
μ΄λ₯Ό μ½λλ°λ 10λΆμ΄ κ±Έλ¦°λ€.
νλ‘κ·Έλλ°μ μ°κΈ°λ³΄λ€ μ½κΈ°κ° λ μ€μνλ€.
μΈμ λΆν κ°μ
κ°λ μ±μ μ¬λμ λ°λΌ λ€λ₯΄κ² λλ μ μλ€.
μΈμ§λΆν(cognitive load)
νμ΅μ΄λ κ³Όμ ν΄κ²° κ³Όμ μμ μΈμ§μ μꡬλμ΄ μꡬλλ€.
μ΄λ€ μ λ³΄κ° νμ΅λκΈ° μν΄μλ λμμμ κΈ°μ΅ μμμ μ λ³΄κ° μ²λ¦¬λμ΄μΌ νλλ°
μ΄λ λμμ κΈ°μ΅μ΄ μ²λ¦¬ν΄ λΌ μ μλ μ 보μ μλ³΄λ€ μ²λ¦¬ν΄μΌ ν μ λ³΄κ° λ§μΌλ©΄ λ¬Έμ κ° μκΈ°λ©°,
μ΄ λ μΈμ§λΆνκ° λ°μνλ€.
Code A
if (person != null && person.isAdult) {
view.showPerson(person)
} else {
view.showError()
}
Code B
person?.takeIf { it.isAdult }
?.let(view::showPerson)
?: view.showError()
Code A
κ° Code B
λ³΄λ€ μ½κΈ° μ¬μ΄ μ΄μ
- μΌλ°μ μΈ κ΄μ©κ΅¬(if/else, &&, λ©μλ νΈμΆ)μ μ¬μ©νκ³ μλ€.
- μ½νλ§μμ μ¬μ©μ€μΈ κ΄μ©κ΅¬(μμ νΈμΆ
?.
,takeIf
, let, Elvis μ°μ°μ, ν¨μ λ νΌλ°μ€) λ±μ μ¬μ©ν¨μΌλ‘μ¨ μ½νλ¦° μλ ¨μλ€λ§μ μν μ½λμ΄λ€. Code A
κ° κ΅¬νμ μ΄ν΄νλκ²μ΄ μ½κ³ , μμ λ° λλ²κΉ μ΄ μ½λ€.
μ λ μ½λλ λμμ μ€ν κ²°κ³Όλ λ€λ₯΄λ€.(Code B
λ showPerson μμ null
μ λ°ννλ©΄ showError
λ₯Ό νΈμΆνλ€.)
μΈμ§λΆνλ₯Ό μ€μ΄λ λ°©ν₯μΌλ‘ μ½λλ₯Ό μμ±νλΌ.
κ·Ήλ¨μ μ΄ λμ§ μκΈ°
κ°λ³ νλ‘νΌν°λ μ°λ λμ κ΄λ ¨λ λ¬Έμ λ₯Ό λ°μμν¬ μ μμΌλ―λ‘, μ€λ§νΈ μΊμ€ν μ΄ λΆκ°λ₯νλ€.
μ΄λ₯Ό ν΄κ²°νκΈ° μν΄μ μμ νΈμΆ(?.
) let
μ μ¬μ©νλ€. μ΄ μΈμλ let
μ μ¬μ©νλ κ²½μ°λ λ€μκ³Ό κ°λ€.
- μ°μ°μ μκ·λ¨ΌνΈλ‘ μ²λ¦¬ νλ‘ μ΄λν λ
print(students.filter{}.joinToString{})
students.filter{}.joinToString{}.let{::print}
- λ°μ½λ μ΄ν°λ₯Ό μ¬μ©ν΄μ κ°μ²΄λ₯Ό λ©(ν¬μ₯)ν λ
컨벀μ
invoke ν¨μ
μ΄λ¦ μμ΄ κ°νΈνκ² νΈμΆλ μ μλ ν¨μ
class Test {
operator fun invoke(str: String) {
print(str)
}
}
fun main() {
val test = Test()
test("wow")
}
μμ κ°μ΄ test.invoke(str)
λ‘ μ¬μ©ν΄μΌ ν κ² κ°μ§λ§,
μ΄λ₯Ό 무μνκ³ test(str)
λ‘ μ¬μ© κ°λ₯νλ―μ΄ μ΄λ¦μ μλ΅ν μ μλ€.
- μ°μ°μλ μλ―Έμ λ§κ² μ¬μ©ν΄μΌ νλ€.
- λλ€λ₯Ό λ§μ§λ§ μκ·λ¨ΌνΈλ‘ μ¬μ©νλ€.
Item 12 μ°μ°μ μ€λ²λ‘λλ₯Ό ν λ μλ―Έμ λ§κ² μ¬μ©νλΌ
μ½νλ¦°μμλ λ€μκ³Ό κ°μ΄ λμλλ μ°μ°μμ μ€λ²λ‘λ©μ μ§μνλ€.
μ°μ°μ | λμλλ ν¨μ |
---|---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
++a | a.inc() |
--a | a.dec() |
a+b | a.plus(b) |
a-b | a.minus(b) |
a*b | a.times(b) |
a/b | a.div(b) |
a..b | a.rangeTo(b) |
a in b | b.contains(a) |
a+=b | a.plusAssign(b) |
a-=b | a.minusAssign(b) |
a*=b | a.timesAssign(b) |
a/=b | a.divAssign(b) |
a==b | a.equals(b) |
a>b | a.compareTo(b)>0 |
a<b | a.compareTo(b)<0 |
a>=b | a.compreTo(b)>=0 |
a<=b | a.compareTo(b)<=0 |
ν©ν 리μΌμ κ³μ°νκΈ° μν΄ ! μ°μ°μλ₯Ό μ¬μ©νλ©΄ μλλ€. (κ΄λ‘μ μ΄κΈλ¨)
λΆλͺ νμ§ μμ κ²½μ°
μλ―Έκ° λͺ
ννμ§ μλ€λ©΄ infix
λ₯Ό νμ©ν νμ₯ν¨μλ₯Ό μ¬μ©νλ κ²μ΄ μ’λ€.
μ€μ(infix) ν¨μ
λκ°μ λ³μ κ°μ΄λ° μ€λ ν¨μ
infix fun String.add(other:String): String {
return this + other
}
val string = "Hello" add "World"
System.out.println(string) // HelloWorld
operator fun Int.times(operation: () -> Unit): () -> Unit = {
repeat(this) { operation() }
}
3 * { print("Hello") } // HelloHelloHello
ν¨μκ° κ΄λ‘λ₯Ό μΆ©μ‘±ν μ§ μλμ§ νμ€νμ§ μμ λλ infix
ν¨μλ‘ μ¬μ©νλΌ
infix fun Int.timesRepeated(operation: () -> Unit) = {
repeat(this) { operation() }
}
val tripledHello = 3 timesRepeated { print("Hello") }
tripledHello() // HelloHelloHello
κ·μΉμ 무μν΄λ λλ κ²½μ°
λλ©μΈ νΉν μΈμ΄(Domain Specific Language, DSL)λ₯Ό μ€κ³ν λλ μ¬μ©ν΄λ λλ€.
μ 리
μ°μ°μ μ€λ²λ‘λ©μ κ·Έ μ΄λ¦μ μλ―Έμ λ§κ² μ¬μ©νλΌ. μ°μ°μ μλ―Έκ° λͺ ννμ§ μλ€λ©΄, μ°μ°μ μ€λ²λ‘λ©μ μ¬μ©νμ§ μλ κ²μ΄ μ’λ€.
μ°μ°μμ ννλ‘ μ¬μ©νλ €λ©΄, infix
νμ₯ ν¨μ λλ ν±λ 벨 ν¨μλ₯Ό νμ©νλΌ.
Item 13 Unit?μ 리ν΄νμ§ λ§λΌ
κΈ°λ³Έμ μΌλ‘ Unit? μ 리ν΄νκ±°λ, μ΄λ₯Ό κΈ°λ°μΌλ‘ μ°μ°νμ§ μλ κ²μ΄ μ’λ€.
Item 14 λ³μ νμ μ΄ λͺ ννμ§ μμ κ²½μ° νμ€νκ² μ§μ νλΌ
μ½νλ¦°μ κ°λ°μκ° νμ μ μ§μ νμ§ μμλ, νμ μ μ§μ ν΄μ λ£μ΄ μ£Όλ κ΅μ₯ν μμ€ λμ νμ μΆλ‘ μμ€ν μ κ°μΆκ³ μλ€.
val num = 10
val name = "Marcin"
val dis = listOf(12, 112, 554, 997)
μμ κ°μ μ½λλ κ°λ° μκ°μ μ€μ¬ μ€ λΏλ§ μλλΌ, μ νμ΄ λͺ νν λ μ½λκ° μ§§μμ§λ―λ‘ μ½λμ κ°λ μ±μ΄ ν₯μλλ€.
μ νμ΄ λͺ ννμ§ μμ λλ λ¨μ©νλ©΄ μ’μ§ μλ€.
val data = getSomeData()
κ°λ μ±μ μν΄ μ½λλ₯Ό μ€κ³ν λ μ½λ μ¬λμκ² μ€μν μ 보λ₯Ό μ¨κ²¨μλ μλλ€.
κ°λ μ± ν₯μ μ΄μΈμ μμ μ μν΄μλ νμ μ μ§μ νλ κ²μ΄ μ’λ€.
Item 15 리μλ²λ₯Ό λͺ μμ μΌλ‘ μ°Έμ‘°νλΌ
μ¬λ¬ κ°μ 리μλ²
μ€μ½ν λ΄λΆμ λ μ΄μμ 리μλ²κ° μλ κ²½μ°, λͺ μμ μΌλ‘ λνλ΄λ©΄ μ’λ€.
class Node(val name: String) {
fun makeChild(childName: String) =
create("$name.$childName")
.apply { print("Created ${name}") }
fun create(name: String): Node? = Node(name)
}
fun main() {
val node = Node("parent")
node.makeChild("child") // Created parent
}
class Node(val name: String) {
fun makeChild(childName: String) =
create("$name.$childName")
.apply { print("Created ${this?.name} in ${this@Node.name}") }
fun create(name: String): Node? = Node(name)
}
fun main() {
val node = Node("parent")
node.makeChild("child") // Created parent.child in parent
}
리μλ²λ₯Ό λͺ ννκ² μμ±νλ©΄, μ½λλ₯Ό μμ νκ² μ¬μ©ν μ μμ λΏλ§ μλλΌ κ°λ μ±λ ν₯μλλ€.
DSL λ§μ»€
DSL λ§μ»€λ κ°μ₯ κ°κΉμ΄ 리μλ²λ§μ μ¬μ©νκ±°λ, λͺ μμ μΌλ‘ μΈλΆ 리μλ²λ₯Ό μ¬μ©νμ§ λͺ»νκ² ν λ νμ©ν μ μλ κ΅μ₯ν μ€μν λ©μ»€λμ¦μ΄λ€.
μ 리
μ¬λ¬κ°μ 리μλ²κ° μλ μν© λ±μμλ 리μλ²λ₯Ό λͺ μμ μΌλ‘ μ μ΄ μ£Όλ κ²μ΄ μ’λ€.
리μλ²λ₯Ό λͺ
μμ μΌλ‘ μ κ² κ°μ νκ³ μΆλ€λ©΄, @DslMarker
λ©ν μ΄λ
Έν
μ΄μ
μ μ¬μ©νλ€.
Item 16 νλ‘νΌν°λ λμμ΄ μλλΌ μνλ₯Ό λνλ΄μΌ νλ€.
κΈ°λ³Έμ μΌλ‘ νλ‘νΌν°λ μ¬μ©μ μ μ Getter
μ Setter
λ₯Ό κ°μ§ μ μλ€.
val name: String? = null
get() = field?.toUpperCase()
set(value) {
if (!value.isNullOrBlank()) {
field = value
}
}
μ μ½λμ field
μλ³μλ νλ‘νΌν°μ λ°μ΄ν°λ₯Ό μ μ₯ν΄ λλ λ°±νΉ νλ(backing field) μ λν λ νΌλ°μ€μ΄λ€.
μ½κΈ° μ μ© νλ‘νΌν°λ field
κ° λ§λ€μ΄μ§μ§ μλλ€.
val fullName: String
get() = "$name $surname"
var
μ μ¬μ©ν΄μ λ§λ μ½κ³ μΈ μ μλ νλ‘νΌν°λ κ²ν°μ μΈν°λ₯Ό μ μν μ μλ€.
μ΄λ₯Ό νμ νλ‘νΌν°(derived property) λΌκ³ λΆλ₯Έλ€.
μμΉμ μΌλ‘ νλ‘νΌν°λ μνλ₯Ό λνλ΄κ±°λ μ€μ νκΈ° μν λͺ©μ μΌλ‘λ§ μ¬μ©ν΄μΌ νκΈ° λλ¬Έμ μλμ κ°μ΄ λ€λ₯Έ λ‘μ§μ ν¬ν¨νμ§ μμμΌ νλ€.
val Tree<Int>.sum: Int
get() = when (this) {
is Leaf -> value
is Node -> left.sum + right.sum
}
νλ‘νΌν° λμ ν¨μλ₯Ό μ¬μ©νλ κ²μ΄ μ’μ κ²½μ°λ λ€μκ³Ό κ°λ€.
- μ°μ° λΉμ©μ΄ λκ±°λ, 볡μ‘λκ°
O(1)
λ³΄λ€ ν° κ²½μ°- ν¨μλ₯Ό νμ©νμ¬ μ¬μ©νλ€λ©΄ μ¬μ©μκ° μ°μ°λΉμ©μ μμΈ‘νκΈ° μ½κ³ μ΄λ₯Ό κΈ°λ°μΌλ‘ν μΊμ±λ±μ κ³ λ €ν μ μλ€.
- λΉμ§λμ€ λ‘μ§(μ ν리μΌμ΄μ
μ λμ) μ ν¬ν¨νλ κ²½μ°
- νλ‘νΌν°λ λ¨μ λμ μ΄μμ μνν κ²μ΄λΌκ³ μμνμ§ μκΈ° λλ¬Έμ΄λ€.
- κ²°μ μ μ΄μ§ μμ κ²½μ°
- ν¨μμ μ€ν μμ μ λ€λ₯Έ κ°μ λμ€λ κ²½μ°
- λ³νμ κ²½μ°
- ν΄λΉ νλ‘νΌν°λ₯Ό μ¬μ©νλ μ¬μ©μλ‘ νμ¬κΈ μ€ν΄λ₯Ό λΆλ¬ μΌμΌν¬ μ μλ€.
Getter
μμ νλ‘νΌν° μνμ λ³κ²½μ΄ μΌμ΄λμΌ νλ κ²½μ°- νλ‘νΌν°μμ μνλ³νλ₯Ό μΌμΌν€κ² λ κΈ°λνμ§ μλλ€
νλ‘νΌν°λ μν μ§ν©μ λνλ΄κ³ , ν¨μλ νλμ λνλΈλ€.
Item 17 μ΄λ¦ μλ μκ·λ¨ΌνΈλ₯Ό μ¬μ©νλΌ
νλΌλ―Έν°κ° λͺ ννμ§ μλ κ²½μ° μ΄λ₯Ό μ§μ μ§μ ν΄μ λͺ ννκ² λ§λ€μ΄ μ€ μ μλ€.
μλ μ½λμ²λΌ μ΄λ¦ μλ μκ·λ¨ΌνΈ(named argument)λ₯Ό μ¬μ©νλΌ
val text = (1..10).joinToString(separator = "|")
λν λ€μκ³Ό κ°μ΄ λ³μλ₯Ό μ¬μ©νμ¬ μλ―Έλ₯Ό λͺ νν ν μ μλ€.
val separator = "|"
val text = (1..10).joinToString(separator)
μ΄λ¦ μλ μκ·λ¨ΌνΈλ μΈμ μ¬μ©ν΄μΌ ν κΉ?
μ΄λ¦ μλ μκ·λ¨ΌνΈλ₯Ό μ¬μ©νλ©΄ μ½λκ° κΈΈμ΄μ§μ§λ§, λ€μκ³Ό κ°μ μ₯μ μ΄ μλ€.
- μ΄λ¦μ κΈ°λ°μΌλ‘ κ°μ΄ 무μμ λνλ΄λμ§ μ μ μλ€.
- νλΌλ―Έν° μ λ ₯ μμμ μκ΄ μμΌλ―λ‘ μμ νλ€.
μλμ κ°μ΄ 100
κ°μ μλ―Έκ° λͺ¨νΈνλ€.
sleep(100)
μ΄λ¦μλ μκ·λ¨ΌνΈ μ¬μ©
sleep(timeMillis = 100)
ν¨μλ‘ μκ°λ¨μλ₯Ό νν
sleep(Millis(100))
νμ₯ νλ‘νΌν°λ‘ DSLκ³Ό μ μ¬ν λ¬Έλ²
sleep(100.ms)
μ΄λ¦μλ μκ·λ¨ΌνΈλ₯Ό μ¬μ©νλ κ²½μ°
- λν΄νΈ μκ·λ¨ΌνΈ κ²½μ°
- κ°μ νμ μ νλΌλ―Έν°κ° λ§μ κ²½μ°
- ν¨μ νμ μ νλΌλ―Έν°κ° μλ κ²½μ°
λν΄νΈ μκ·λ¨ΌνΈ κ²½μ°
νλ‘νΌν°κ° λν΄νΈ μκ·λ¨ΌνΈλ₯Ό κ°μ§ κ²½μ°, νμ μ΄λ¦μ λΆμ¬μ μ¬μ©νλ κ²μ΄ μ’λ€.
ν¨μ μ΄λ¦μ νμ νλΌλ―Έν°λ€κ³Ό κ΄λ ¨μ΄ μμΌλ©°, λν΄νΈ κ°μ κ°λ μ΅μ νλΌλ―Έν° (optional parameter) μ μ€λͺ μ΄ λͺ ννμ§ μκΈ° λλ¬Έμ, μ΄λ¦μ λΆμ¬μ μ¬μ©νλ κ²μ΄ μ’λ€.
κ°μ νμ μ νλΌλ―Έν°κ° λ§μ κ²½μ°
fun sendEmail(to: String, message: String) {
/**
* other codes
**/
}
μμ κ°μ΄ ν¨μμ κ°μ λ°μ΄ν° νμ μ νλΌλ―Έν°λ₯Ό μ¬μ©ν κ²½μ° μ΄λ¦ μλ μκ·λ¨ΌνΈλ₯Ό μ¬μ©νλ κ²μ΄ μ’λ€.
sendEmail(
to = "abc@google.com",
message = "Hello, ..."
)
ν¨μ νμ νλΌλ―Έν°
μΌλ°μ μΌλ‘ ν¨μ νμ νλΌλ―Έν°λ λ§μ§λ§ μμΉμ λ°°μΉνλ κ²μ΄ μ’λ€.
ν¨μ μ΄λ¦μ΄ μκ·λ¨ΌνΈλ₯Ό μ€λͺ ν΄ μ£ΌκΈ°λ νλ€.
λ€μκ³Ό κ°μ΄ repeat
μΈ κ²½μ° λ€μ μ€λ λλ€λ λ°λ³΅λ λΈλμ λνλΈλ€.
repeat {
/**
* other codes
**/
}
λ€μμ 리μν°λΈ λΌμ΄λΈλ¬λ¦¬μμ μμ£Ό λ³Ό μ μλ ννμ΄λ€.
RxJava μμ Observable λ₯Ό ꡬλ ν λ ν¨μλ₯Ό μ€μ νλ€.
- κ°κ°μ μμ΄ν μ λ°μ λ (onNext)
- μ€λ₯κ° λ°μνμ λ (onError)
- μ μ²΄κ° μλ£λμμ λ (onComplete)
observable.getuser()
.subscribeBy {
onNext = { user: List<User> ->
/**
* other codes
**/
},
onError = { throwable: Throwable ->
/**
* other codes
**/
},
onCompleted = {
/**
* other codes
**/
}
}
μ 리
μ΄λ¦ μλ μκ·λ¨ΌνΈλ κ°λ°μκ° μ½λλ₯Ό μ½μ λλ νΈλ¦¬νκ² νμ©λλ©°, μμ μ±λ ν₯μμν¬ μ μλ€.
Item 18 μ½λ© 컨벀μ μ μ§μΌλΌ
μ½λ©μ»¨λ²€μ μ μ§ν€λ©΄ λ€μκ³Ό κ°μ μ΄μ μ΄ μλ€.
- μ΄λ€ νλ‘μ νΈλ₯Ό μ ν΄λ μ½κ² μ΄ν΄ν μ μλ€.
- λ€λ₯Έ μΈλΆ κ°λ°μλ νλ‘μ νΈμ μ½λλ₯Ό μ½κ² μ΄ν΄ν μ μλ€.
- λ€λ₯Έ κ°λ°μλ μ½λμ μλ λ°©μμ μ½κ² μ μΆν μ μλ€.
- μ½λλ₯Ό λ³ν©νκ³ , ν νλ‘μ νΈμ μ½λ μΌλΆλ₯Ό λ€λ₯Έ μ½λλ‘ μ΄λνλ κ²μ΄ μ½λ€.
IDE μμλ μ¬λ¬ νλ¬κ·ΈμΈμ ν΅ν΄μ μ΄λ₯Ό μ§μνλ€.
- IntelliJ Formatter
- ktlink
λ§μ νλΌλ―Έν°λ₯Ό κ°μ§κ³ μλ κ²½μ°μλ λ€μκ³Ό κ°μ΄ νμ€μ© μμ±νλ κ²μ κΆμ₯νλ€.
class Person(
val id: Int = 0,
val name: String = "",
val surname: String = ""
): Human(id, name) {
// λ³Έλ¬Έ
}
λ§μΉ ν κ°λ°μκ° μμ±ν κ²κ³Ό κ°μ΄ μ½λ© 컨벀μ μ μ€μνλ©΄ μ½λμ μΌκ΄μ±μλ νμ§μ μ μ§ν μ μλ€.