В принципе, я согласен с комментариями, что данная тема излишняя, так как существуют автоматические инструменты форматирования кода
И к тому же у каждого своё мнение о красоте и эстетичности, поэтому coding style носит субъективный характер.
Но я все таки решил закончить данную серию статей по Kotlin стилю, как и обещал.
Возможно кому-нибудь пригодится.
Ну что ж прошу под кат!
Именование
Идентификаторы переменных, функций, свойств, классов используют только ASCII буквы и цифры (обычные английские буквы + 10 цифр)
Специальные суффиксы или префиксы (например: _digit, power_
) не используются (исключение: Backing свойства).
Имена функций
Начнем с именования функций.
Основное правило: имя функции должно быть написано в верблюжьем стиле (например: fetchDogs
) и быть глаголом (makeRepost
)
Нижние подчеркивания разрешены, если они используются для разделения логических частей в тестирующих функциях, как здесь:
@Test fun get_emptyList() {
// ...
}
Функции, которые аннотированы @Composable
(Jetpack Compose смотрите здесь) носят имена, которые являются существительными, отформатированными в Pascal стиле:
@Composable
fun MyDog(name: String) {
// …
}
Именование констант
Константы используют имена в верхнем регистре, отдельные слова разделяются нижним подчеркиванием.
Константы в Kotlin - это val
свойства, которые не имеют кастомного оператора доступа get
, а их контент является неизменяемым. Сюда относятся: неизменяемые коллекции и типы
(listOf(1, 2, 3)
), а также скалярные типы, помеченные ключевым словом const:
// константы для скалярных типов должны быть объявлены с помощью const
const val FIVE = 5
val MY_DOGS = listOf("Dina", "Red")
val EMPTY_ARRAY = arrayOf()
Константы могут быть объявлены внутри конструкции object
или как высокоуровневые определения (на уровне файла).
На константы, которые объявлены на уровне класса, данные правила именования не распространяются.
Именование свойств и переменных
Свойства и переменные, подобно функциям, должны быть написаны в верблюжьем стиле. Это относится и к параметрам функций.
val viewModel by viewModels<DogViewModel> { viewModelFactory }
val firstName = "Anna"
val dogs = listOf(Dog("Dina"), Dog("Red"))
lateinit var binding: ListItemBinding
fun fetchDogs(page: Int): List<Dog> {
// ...
}
Когда вы используете backing свойство имя должно точно соответствовать реальному свойству только без нижнего подчеркивания:
private val _dogs = MutableLiveData<List<Dog>>()
val dogs: LiveData<List<Dog>>
get() = _dogs
Имена generic типов должны соответствовать одному из стилей:
Одна заглавная буква (можно добавить одну цифру, например:
T1, T2, R1
)Имя generic типа, который используется для класса может состоять из имени класса и дополнительного суффикса T (например:
RequestT, ResponseT
)
По моему мнению второй стиль избыточен, да и к тому же немного страноват для generic типов.
Именование классов и интерфейсов
Имена классов записываются в Pascal стиле (например: SleepingDog
- каждое слово начинается с заглавной буквы).
Также они являются существительными или фразами (например: MyCar
- состоит из двух слов)
Интерфейсы именуются по тем же правилам. Как дополнение они могут быть прилагательными (например: Cloneable, Readable, Writable
):
class MainActivity(): AppCompatActivity() {
// ...
}
interface OnItemListener {
fun onItemClick(id: Long)
}
interface Readable {}
Именование пакетов
Здесь ничего особеного: имена пакетов находятся в нижнем регистре и не содержат никаких нижних подчеркиваний:
// Неправильно
package com.example.android.marsRealeState.overview
// Неправильно
package com.example.android.mars_reale_state.overview
// OK
package com.example.android.marsrealestate.overview
Специальные конструкции
Константы enum классов могут быть размещены на одной строке:
enum class NetworkStatus {
SUCCESS, FAILED, LOADING
}
Если вы решили поместить свои константы на отдельные строчки то следуйте рекомендации: разделяйте отдельные константы, которые содержат тело пустой строкой от других:
enum class NetworkStatus {
SUCCESS,
FAILED,
LOADING {
override fun toString() = "loading..."
}
}
Поскольку перечисления относятся к классам, все вышепривиденные правила для классов действуют и на них.
Что касается аннотаций, здесь правила предельно простые:
// аннотации размещаются на отдельных строчках
@Singleton
@Component(modules = [DatabaseModule::class])
interface AppComponent {
// ...
}
// если аннотации не имеют параметров, то можно впихнуть их в одну строку
@JvmField @Volatile
var disposable: Disposable? = null
// если у вас одна простая аннотация то можно вот так:
@Inject lateinit var viewModelFactory: DogViewModelFactory
Также возможен вариант более лаконичного синтаксиса для объявления переменных и функций:
// вместо
override fun toString(): String = "My name is $name"
// можно
override fun toString() = "My name is $name"
// вместо
private val redDog: Dog = Dog("Red")
// можно
private val redDog = Dog("Red")
Документация
Базовое форматирование KDoc выглядит следующим образом:
/**
* Здесь пишем документацию
*
*/
fun fetchDogs(page: Int) {
// …
}
Если строка очень маленькая её можно уместить на одной строке:
/** Очень короткая строка моей документации */
Основные правила форматирования документации:
Используйте пустую строку, которая содержит только звездочку (
*
), чтобы разделять отдельные абзацыЛюбые из стандартных блоков идут по порядку:
@constructor
,@receiver
,@param
,@property
,@return
,@throws,@see
и не могут быть пустымиКаждый KDoc блок начинается со специального фрагмента, которые содержит основную информацию о классе или функции (например: "This function returns sum of digits"). Обычно это неполное предложение
Как минимум, KDoc документация используется для публичных методов, классов, полей, то есть public API.
Для простых функций документацию можно не писать при условии, что они настолько простые, что их легко прочитать:
// Полагаю, не требует объяснений.
fun sum(a: Int, b: Int) = a + b
А вот, например, такие нетривиальные вещи, как функция нахождения определителя матрицы требует дополнительных разъяснений.
Исключение: KDoc документация не всегда присутствует в методе, который переопределяет метод из суперкласса.
Заключение
Эта статья завершает мой небольшой цикл.
Возможно я выбрал эту тему, потому что мне нечего делать, а возможно я просто хотел понять: стоит ли замарачиваться такими вещами, как форматирование кода, если есть встроенные инструменты Android Studio, которые сделают это лучше меня по всем правилам!
Я хотел бы попросить читателей о небольшой просьбе: написать комментарий "на какую тему вы бы хотели прочитать статью по Android разработке?"
Полезные ссылки:
imanushin
Я бы еще добавил: если хотите, чтобы в проекте был единый и корректный стиль, используйте detekt.
Если кто-то закоммитит некорректный код, то не получится смержить pull request, так как билд упадет.
Если кто-то не знает, когда разделять строки дополнительным Enter'ом (или что-то в этом духе), то плагин даст ответ, так как большинство правил уже детально разобраны.
Если кто-то считает, что определенные конструкции сложны для понимания, то всегда можно создать issue у этого проекта и обсудить с коллегами. Ведь возможно, что стоит добавить новый пункт правил.
KiberneticWorm Автор
Огромное спасибо за ваш ответ!