Cleaner Code with Kotlin Philipp Hauer Spreadshirt Clean Code - - PowerPoint PPT Presentation

cleaner code with kotlin
SMART_READER_LITE
LIVE PREVIEW

Cleaner Code with Kotlin Philipp Hauer Spreadshirt Clean Code - - PowerPoint PPT Presentation

Cleaner Code with Kotlin Philipp Hauer Spreadshirt Clean Code Days 2017 Spreadshirt Hands Up! Spreadshirt Spreadshirt Spreadshirt 3 Kotlin Usage at Spreadshirt 8 new services and tools purely 1 Java service enriched written in Kotlin


slide-1
SLIDE 1

Spreadshirt

Cleaner Code with Kotlin

Philipp Hauer Spreadshirt

Clean Code Days 2017

slide-2
SLIDE 2

Spreadshirt

Hands Up!

slide-3
SLIDE 3

Spreadshirt 3

Spreadshirt

slide-4
SLIDE 4

Spreadshirt

Kotlin Usage at Spreadshirt

8 new services and tools purely written in Kotlin 1 Java service enriched with Kotlin

4

slide-5
SLIDE 5

Spreadshirt

Recap: What is Clean Code?

slide-6
SLIDE 6

Spreadshirt

Recap: What is Clean Code?

6

easy to understand

readable intuitive

expressive short concise simple

minimal ceremony minimal syntactic noise

slide-7
SLIDE 7

Spreadshirt

Clean Code and Kotlin

slide-8
SLIDE 8

Spreadshirt

Clean Code and Kotlin

8

slide-9
SLIDE 9

Spreadshirt

Functions: “Small” Functions with Java

9

"Rule 1: Functions should be small! Rule 2: Functions should be smaller than that!"

public Product parseProduct(Response response){ if (response == null){ throw new ClientException("Response is null"); } int code = response.code(); if (code == 200 || code == 201){ return mapToDTO(response.body()); } if (code >= 400 && code <= 499){ throw new ClientException("Sent an invalid request"); } if (code >= 500 && code <= 599){ throw new ClientException("Server error"); } throw new ClientException("Error. Code " + code); }

slide-10
SLIDE 10

Spreadshirt

Functions: Small Functions with Kotlin

10

fun parseProduct(response: Response?) = when (response?.code()){ null -> throw ClientException("Response is null") 200, 201 -> mapToDTO(response.body()) in 400..499 -> throw ClientException("Sent an invalid request") in 500..599 -> throw ClientException("Server error") else -> throw ClientException("Error. Code ${response.code()}") }

slide-11
SLIDE 11

Spreadshirt

Functions: Side-Effects

11

“Reduce side-effects!” “No unexpected and hidden changes!” Better Support for Functional Programming in Kotlin

  • Expressions
  • Immutability
  • Function Types
  • Concise Lambda Expressions
  • Kotlin’s Collection API

λ

slide-12
SLIDE 12

Spreadshirt

Expressions in Kotlin

12

Flow control structures are expressions!

val json = """{"message": "HELLO"}""" val message = try { JSONObject(json).getString("message") } catch (ex: JSONException) { json }

slide-13
SLIDE 13

Spreadshirt

Expressions in Kotlin

13

Single Expression Functions

fun getMessage(json: String): String { val message = try { JSONObject(json).getString("message") } catch (ex: JSONException) { json } return message } fun getMessage(json: String) = try { JSONObject(json).getString("message") } catch (ex: JSONException) { json }

slide-14
SLIDE 14

Spreadshirt

Be aware of Train Wrecks!

fun map(dto: OrderDTO, authData: RequestAuthData) = OrderEntity( id = dto.id, shopId = try { extractItemIds(dto.orderItems[0].element.href).shopId } catch (e: BatchOrderProcessingException) { restExc("Couldn't retrieve shop id from first order item: ${e.msg}") }, batchState = BatchState.RECEIVED,

  • rderData = OrderDataEntity(
  • rderItems = dto.orderItems.map { dto -> mapToEntity(dto) },

shippingType = dto.shipping.shippingType.id, address = mapToEntity(dto.shipping.address), correlationOrderId = dto.correlation?.partner?.orderId, externalInvoiceData = dto.externalInvoiceData?.let { ExternalInvoiceDataEntity( url = it.url, total = it.total, currencyId = it.currency.id )} ), partnerUserId = authData.sessionOwnerId ?: restExc("No sessionId supplied", 401), apiKey = authData.apiKey, dateCreated = if (dto.dateCreated != null) dto.dateCreated else Instant.now(), )

slide-15
SLIDE 15

Spreadshirt

Immutability: Feels Natural and Easy

15

val id = 1 id = 2 var id2 = 1 id2 = 2 val list = listOf(1,2,3,4) list.add(1)

Immutable References Read-only Collections

val evenList = list.filter { it % 2 == 0 }

slide-16
SLIDE 16

Spreadshirt

Immutability: Feels Natural and Easy

16

Immutable Data Classes

data class DesignData( val id: Int, val fileName: String, val uploaderId: Int, val width: Int = 0, val height: Int = 0 )

  • Constructor (assign args to props)
  • Getter
  • toString()
  • hashCode(), equals()
  • copy()
  • final
  • Default Arguments (no

chaining)

val design = DesignData(id = 1, fileName = "cat.jpg", uploaderId = 2) val id = design.id design.id = 2 val design2 = design.copy(fileName = "dog.jpg")

slide-17
SLIDE 17

Spreadshirt

Error Handling

17

Clean Code Recommendation Kotlin Support? Separate error handling from logic / Use exceptions instead of returning null / Don’t return null, because: / a) Scattered code with null-checks Concise syntax for dealing with null. Don’t use checked exceptions Checked exceptions don’t exist. Strategies to avoid null / b) Easy to forget null-check. NPE. Nullable types. Compiler enforces handling.

slide-18
SLIDE 18

Spreadshirt

Nullability in Kotlin

18

String? "Clean" null String "Clean"

val value: String = "Clean Code" val value: String = null val nullableValue: String? = "Clean Code" val nullableValue: String? = null val v: String = if (nullableValue == null) "default" else nullableValue smart-cast! val v: String = nullableValue ?: "default" val v: String = nullableValue

slide-19
SLIDE 19

Spreadshirt

Nullability in Kotlin

19

if (order == null || order.customer == null ||

  • rder.customer.address == null){

throw IllegalArgumentException("Invalid Order") } val city = order.customer.address.city val city = order?.customer?.address?.city ?: throw IllegalArgumentException("Invalid Order") val city = order?.customer?.address?.city

smart-cast

val city = order!!.customer!!.address!!.city

avoid this!

val city = order.customer.address.city

slide-20
SLIDE 20

Spreadshirt

Restrictions

slide-21
SLIDE 21

Spreadshirt

Clean Code Chapters

21

  • Meaningful Names
  • Functions
  • Comments
  • Formatting
  • Object and Data Structures
  • Error Handling
  • Boundaries
  • Classes
  • Systems
  • Emergence
  • Concurrency

⇒ Kotlin can help for 4 of 11 items

slide-22
SLIDE 22

Spreadshirt

Clean Code: Smells and Heuristics

22

slide-23
SLIDE 23

Spreadshirt

Hammer and Nails

23

Be carefull with:

  • Unreadable monster expressions
  • Complicated null-safe-calls and elvis structures

//Don't value?.emptyToNull()?.let { map.put("bla", it) } // KISS! if (!value.isNullOrEmpty()){ map.put("key", value!!) }

fun String.emptyToNull() = if (this.isEmpty()) null else this

//Don't if (value?.isNotEmpty() ?: false){ map.put("key", value!!) }

slide-24
SLIDE 24

Spreadshirt 24

Readability and Simplicity is (still) King!

slide-25
SLIDE 25

Spreadshirt

Conclusion

slide-26
SLIDE 26

Spreadshirt

Cleaner Code with Kotlin?

26

  • Less boilerplate and syntactic noise → readability
  • Safer
  • Kotlin encourages good design

Yes!

  • Clean code and good design is no automatism with Kotlin!

Developer's discipline is still important!

  • Use some features with sound judgement. "Clarity is King"

But:

slide-27
SLIDE 27

Spreadshirt

Thanks! Let’s get in touch!

27

Twitter: @philipp_hauer Blog: blog.philipphauer.de