![](https://habrastorage.org/webt/0t/yk/68/0tyk6892_mytdaw3a-ccgqi3cmw.png)
За полтора года работы с языком Kotlin, мы перевели на него все свои проекты и фреймворки. Чтобы разработчики могли быстрее включаться в работу над проектом, а код ревью не превращался в бесконечный спор, мы решили формализовать накопленный опыт и разработали собственный код-стайл.
Поехали!
Каждый разработчик пишет код исходя из собственного опыта и привычек. Если на проекте один разработчик или код пишется для себя, это не проблема. Но в больших командах, работающих над несколькими проектами, неизбежно возникают проблемы:
- на ревью кода уходит много времени и нервов — без единого стандарта спорить можно до бесконечности;
- нужно куда больше времени и сил для погружения нового человека в код;
- сложнее концентрироваться на функции, которую выполняет код;
- в результате проект выглядит, как отпечаток всех специалистов, которые принимали в нем участие.
И даже если сейчас вы единственный разработчик на проекте, не забывайте — когда-нибудь это закончится. И только от вас зависит, будет ли новый человек в команде вам благодарен или первым делом попытается разузнать ваш адрес.
Наличие единого стиля написания кода позволяет решает все эти проблемы.
Почему сейчас и почему мы
Kotlin довольно популярен в сообществе Android-разработчиков и с каждым днем собирает все больше сторонников. Но отыскать стиль написания кода, которым можно руководствоваться, по-прежнему проблема, а соглашения, опубликованные на официальном сайте языка не дают исчерпывающих ответов, так как то количество правил, которые там присутствуют, едва ли могут покрыть большинство потребностей команды. Например, не содержат правил форматирования функций, их вызов и описания.
Во время написания статьи вышел официальный гайд от Google с ответами на вопросы о написании кода на Kotlin, что в некоторой степени повлияло на статью. Нам было интересно сравнить результаты и проанализировать, в чем наши мнения сошлись и с чем мы оказались не согласны.
О процессе разработки правил
Процесс выработки единого стиля, с которым была бы согласна такая большая команда как наша, не из простых: собрать идеи и предложения, учесть мнение каждого, вспомнить, какие моменты вызывают споры на код ревью. Ожидаемо, что единого вердикта по всем вопросам добиться будет практически нереально, но важно, чтобы все осознавали важность и пользу процесса, были готовы идти на уступки и соблюдали принятые решения.
Конечно, с течением времени набор правил может пересматриваться и дополняться — мы планируем поддерживать свой набор соглашений в актуальном состоянии.
Спорные моменты
С нашим представлением о том, как должен выглядеть код, вы сможете ознакомиться по ссылке в конце статьи, а ниже мы хотели бы представить особо спорные и противоречивые моменты.
1. Имена полей View и Kotlin Android Extensions
Для полей View из Kotlin Android Extensions используется стиль именования lower_snake_case
При разработке стандарта мы старались абстрагироваться от внешних зависимостей или возможностей использования IDE и сосредоточится на языке в чистом виде. Но все же сделали исключение для Kotlin Android Extensions. Поскольку чаще всего мы используем Kotlin в Android-разработке, а приложения не обходятся без использования XML, так как в этом формате в стиле lower_snake_case описывается большинство ресурсов. Таким образом, мы сделали исключение для идентификаторов View (их мы описываем как раз в таком стиле) и обращений к этим полям (хотя если посмотреть как эта магия работает в рантайме, окажется, что это не переменные, а ключи для получения значений из HashMap). Из кода выглядит как обращение к полю, написанному в стиле lower_snake_case, но при этом в коде всегда видно, что происходит обращение к полю View.
2. Порядок private методов
Структура класса:
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 классы
Еще одним спорным моментом было расположение приватных методов. Есть два распространенных варианта: писать их сразу после метода, где они использовались, или в структуре класса после всех методов. Мы сошлись на втором варианте. Так как мы рассматриваем класс как некоторый интерфейс, в первую очередь интересно узнать, что он делает — благодаря тому, что все приватные методы располагаются в самом конце, можно быстро понять ответственность этого класса по его интерфейсу. В приватных же методах как правило содержатся уже конкретные реализации, а обращаемся мы к ним зачастую лишь в случае, если хотим сделать изменения. И в таком случае структура любого класса всегда останется консистентной.
3. Константы
Неизменяемые поля в (Companion) Object и compile-time константы именуются в стиле SCREAMING_SNAKE_CASE
Вопрос об именовании констант влечет за собой еще одну важную проблему: а что сейчас является константой в Kotlin? Язык предоставляет ключевое слово для обозначения compile-time констант "const", но compile-time константы могут быть только примитивного типа и String-и. В качестве констант хотелось бы использовать и другие неизменяемые переменные, расположенные в блоке Object — для таких случаев мы расширили понимание констант при именовании, включив в их число и такие неизменяемые переменные. Интересно, что в этом наше мнение совпало с позицией Google-а.
4. Имена пакетов
Пакеты именуются в стиле lower_snake_case
В процессе работы у нас часто возникала проблема с именованием пакетов: разные фичи могут быть настолько не очевидными, что при создании для них нового пакета нужно использовать два или более слова, чтобы точно отразить смысл. В правилах именования пакетов для Java от Oracle именовать пакеты предлагается слитно без разделителей, что в наших проектах могло привести к появлению пакетов со сложно читаемыми названиями. Поэтому мы добавили возможность разделять пакеты символом underscore. Стоит подчеркнуть, что использование такого стиля должно быть скорее вынужденным исключением, чем правилом, и стоит этого максимально избегать.
5. Аннотации
Другой пункт, по которому наше видение отличается от распространенного, оказалось использование одиночных аннотаций: в некоторых рекомендациях разрешается записывать несколько аннотаций без параметров в одну строку или даже оставлять одну аннотацию без параметров на одной строке с описываемым методом/полем. Такой подход, на наш взгляд, не несет особой пользы (разве что экономия места), а код из-за таких исключений становится менее консистентным, поэтому мы решили оставить единое правило для всех аннотаций: указывать их всегда с новой строки.
6. Функции как выражения
Также мы ограничили возможности по использованию function expression – описывать функцию как выражение разрешено только в случае, если она помещается в одну строку (для этого, кстати, мы увеличили максимальную длину строки до 120 символов). Если выражение не помещается в одну строку, вероятно, что при дальнейших изменениях может возникнуть потребность перевести эту функцию в обычный вариант написания, да и читаться такое выражение будет ничуть не проще.
Что имеем
В конце хотелось бы обозначить почему даже не смотря на то, что Google выпустил свой style guide мы все же публикуем свое представление. Как уже было сказано выше набор соглашений от разработчика самого языка – JetBrains из-за своей лаконичности едва ли покрывает все нужды команды, очень надеюсь, что команда разработки Kotlin-а не останется в стороне и будет в дальнейшем развивать этот список. При более внимательном просмотре замечаешь, что большинство правил Google были скопированы или переформулированы с их style guide по Java, мы же старались учитывать опыт и других смежных языков программирования, но в большей степени отталкивались от применения разных подходов к стилям, и как раз такой подход позволил нам раскрыть некоторые пункты (структуру класса, описание, вызов функций и др. правила).
Что дальше
Даже после принятия единого стандарта написания кода могут возникать проблемы: кто-то может забыть правила, или что еще хуже – начать саботировать их. Хорошо, если этот код будет забракован на этапе code review, но проверяющий может не заметить этих ошибок или даже участвовать в подрывной деятельности. Несмотря на молодость Kotlin, для него уже существуют инструменты по статическому анализу кода, для которых имеется возможность описать все правила и отслеживать любое нарушение автоматически, что уже на подходе в нашем бэклоге. Сервис поможет разработчикам быть более дисциплинированными и освободит Reviewer’а от необходимости проверять соответствие кода принятому стандарту, и тогда эти инструменты станут помощниками в поддержании чистоты на проекте.
Ссылки: