Best Practices in Kotlin

Aryan Gupta
Bobble Engineering
Published in
4 min readOct 4, 2022

If you are in android app development, you must be knowing the importance a language plays while developing an application, which will be used by millions in the coming future. Kotlin is the most widely used language nowadays, and Google itself migrated entirely from Java to Kotlin. So, it is always a plus point to develop a compatible application, which can be edited and worked on in near future by other developers, and hence using the best practices for developing Kotlin-based android applications is very important. I will be sharing links with points where it’s required so that, you must get a proper idea of how and where to use it. It is advised to read the documentation. So, with that said, let us start…

1.) Use binding in place of findViewById

We often use findViewById for finding a child from the XML file, but that’s not come under some best practices rather we can use binding.

android{
...
buildFeatures{
viewBinding true
}
}

So, this is what we can implement in the Gradle file. Now after syncing, we can use it in any of the activities.

class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

binding.button1.setOnClickListener {
...

}
}

2.) Don’t use if-type checks

We all are very much convenient with if statement, but sometimes it may happen to take extra space or an extra unnecessary variable, and also easy to forget.

if (service !is CustomerService) {
throw IllegalArgumentException("No CustomerService")
}
service.getCustomer()

We can check the form, (smart-)cast it, and throw an exception if the type is not the intended one by using as? And? All in one expression!

We can check, smart-cast the entire thing, and then throw an exception if the type isn’t found, basically using as? And?

service as? CustomerService ?: throw IllegalArgumentException("No CustomerServic
e")
service.getCustomer()

3.) Embrace Immutability

In Java, it’s generally not explicit about immutability, until there’s the final operator.

public void main() {
String str = “Data”;
int num = 6;
str = null; //NPE
num = 7;
}

Instead, Kotlin makes it incredibly easy to declare values immutable from the beginning. In fact, IntelliJ Idea will typically recommend a quick-fix to change var variables to val if they value isn’t being mutated anywhere.

fun main() {
val str = "Data" // Immutable val
var num = 6 // mutable var
str = "some other data" // Compiler error!
num = 7
}

4.) Elvis Throw

Following along with safe calls, the Elvis operator can coalesce a nullable value into a non-null value.

fun getName (id: Int): String {
val dbRow: DbRow? = selectFromDbById(id)
return dbRow?.person?.name
?: throw NotFoundException("No user found with id $id")
}

Using the Elvis operator, we can assert that getName() will always return a non-null string or throw a more detailed exception if the value can’t be found.

5.) Let()

Instead of using if we can use let()

val user: User? = findUser()
if (user != null){
dun(user.id)
}

There is no need for an extra variable when using let().

findUser()?.let { dun(it.id) }

6.) apply()

Instead of calling the same function again and again for iteration of different calls, we can simply call apply() so that we can get the iterations in one go.

//Don't
val dataSource = BasicDataSource()
dataSource.driverClassName = "com.mysql.jdbc.Driver"
dataSource.url = "jdbc:mysql://domain:3309/db"
dataSource.username = "username"
dataSource.password = "password"

And what we really need to do, is to just call apply(), as it will also decrease the number of calls and make your code look structured.

//Do
val dataSource = BasicDataSource().apply {
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://domain:3309/db"
username = "username"
password = "password"
}

7.) Not-null Statements

Don’t use not-null ‘!!’ signs until it’s very important.

//Don't
order!!.customer!!.address!!.city

8.) Use Functional Constructs

Functional constructs with cleaning up code, help bring together immutability and collections, and makes code more effective.

fun doubleList(values: Array<Int>) {
for (i in 0..values.count()) {
values[i] = values[i] * 2
}
}

The ‘for’ loop is understandable, but it’s taking major in multiplication part. This is an excellent place for an operation like .map():

fun doubleList(values: Array<Int>): Array<Int> {
return values.map { it * 2 }
}

Some other practices which must be followed during development and production

1.) Using proper architectures for well designed activities

While creating an application, there are many components to be covered like adapters, UI, utils, data, and DB among others. So, for that following a proper architecture is very important, so according to me, MVVM (Model View ViewModel) is one of the best architectures that can be followed.

See the source image

2.) Testing

The most important, now it’s no longer necessary to remind, production code requires its corresponding unit testing, that’s Test Driven Development (TDD). Try writing unit tests for everything except pure data classes and views.

Tutorial: Test-driven development with Kotlin | IntelliJ IDEA (jetbrains.com)

So, now you know, some of the best practices can be used in your Kotlin code, implement and try it yourself, and you will surely get amazed by the experience. Hope these tips will help you while developing. Please do comment if you know some of such practices and give a clap if you find this story useful.

--

--

Aryan Gupta
Bobble Engineering

Android App Developer | Web Developer | Data Structures and Algorithms | Competitive Programming