kt.academy Logo

Effective Kotlin:

Best Practices

Effective Kotlin

Kotlin is a powerful and pragmatic language, but it's not enough to know about its features. We also need to know when they should be used and in what way. This book is a guide for Kotlin developers on how to become excellent Kotlin developers. It presents and explains in-depth the best practices for Kotlin development. Each item is presented as a clear rule of thumb, supported by detailed explanations and practical examples.

Effective Kotlin provides insights into the idiomatic way of Kotlin development, as well as many general programming best practices and details about advanced Kotlin features like DSL creation, generics, platform types or inline functions and classes. All that for experienced Kotlin developers to get more effective when they use this programming language: to make safe, well designed and efficient code.

The purpose

Book Purpose Arrows

To really unleash the advantages of Kotlin, we need to use it properly. To do so, not only do we need to know about different Standard Library (stdlib) functions but even more, we need a good understanding of Kotlin features, purpose, and design. The main goal of this book is to explain how to use different Kotlin features to achieve safe, readable, scalable, and efficient code. Since this book is written to help developers get better at writing code, it also touches many general rules for programmers. This book tries to compose as much knowledge about best practices in Kotlin as possible. You can call it a collection of best practices.

Chapter by Chapter

Clear path to progress

1.Safety
  • Limit mutability
  • Eliminate critical sections
  • Eliminate platform types as soon as possible
  • Minimize the scope of variables
  • Specify your expectations for arguments and state
  • Prefer standard errors to custom ones
  • Prefer a nullable or Result result type when the lack of a result is possible
  • Close resources with use
  • Write unit tests
2.Readability
  • Design for readability
  • An operator’s meaning should be consistent with its function name
  • Use operators to increase readability
  • Consider making types explicit
  • Consider referencing receivers explicitly
  • Properties should represent a state, not a behavior
  • Avoid returning or operating on Unit?
  • Consider naming arguments
  • Respect coding conventions
3.Reusability
  • Do not repeat knowledge
  • Do not repeat common algorithms
  • Use generics when implementing common algorithms
  • Avoid shadowing type parameters
  • Consider using variance modifiers for generic types
  • Reuse between different platforms by extracting common modules
4.Abstraction design
  • Each function should be written in terms of a single level of abstraction
  • Use abstraction to protect code against changes
  • Specify API stability
  • Consider wrapping external APIs
  • Minimize elements’ visibility
  • Define contracts with documentation
  • Respect abstraction contracts
5.Object creation
  • Consider factory functions instead of secondary constructors
  • Consider a primary constructor with named optional arguments
  • Consider defining a DSL for complex object creation
  • Consider using dependency injection
6.Class design
  • Prefer composition over inheritance
  • Use the data modifier to represent a bundle of data
  • Use function types or functional interfaces to pass operations and actions
  • Use sealed classes and interfaces to express restricted hierarchies
  • Prefer class hierarchies instead of tagged classes
  • Use enum to represent a list of values
  • Respect the contract of equals
  • Respect the contract of hashCode
  • Respect the contract of compareTo
  • Consider extracting non-essential parts of your API into extensions
  • Avoid member extensions
7.Make it cheap
  • Avoid unnecessary object creation
  • Consider using object declarations
  • Use caching when possible
  • Extract objects that can be reused
  • Use the inline modifier for functions with parameters of functional types
  • Consider using inline value classes
  • Eliminate obsolete object references
8.Efficient collection processing
  • Prefer Sequences for big collections with more than one processing step
  • Consider associating elements to a map
  • Consider using groupingBy instead of groupBy
  • Limit the number of operations
  • Consider Arrays with primitives for performance-critical processing
  • Consider using mutable collections
  • Use appropriate collection types