Руководство по стилю Kotlin для Android разработчиков (Часть II)

В принципе, я согласен с комментариями, что данная тема излишняя, так как существуют автоматические инструменты форматирования кода

И к тому же у каждого своё мнение о красоте и эстетичности, поэтому 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 разработке?”

Полезные ссылки:

  1. Официальное руководство по Kotlin стилю (на английском)

  2. Backing свойства

  3. Generic типы

  4. Jetpack Compose

  5. Документирование Kotlin кода (на английском)

  6. Дополнительная информация на Википедии

Let’s block ads! (Why?)

Read More

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *