Я использую Groovy около 4 лет. Код, который я писал 3 года назад, сильно отличается от кода 1 года и от кода, который я пишу в эти дни. Почему это?
Несомненно, одна часть этого — то, что я становился все более и более знакомым с Groovy за эти годы, и Groovy становится все более сильным; такие функции, как @Delegate и особенно @Mixin, меняют способ написания кода.
Однако основные причины разные. Когда я начал использовать Groovy, я был Java-разработчиком. И именно поэтому в течение первых нескольких месяцев мой код больше походил на Java с замыканиями и необычными коллекционными литералами; Я считаю, что это так для многих разработчиков Groovy.
Затем я много занимался разработкой на Ruby, и это изменило мои привычки и стиль кодирования. Всего несколько примеров: в Ruby нет интерфейсов. Они просто не имеют никакого смысла в мире Ruby. Вы не указываете тип, когда определяете переменную в Ruby. Мы указываем def в groovy, если не хотим указывать точный тип переменной.
Сравните эти две части кода:
class SqlPersonRepository
...
def find_by_name name
...
end
...
end
class SqlPersonRepository {
...
def findByName(name){
...
}
...
}
Они практически идентичны. Какой код будет писать разработчик Java, когда он начнет использовать Groovy?
class SqlPersonRepository implements PersonRepository {
...
Person findByName(String name){
...
}
...
}
Я не говорю, какой из них лучше, это не главное. Дело в том, что они такие разные, и Groovy позволяет использовать оба, и это может сбивать с толку.
И я был смущен, смущен двумя разными культурами (Java и Ruby), и я долго не мог решить, какой стиль я предпочел. Чтобы упростить это для себя, я попытался формализовать это, чтобы найти несколько простых правил, на которые я всегда буду обращать внимание, когда не знаю, какой стиль следует использовать.
Прежде чем упоминать правила, я хотел бы написать о трех основных вещах, влияющих на то, как я пишу код на Groovy.
-
Совместимость с Java. Довольно часто ваши классы Groovy должны расширять классы Java или реализовывать некоторые интерфейсы. Или классы Java должны использовать ваши классы Groovy. В обоих случаях у вас нет выбора, но везде используются типы и интерфейсы. Если вы этого не сделаете, ваш Java-код станет безобразным.
-
Поддержка IDE. Для ребят из Ruby все очень просто, IDE не очень вам помогают. Даже RubyMine от JetBrains (!!) не так впечатляет. Напротив, Groovy IDE действительно потрясающие. В частности, поддержка Groovy в IDEA обеспечивает расширенное автозаполнение и рефакторинг. Когда у вас есть все эти функции, вы не хотите их терять, поэтому вы указываете типы для автозаполнения.
-
Использование динамических возможностей. Хотя Groovy обладает чрезвычайно мощными динамическими возможностями, позволяющими делать все (возможно, почти все) сумасшедшие вещи, которые я делал в Ruby, я не часто использую все эти возможности. Это просто не часть Groovy культуры. Если вы пишете даже небольшую библиотеку на Ruby, то обычно добавляете некоторые методы в базовые классы. Мы не делаем это в Groovy. За исключением Грааля и еще нескольких библиотек. Конечно, ситуация отличается при разработке языка, специфичного для предметной области. Но давайте будем честными, мы не делаем это каждый день.
Исходя из этих моментов, я сформулировал некоторые правила, которым я пытаюсь следовать, чтобы сохранить мой стиль кодирования единообразным.
Правило 1
Все, что является публичным, должно иметь указанный тип, если только тип не Object. Это значит, что я напишу публичный метод так:
Person findByName(String name){
...
}
Если аргумент или тип возвращаемого значения — Object, я ничего не указываю:
def transformObject(obj){
...
}
Правило 2
Я обычно не указываю типы в приватном методе, если это действительно не помогает понять это. Также я могу указать тип параметра, когда я вызываю много методов, и мне действительно нужно автозаполнение. Я никогда не указываю типы возврата для частных методов. Очень часто IDEA может вывести эти типы из кода, и у меня все равно есть автозаполнение.
Person findByName(String name){
internalMethod name
}
private internalMethod(name){
...
}
Почему я это делаю? Лично для меня указание типов во всех частных методах добавляет много шума в код. Если у вас есть 50-строчный класс, все ясно из контекста. Вам не нужно повторяться все время.
Person findByName(String name){
def prefixedName = getFirstName(name)
}
private getFirstName(name){
...
}
Понятно, что name — это String, а тип возвращаемого значения — String. Зачем мне это писать?
Правило 3
Все типы свойств должны быть указаны.
class Person {
String name
int age
}
Правило 4
Не указывайте типы для локальных переменных. Я не делаю этого, потому что IDEA может определять типы, и у меня есть автозаполнение.
def greeting = sayHi('john')
private sayHi(name){
"Hi $name"
}
IDEA знает, что приветствие — GString.
Правило 5
Если что-то может быть сделано во время компиляции, это должно быть сделано во время компиляции. Если мне нужно делегировать вызовы методов другому объекту, я бы предпочел использовать @Delegatethan methodMissing.
Правило 6
Используйте интерфейсы для публичных API. Другим разработчикам гораздо проще понять, что необходимо реализовать, если используются интерфейсы. Если вам требуется что-то вроде:
class ConditionBuilder {
void addCondition(condition)
}
это может занять некоторое время, чтобы понять, что такое состояние.
Правило 7
Предоставить конструкторы для открытых классов.
class Person {
String name
int age
Person(String name, int age){
...
}
}
Очень часто я не предоставляю конструкторы для своих внутренних служебных классов. Вы могли бы сказать, что контакт строительства не ясен в этом случае. Лично для меня новый Person (имя: «Джон», возраст: 50) выглядит лучше, чем новый Person («Джон», 50), и обычно мой внутренний код тестируется очень хорошо, поэтому у меня нет проблем с нулевыми значениями.
Это семь простых правил, помогающих мне принимать решения о стиле моего кода. Некоторые из них продиктованы тем, что поддержка IDE улучшается, и указывать типы во всех методах больше не нужно.
С http://vsavkin.tumblr.com/post/3191162772/groovy-coding-style