RizTech Academy logo
RizTech Academy
Writing Idiomatic KotlinLesson 1 of 525 min

Naming things so the next reader understands

You now know enough Kotlin to make things work. This module is about the gap between code that works and code that a team is glad you wrote — the difference that decides whether you are worth hiring beyond a first task. It starts with naming, because names are the documentation that never goes stale and the first thing every reader sees.

The rule under everything here: code is read far more often than it is written. You write a function once; it is read dozens of times, by teammates, by reviewers, and by you in six months when you have forgotten everything. Optimise for the reader.

Names should reveal intent

A name should answer "what is this and why does it exist" without the reader having to look further:

// what do these hold?
val d = 30
val list = getUsers()
fun process(x: List<User>): List<User>

// now you know at a glance
val timeoutSeconds = 30
val activeUsers = getUsers()
fun withoutBlockedUsers(users: List<User>): List<User>

d could be days, distance, a discount. timeoutSeconds tells you what it is and its unit. list tells you the type you already know; activeUsers tells you the meaning the type cannot. A good name carries the information the type leaves out — and the unit, especially, because a bug where someone treats seconds as milliseconds is exactly the kind a good name prevents. Notice timeoutSeconds, and recall the database course's amount_paise: putting the unit in the name is one of the cheapest, highest-value habits there is.

Kotlin's conventions

Follow the language's conventions — they are what every Kotlin reader expects, and deviating from them is friction:

val activeUsers = ...            // camelCase for values, properties, functions
fun calculateTotal() = ...       // camelCase, and a VERB — functions do things
class OrderService              // PascalCase for classes and interfaces
const val MAX_RETRIES = 3        // UPPER_SNAKE_CASE for compile-time constants
interface PaymentMethod          // PascalCase; an interface is often a noun or an -able adjective
  • Values, properties, functions: camelCase.
  • Functions are verbs or verb phrases — they do something: fetchUser, calculateTotal, isValid. A function named data or user reads wrong.
  • Booleans read as questions — isValid, hasPermission, canRetry. if (user.isActive) reads like English; if (user.active) is worse and if (user.activeStatus) is worse still.
  • Classes and interfaces: PascalCase, usually nouns.
  • Compile-time constants: UPPER_SNAKE_CASE.

These are not arbitrary. When every Kotlin codebase follows them, you can read any Kotlin codebase, and a name that breaks convention makes the reader stumble.

Say what it is, not how it is stored

Names should describe meaning, not implementation:

val userList = getUsers()        // "List" just repeats the type
val userMap = ...                // "Map" too

val users = getUsers()           // the meaning; the type already says it is a list
val usersByPincode = ...         // says what the map means, not that it is a map

userList tells you it is a list — which you already knew from the type. users tells you the meaning. And usersByPincode is far better than userMap: it says what the keys are, which is the thing you actually need to know. Name for the concept, and let the type carry the container.

Length should match scope

How long a name should be depends on how far it travels:

// a loop variable used on the next line — short is fine
for (u in users) println(u.name)

// a public property read across the whole app — spell it out
val recommendedRetryIntervalSeconds = 30

A variable used for two lines in a tiny scope can be short — it, i, u — because the reader sees its meaning right there. A public name that travels across the codebase must be self-explanatory, because most readers meet it with no surrounding context. Short names for short lives, descriptive names for long ones. The mistake in both directions is common: theCurrentIndexInTheLoop for a loop counter is noise; d for a public timeout is a puzzle.

Avoid the noise words

Some words add length without meaning and should be cut:

  • Manager, Helper, Util, Data, Info, Object — UserManager, DataHelper, UserInfo. What do they manage or help with? Usually the class has a real job that names it better — UserRepository, PriceCalculator. A Util class is where unrelated functions go to be forgotten (recall the database course's warning); name for the job.
  • Repeating the type — userObject, nameString, countInt. The type already says it.
  • get/set on a val — Kotlin generates accessors; a property named getName is Java habit.

The test: if you removed the noise word, would the name lose any meaning? UserManager → User? No — so the class needed a real name, not a Manager suffix.

The payoff, and the honest caveat

Good names are the highest-return, lowest-effort investment in readable code: they cost seconds and save every future reader minutes. The honest caveat is that naming is genuinely hard — "there are only two hard things in computer science: cache invalidation and naming things" is half serious for a reason. You will not get every name right the first time, and that is fine: rename freely. The IDE renames every usage safely in one action, so a name is never locked in. When you learn what something really is, give it the name it deserves. A codebase where names have been refined as understanding grew is a pleasure; one where the first rough guess stuck everywhere is a slog.

Check your work

Why naming matters most. Code is read far more than written — optimise for the reader.

What a good name carries. The meaning and unit the type cannot express — like timeoutSeconds.

Kotlin's conventions. camelCase for values/functions, PascalCase for types, UPPER_SNAKE_CASE for constants; functions are verbs; booleans read as questions.

Meaning versus storage. Name for the concept (users, usersByPincode), not the container (userList, userMap).

How length should match scope. Short names for short-lived locals; descriptive names for names that travel far.

The noise words to avoid. Manager/Helper/Util/Data, repeating the type, and get/set on properties.

The test for a noise word. Remove it — if the name loses no meaning, it needed a real name.

The caveat, and the fix. Naming is hard and you will not get it right first time — rename freely; the IDE makes it safe.

Practice

  1. Take five badly-named variables (d, list, flag, temp, data) and rename each to reveal intent and unit.
  2. Find a value in your code holding a duration or amount and add the unit to its name.
  3. Rename three functions to be verbs, and three booleans to read as questions (isX, hasX).
  4. Find a Manager, Helper, or Util name and rename it for what it actually does.
  5. Find a name that repeats its type (userList, nameString) and drop the redundancy.
  6. Pick a loop variable and a public property; decide the right length for each and adjust.
  7. Rename something in an IDE and watch it update every usage. Note that this makes names cheap to improve.

Official documentation

Next: function size, extraction, and organising code into files.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship