This style-guide is somewhat of a mash-up between the existing Kotlin language style guides, and a tutorial-readability focused Swift style-guide. The language guidance is drawn from:
- The Kotlin Style Guide
- The Android Kotlin style guide
- The Kotlin Coding Conventions
- The Android contributors style guide
On the whole, naming should follow Java standards, as Kotlin is a JVM-compatible language.
Package names are similar to Java: all lower-case, multiple words concatenated together, without hypens or underscores:
BAD:
com.Sysdata.funky_widgetGOOD:
com.sysdata.funkywidgetWritten in UpperCamelCase. For example RadialSlider.
Written in lowerCamelCase. For example setValue.
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
}Written in lowerCamelCase.
Single character values must be avoided, except for temporary looping variables.
In code, acronyms should be treated as words. For example:
BAD:
XMLHTTPRequest
URL: String?
findPostByIDGOOD:
XmlHttpRequest
url: String
findPostByIdOnly 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 should be explicitly defined for classes, methods and member variables.
Prefer single declaration per line.
GOOD:
username: String
twitterHandle: StringExactly one class per source file, although inner classes are encouraged where scoping appropriate.
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 should be avoided where possible, due to a large memory overhead. Static constants are preferred. See http://developer.android.com/training/articles/memory.html#Overhead for further details.
Enum classes without methods may be formatted without line-breaks, as follows:
private enum CompassDirection { EAST, NORTH, WEST, SOUTH }Spacing is especially important in Sysdata code, as code needs to be easily readable as part of the tutorial.
Indentation is using spaces - never tabs.
Lines should be no longer than 100 characters long.
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.
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()
}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.
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()
}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 -> doSomethingForCaseOne()
2 -> doSomethingForCaseOneOrTwo()
3 -> doSomethingForCaseThree()
}GOOD:
when (anInput) {
1, 2 -> doSomethingForCaseOneOrTwo()
3 -> doSomethingForCaseThree()
else -> println("No case satisfied")
}Always use Kotlin's native types when available.
Type inference should be preferred where possible to explicitly declared types.
BAD:
val something: MyType = MyType()
val meaningOfLife: Int = 42GOOD:
val something = MyType()
val meaningOfLife = 42Constants 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!
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")Copyright (C) 2019 Sysdata, S.p.a.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.