Kotlin Style Guide¶
What's on this page
- Core content for this topic in the Inkorporated enterprise OS.
- Practical guidance, roles, or standards as applicable.
What this enables
- Consistent enterprise operations and decision-making.
- Shared language for humans and cyborg AI agents.
This document outlines the coding standards and best practices for Kotlin development within this project. Adhering to these guidelines ensures code consistency, readability, and maintainability.
Table of Contents¶
- General Principles
- Source Files
- Formatting
- Naming Conventions
- Documentation
- Classes and Objects
- Functions
- Properties
- Control Flow
- Null Safety
- Idiomatic Kotlin
- Concurrency
- Testing
- Recommended Tools
General Principles¶
- Standard: Follow the official Kotlin Coding Conventions and Google's Kotlin Style Guide unless otherwise specified.
- Readability: Code is read much more often than it is written. Prioritize clarity over brevity.
- Consistency: Be consistent with the existing codebase. If you edit a file, follow its existing style.
- Immutability: Prefer immutable data structures (
valovervar, read-only collections) to reduce side effects.
Source Files¶
- File Naming:
- Use
PascalCase(UpperCamelCase) for file names (e.g.,ProcessData.kt). - If a file contains a single top-level class, the file name should match the class name.
- If a file contains multiple top-level declarations, choose a name that describes the contents (e.g.,
Extensions.kt).
- Use
- File Structure:
- File annotations (e.g.,
@file:JvmName("...")). - Package declaration.
- Import statements.
- Top-level declarations (classes, objects, interfaces, functions, properties).
- File annotations (e.g.,
- Encoding: Source files must be encoded in UTF-8.
Formatting¶
- Indentation: Use 4 spaces for indentation. Do not use tabs.
- Line Length: Limit lines to 100 characters.
- Exceptions: Package imports, URLs in comments, and shell commands.
- Braces:
- Open braces at the end of the line where the construct begins.
- Close braces on a separate line, aligned horizontally with the opening construct.
- Use braces for all control structures (
if,when,for,do,while), even if the body is a single line.
- Whitespace:
- Put spaces around binary operators (
a + b). - Put spaces after keywords (
if,when,for,catch). - Do not put spaces around the range operator (
0..10). - Put a space before the opening brace
{. - Colon spacing:
fun foo(x: Int): String(no space before colon when specifying type).class Foo : Bar(space before and after colon for inheritance).
- Put spaces around binary operators (
Naming Conventions¶
- Packages:
lowercasewith no underscores (e.g.,com.example.project). - Classes/Interfaces/Objects:
PascalCase(UpperCamelCase). - Functions:
camelCase. Verbs or verb phrases.- Test functions in tests can use backticks with spaces (e.g., `test data is valid`).
- Properties:
camelCase.- Constants (
const val) should beUPPER_SNAKE_CASE. - Private properties used as backing fields for public properties should start with an underscore (e.g.,
_elementList).
- Constants (
- Type Parameters: Single capital letter (e.g.,
T,E,K,V). - Acronyms: Treat acronyms as words (e.g.,
HttpConnection, notHTTPConnection).
Documentation¶
- KDoc: Use KDoc comments (
/** ... */) for public APIs.- Use
@param,@return,@throws,@receiver,@sampletags. - The first line should be a summary description.
- Use
- Comments:
- Use
//for implementation details. - Avoid block comments
/* ... */for code explanation; use them only for temporary commenting out of code.
- Use
/**
* Calculates the total price including tax.
*
* @param price The base price of the item.
* @param taxRate The tax rate as a decimal (e.g., 0.1 for 10%).
* @return The total price.
*/
fun calculateTotal(price: Double, taxRate: Double): Double {
return price * (1 + taxRate)
}
Classes and Objects¶
- Layout:
- Property declarations and initializer blocks.
- Secondary constructors.
- Method declarations.
- Companion object.
- Primary Constructors: Use primary constructors in the class header.
- Data Classes: Use
data classfor classes that hold data. - Companion Objects: Place at the bottom of the class. Use explicitly named companion objects only if necessary.
- Object Declarations: Use
objectfor singletons.
Functions¶
- Single-Expression Functions: Use expression body syntax when the function body is a single expression.
// Preferred
fun square(x: Int): Int = x * x
// Avoid for simple expressions
fun square(x: Int): Int {
return x * x
}
- Default Arguments: Prefer default arguments over function overloading.
- Named Arguments: Use named arguments when a function has many parameters or boolean flags, for clarity.
- Extension Functions: Use liberally to extend functionality without inheritance, but avoid polluting the global namespace. Keep them relevant to the receiver.
- Unit Return: Omit the return type if it is
Unit.
Properties¶
- Val vs Var: Prefer
val(read-only) overvar(mutable). - Custom Accessors: Use custom get/set only when necessary.
- Backing Properties: Use
_propertyNamefor private mutable state exposed as public immutable state.
- Lateinit: Use
lateinitonly when dependency injection or setup methods are unavoidable. Prefer nullable types initialized tonullif possible.
Control Flow¶
- When Expression: Prefer
whenoverif-else ifchains when checking more than two conditions or checking against types/ranges. - Loops: Prefer functional operations (
map,filter,forEach) over imperative loops (for,while) for collection processing. - Trailing Lambdas: If the last argument of a function is a function, place the lambda outside the parentheses.
Null Safety¶
- Nullable Types: Define types as nullable
Type?only ifnullis a valid state. - Safe Calls: Use
?.for accessing properties/methods of nullable types. - Elvis Operator: Use
?:for default values. - Not-Null Assertion: Avoid
!!operators. If you think you need it, refactor the code or userequireNotNull()/checkNotNull()with a message.
Idiomatic Kotlin¶
- Scope Functions: Use scope functions (
let,run,with,apply,also) appropriately:let: Execute a block on non-null objects (obj?.let { ... }).apply: Configure an object (returns the object itself).run: Compute a value from an object context.also: Perform side effects (returns the object itself).with: Call multiple methods on an object instance.
- String Templates: Use string templates (
"$variable") instead of concatenation. - Ranges: Use ranges (
1..10,1 until 10,10 downTo 1) for loops and checks.
Concurrency¶
- Coroutines: Prefer Kotlin Coroutines over threads and
Futures. - Suspend Functions: Use
suspendmodifier for functions that perform long-running or blocking operations. - Dispatchers: Use
Dispatchers.IOfor I/O operations andDispatchers.Defaultfor CPU-intensive tasks. AvoidGlobalScope. - Structured Concurrency: Ensure all coroutines are launched within a specific
CoroutineScopetied to a lifecycle.
Testing¶
- Framework: JUnit 5 or Kotest.
- Mocking: MockK (preferred over Mockito for Kotlin).
- Naming:
- Use descriptive names, potentially with backticks:
`calculating total returns correct sum`.
- Use descriptive names, potentially with backticks:
- Assertions: Use strict assertions (e.g., Kotest assertions or AssertJ).
Recommended Tools¶
- Build System: Gradle (Kotlin DSL preferred).
- Linter/Formatter:
- IDE: IntelliJ IDEA or Android Studio.
Related Interview Questions¶
- Practice Questions: Test your knowledge of Kotlin concepts.