Skip to content

doapps/kotlin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 

Repository files navigation

DOAPPS Kotlin Style Guide

Table of Contents

Nomenclature

On the whole, naming should follow Java standards, as Kotlin is a JVM-compatible language.

Packages

Package names are similar to Java: all lower-case, multiple words concatenated together, without hypens or underscores:

BAD:

com.RayWenderlich.funky_widget

GOOD:

com.raywenderlich.funkywidget

Classes & Interfaces

Written in UpperCamelCase. For example RadialSlider.

Methods

Written in lowerCamelCase. For example setValue.

Fields

Generally, written in lowerCamelCase. Fields should not be named with Hungarian notation, as Hungarian notation is erroneously thought to be recommended by Google.

Example field names:

class MyClass {
  var publicField: Int = 0
  val person = Person()
  private var privateField: Int?
}

Constant values in the companion object should be written in uppercase, with an underscore separating words:

companion object {
  const val THE_ANSWER = 42
}

Variables & Parameters

Written in lowerCamelCase.

Single character values must be avoided, except for temporary looping variables.

Misc

In code, acronyms should be treated as words. For example:

BAD:

XMLHTTPRequest
URL: String? 
findPostByID

GOOD:

XmlHttpRequest
url: String
findPostById

Declarations

Visibility Modifiers

Only include visibility modifiers if you need something other than the default of public.

BAD:

public val wideOpenProperty = 1
private val myOwnPrivateProperty = "private"

GOOD:

val wideOpenProperty = 1
private val myOwnPrivateProperty = "private"

Access Level Modifiers

Access level modifiers should be explicitly defined for classes, methods and member variables.

Fields & Variables

Prefer single declaration per line.

GOOD:

username: String
twitterHandle: String

Classes

Exactly one class per source file, although inner classes are encouraged where scoping appropriate.

If we want to use the arguments passed through the constructor, we can do it by defining the properties, these properties can be mutable or immutable and they help us to define in a simple way the famous Java getters and setters fields, but with a big difference, the simplicity.

  • Properties without modifying its get and set method

BAD:

class Person(name: String, age: Int) {
    val name: String
    val age: Int

    init {
        this.name = name
        this.age = age
    }
}

BAD:

class Person(name: String, age: Int) {
    val name: String = name
    val age: Int = age
}

GOOD:

class Person(val name: String, val age: Int)
  • Properties modifying its get and set method.

You don't need to move all the arguments to the body of the class, only the one that will be modified.

BAD:

class Person(name: String, age: Int) {
    val age = age
    var name = name
        get() = "Su nombre es: $field"
        set(value) { field = "Nuevo $value" }
}

GOOD:

class Person(name: String, val age: Int) {
    var name = name
        get() = "Su nombre es: $field"
        set(value) { field = "Nuevo $value" }
}

Data Type Objects

Prefer data classes for simple data holding objects.

BAD:

class Person(val name: String) {
  override fun toString() : String {
    return "Person(name=$name)"
  }
}

GOOD:

data class Person(val name: String)

Enum Classes

Enum classes without methods may be formatted without line-breaks, as follows:

private enum class CompassDirection { EAST, NORTH, WEST, SOUTH }

LiveData

Declare a LiveData as public and associate it with a private MutableLiveData, it is true that you can work it defining and observing only a MutableLiveData, but this is not a good practice, since the logic and values ​​that are bound to that MutableLiveData could be modified by other classes from outside. Remember that LiveData are read only and are perfect to be observed by other classes.

BAD:

val progressVisible: MutableLiveData<Boolean> by lazy {
    MutableLiveData<Boolean>()
}

GOOD:

private val _progressVisible = MutableLiveData<Boolean>()
val progressVisible: LiveData<Boolean> get() = _progressVisible

Spacing

Spacing is especially important in raywenderlich.com code, as code needs to be easily readable as part of the tutorial.

Indentation

Indentation is using spaces - never tabs.

Blocks

Indentation for blocks uses 2 spaces (not the default 4):

BAD:

for (i in 0..9) {
    Log.i(TAG, "index=" + i)
}

GOOD:

for (i in 0..9) {
  Log.i(TAG, "index=" + i)
}

Line Wraps

Indentation for line wraps should use 4 spaces (not the default 8):

BAD:

val widget: CoolUiWidget =
        someIncrediblyLongExpression(that, reallyWouldNotFit, on, aSingle, line)

GOOD:

val widget: CoolUiWidget =
    someIncrediblyLongExpression(that, reallyWouldNotFit, on, aSingle, line)

Line Length

Lines should be no longer than 100 characters long.

Vertical Spacing

There should be exactly one blank line between methods to aid in visual clarity and organization. Whitespace within methods should separate functionality, but having too many sections in a method often means you should refactor into several methods.

Comments

When they are needed, use comments to explain why a particular piece of code does something. Comments must be kept up-to-date or deleted.

Avoid block comments inline with code, as the code should be as self-documenting as possible. Exception: This does not apply to those comments used to generate documentation.

Semicolons

Semicolons are dead to us should be avoided wherever possible in Kotlin.

BAD:

val horseGiftedByTrojans = true;
if (horseGiftedByTrojans) {
  bringHorseIntoWalledCity();
}

GOOD:

val horseGiftedByTrojans = true
if (horseGiftedByTrojans) {
  bringHorseIntoWalledCity()
}

Getters & Setters

Unlike Java, direct access to fields in Kotlin is preferred.

If custom getters and setters are required, they should be declared following Kotlin conventions rather than as separate methods.

Brace Style

Only trailing closing-braces are awarded their own line. All others appear the same line as preceding code:

BAD:

class MyClass
{
  fun doSomething()
  {
    if (someTest)
    {
      // ...
    }
    else
    {
      // ...
    }
  }
}

GOOD:

class MyClass {
  fun doSomething() {
    if (someTest) {
      // ...
    } else {
      // ...
    }
  }
}

Conditional statements are always required to be enclosed with braces, irrespective of the number of lines required.

BAD:

if (someTest)
  doSomething()
if (someTest) doSomethingElse()

GOOD:

if (someTest) {
  doSomething()
}
if (someTest) { doSomethingElse() }

When Statements

Unlike switch statements in Java, when statements do not fall through. Separate cases using commas if they should be handled the same way. Always include the else case.

BAD:

when (anInput) {
  1 -> doSomethingForCaseOneOrTwo()
  2 -> doSomethingForCaseOneOrTwo()
  3 -> doSomethingForCaseThree()
}

GOOD:

when (anInput) {
  1, 2 -> doSomethingForCaseOneOrTwo()
  3 -> doSomethingForCaseThree()
  else -> println("No case satisfied")
}

Types

Always use Kotlin's native types when available. Kotlin is JVM-compatible so [TODO: more info]

Type Inference

Type inference should be preferred where possible to explicitly declared types.

BAD:

val something: MyType = MyType()
val meaningOfLife: Int = 42

GOOD:

val something = MyType()
val meaningOfLife = 42

Constants vs. Variables

Constants are defined using the val keyword, and variables with the var keyword. Always use val instead of var if the value of the variable will not change.

Tip: A good technique is to define everything using val and only change it to var if the compiler complains!

Companion Objects

** TODO: A bunch of stuff about companion objects **

Nullable Types

Declare variables and function return types as nullable with ? where a null value is acceptable.

Use implicitly unwrapped types declared with !! only for instance variables that you know will be initialized before use, such as subviews that will be set up in onCreate for an Activity or onCreateView for a Fragment.

When naming nullable variables and parameters, avoid naming them like nullableString or maybeView since their nullability is already in the type declaration.

When accessing a nullable value, use the safe call operator if the value is only accessed once or if there are many nullables in the chain:

editText?.setText("foo")

Language

Use en-US English spelling. 🇺🇸

BAD:

val colourName = "red"

GOOD:

val colorName = "red"

About

DOAPPS Kotlin Style Guide

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors