Giter Club home page Giter Club logo

kotlin-style-guide's Introduction

В репозитории приведен набор соглашений по оформлению кода на языке Kotlin.

Этот список правил расширяет предложенные Google и командой разработки Kotlin гайды и пересматривает в них некоторые неоднозначные моменты.

Содержание

  1. Длина строки
  2. Правила именования
  3. Порядок следования модификаторов
  4. Форматирование выражений
  5. Функции
  6. Классы
  7. Аннотации
  8. Структура класса
  9. Форматирование лямбда-выражений
  10. Использование условных операторов
  11. Template header
  12. Файлы
  • Максимальная длина строки: 120 символов.
  • Неизменяемые поля в (Companion) Object и compile-time константы именуются в стиле SCREAMING_SNAKE_CASE
  • Для полей View из Kotlin Extension используется стиль lower_snake_case
  • Любые другие поля именуются в стиле lowerCamelCase
  • Функции именуются в стиле lowerCamelCase
  • Классы именуются в стиле UpperCamelCase
  • Пакеты именуются в стиле lower_snake_case
  1. override
  2. public / protected / private / internal
  3. final / open / abstract
  4. const / lateinit
  5. inner
  6. enum / annotation / sealed / data
  7. companion
  8. inline
  9. infix
  10. operator

При переносе на новую строку цепочки вызова методов символ . или оператор ?. переносятся на следующую строку, property при этом разрешается оставлять на одной строке:

val collectionItem = source.collectionItems
                ?.dropLast(10)
                ?.sortedBy { it.progress }

Элвис оператор ?: при разрыве выражения также переносится на новую строку:

val promoItemDistanceTradeLink: String = promoItem.distanceTradeLinks?.appLink
            ?: String.EMPTY

При описании переменной с делегатом, не помещающимися на одной строке, оставлять описание с открывающейся фигурной скобкой на одной строке, перенося остальное выражение на следующую строку:

private val promoItem: MarkPromoItem by lazy {
        extractNotNull(BUNDLE_FEED_UNIT_KEY) as MarkPromoItem
}
  • Позволительно использовать функцию с одним выражением только в том случае, если она помещается в одну строку.
  • Использование именованного синтаксиса аргументов остается на усмотрение разработчика. Стоит руководствоваться сложностью вызываемого метода: если вызов метода с переданными в него параметрами понятен и очевиден, нет необходимости использовать именованные параметры. При написании именованных аргументов делать перенос каждого аргумента на новую строку с двойным отступом и переносом закрывающейся круглой скобки на следующую строку:
runOperation(
		method = operation::run,
		consumer = consumer,
		errorHandler = errorHandler,
		tag = tag,
		cache = cache,
		cacheMode = cacheMode
)
  • При необходимости разрыва строки осуществляется перенос каждого аргумента функции на новую строку с двойным отступом и переносом закрывающей круглой скобки на следующую строку.
  • Всегда использовать полный вариант с написанием invoke у переменной вместо использования сокращенного варианта:
fun runAndCall(expression: () -> Unit): Result {
        val result = run()

        //Bad
        expression()
        //Good
        expression.invoke()

        return result
}
  • При необходимости разрыва строки осуществляется перенос каждого параметра класса на новую строку с двойным отступом и переносом закрывающейся круглой скобки на следующую строку:
data class CategoryStatistic(
                val id: String,
                val title: String,
                val imageUrl: String,
                val percent: Double
) : Serializable
  • Если в описании класса родительский класс не помещается на одной строке, также осуществляется перенос каждого из его параметров на новую строку с переносом закрывающей круглой скобки на следующую строку.
  • Если описание класса не помещается в одну строку и реализует несколько интерфейсов, то применять стандартные правила переносов, т.е. делать перенос только в случае, когда не помещается на одну строку, и продолжать перечисление интерфейсов на следующей строке.
  • Использование именованного синтаксиса аргументов остается на усмотрение разработчика. Стоит руководствоваться сложностью используемого конструктора класса: если конструктор с переданными в него параметрами понятен и очевиден, нет необходимости использовать именованные параметры.
  • Аннотации как правило располагаются над описанием класса/поля/метода, к которому они применяются.
  • Если к классу/полю/методу есть несколько аннотаций, размещать каждую аннотацию с новой строки:
@JsonValue
@JvmField
var promoItem: PromoItem? = null
  • Если к полю/методу применяется только одна аннотация без параметров, указывать ее над полем/методом.
  • Аннотации, относящиеся к файлу, располагаются сразу после комментария к файлу, и перед package, с разделителем в виде пустой строки.
  1. companion object
  2. Поля: abstract, override, public, internal, protected, private
  3. Блок инициализации: init, конструкторы
  4. Абстрактные методы
  5. Переопределенные методы родительского класса(желательно в том же порядке, в каком они следуют в родительском классе)
  6. Реализации методов интерфейсов(желательно в том же порядке, в каком они следуют в описании класса, соблюдая при этом порядок описания этих методов в самом интерфейсе)
  7. public методы
  8. internal методы
  9. protected методы
  10. private методы
  11. inner классы
  • При возможности оставлять лямбда-выражение на одной строке, используя it в качестве аргумента.
  • При использовании лямба-функции в качестве аругмента выносить её за скобки если этот параметр единственный.
  • Если выражение возможно написать с передачей метода по ссылке, передавать метод по ссылке (Доступно с 1.1):
viewPager.adapter = QuestAdapter(quest, this::onQuestClicked)
  • При написании лямбда-выражения более чем в одну строку всегда использовать именованный аргумент, вместо it:
viewPager.adapter = QuestAdapter(quest, { quest ->
        onQuestClicked(quest)
})
  • Неиспользуемые параметры лямбда-выражений всегда заменять символом _.
  • Избегать использования Destrucion Declaration в лямбда-выражениях.

Не обрамлять if выражения в фигурные скобки только если условный оператор if помещается в одну строку. При возможности использовать условные операторы, как выражение:

return if (condition) foo() else bar()

У оператора when для коротких выражениях ветвей условия размещать их на одной строке с условием без фигурных скобок:

when (somenCondition) {
        0 -> fooFunction()
        1 -> barFunction()
        else -> exitFunction()
}

Если хоть в одной из ветвей есть фигурные скобки, обрамлять ими все остальные ветки. У оператора when для блоков с выражениями, которые состоят более чем из одной строки использовать для этих блоков фигурные скобки и отделять смежные case-блоки пустой строкой:

when (feed.type) {
        FeedType.PERSONAL -> {
        	with(feed as PersonalFeed) {
        		datePopupStart = dateBegin
        		datePopupEnd = dateEnd
        	}
        }


        FeedType.SUM -> {
        	with(feed as SumFeed) {
        		datePopupStart = dateBegin
        		datePopupEnd = dateEnd
        	}
        }

        FeedType.CARD -> {
        	with(feed as CardFeed) {
        		datePopupStart = dateBegin
        		datePopupEnd = dateEnd
        	}
        }

        else -> {
        	Feed.EMPTY
        }
}
  • Не использовать Template Header для классов (касается авторства и даты создания файла).
  • Возможно описывать несколько классов в одном файле только для sealed классов. В остальных случаях для каждого класса необходимо использовать отдельный файл (не относится к inner классам).

kotlin-style-guide's People

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.