Typical Mistakes in Java Code

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Эта страница содержит наиболее типичные ошибки, которые я вижу в Java коде людей, работающих со мной. Статический анализ (мы используем qulice) не может поймать все ошибки по очевидным причинам, и поэтому я решил перечислить их здесь.

Дайте мне знать, если вы хотите видеть что-то еще добавлено здесь, и я буду рад выполнить ваше пожелание.

Все перечисленные ошибки связаны с объектно-ориентированным программированием в общем и с Java в частности.

Ваш класс должен быть абстракцией реальной сущности без “валидаторов”, “контроллеров”, “менеджеров” и т.д. Если имя вашего класса заканчивается на “-er”, это плохой дизайн. Кстати, вот мои семь добродетелей хорошего объекта. Кроме того, в этом посте подробно объясняется эта идея: Не создавайте объекты, которые заканчиваются на -ER.

И, конечно же, утилитарные классы являются анти-паттернами, как StringUtils, FileUtils и IOUtils из Apache. Это примеры ужасного дизайна. Прочитайте этот последующий пост: ООП-альтернатива утилитарным классам.

Конечно, никогда не добавляйте суффиксы или префиксы для различения между интерфейсами и классами. Например, все эти имена являются ужасно неправильными: IRecord, IfaceEmployee или RecordInterface. Обычно имя интерфейса является именем реальной сущности, в то время как имя класса должно объяснять детали его реализации. Если нет ничего специфического для сказать о реализации, называйте его Default, Simple или что-то подобное. Например:

Method Names

Методы могут либо возвращать что-то, либо возвращать void. Если метод возвращает что-то, то его имя должно объяснять что именно он возвращает, например (никогда не используйте префикс get):

Если он возвращает void, то его имя должно объяснять что он делает. Например:

Вы можете прочитать больше об этой идее в книге Elegant Objects, раздел 2.4. Есть только одно исключение из только что упомянутого правила - тестовые методы для JUnit. Они объясняются ниже.

Имена методов в тестах JUnit должны быть созданы как английские предложения без пробелов. Это легче объяснить на примере:

Важно начинать первое предложение вашего Javadoc с названия класса, который вы тестируете, за которым следует can (или cannot). Поэтому ваше первое предложение должно всегда быть похожим на “кто-то может сделать что-то”.

Название метода будет точно таким же, но без подлежащего. Если я добавлю подлежащее в начало названия метода, я должен получить полное предложение на английском языке, как в приведенном выше примере: “HttpRequest возвращает свое содержимое в формате Unicode.”

Обратите внимание, что метод тестирования не начинается с can. Только комментарии Javadoc используют ‘can’.

Хорошей практикой всегда является объявление методов тестирования с генерацией исключения Exception.

Избегайте составных имен переменных, таких как timeOfDay, firstItem или httpRequest. Я имею в виду как классовые переменные, так и переменные внутри методов. Имя переменной должно быть достаточно длинным, чтобы избежать неоднозначности в ее области видимости, но при этом не слишком длинным, если это возможно. Имя должно быть существительным в единственном или множественном числе или соответствующим сокращением. Подробнее об этом можно прочитать в этой статье: Составное имя - это признак плохого кода. Например:

Иногда может возникать конфликт между параметрами конструктора и свойствами класса, если конструктор сохраняет входные данные в созданном объекте. В таком случае рекомендуется создавать сокращения путем удаления гласных (см. как USPS сокращает названия улиц).

public class Message {
  private String recipient;
  public Message(String rcpt) {
    this.recipient = rcpt;
  }
}

Во многих случаях лучшую подсказку для имени переменной можно получить, прочитав ее название класса. Просто напишите его с маленькой буквы, и все будет хорошо:

Однако никогда не делайте такое для примитивных типов, таких как Integer number или String string.

Вы также можете использовать прилагательное, когда есть несколько переменных с разными характеристиками. Например:

Constructors

Без исключений, должен существовать только один конструктор, который сохраняет данные в переменные объекта. Все остальные конструкторы должны вызывать этот с разными аргументами. Например:

Больше об этом в статье “There Can Be Only One Primary Constructor”.

Избегайте использования одноразовых переменных вообще. Под “одноразовыми” я имею в виду переменные, которые используются только один раз. Как в этом примере:

Эта переменная выше используется только один раз, и код должен быть переработан в:

Иногда, в очень редких случаях — в основном из-за лучшего форматирования — могут использоваться одноразовые переменные. Тем не менее, по возможности старайтесь избегать таких ситуаций любой ценой.

Не нужно говорить, что вы никогда не должны глотать исключения, а вместо этого должны позволить им подниматься как можно выше. Приватные методы всегда должны пропускать проверяемые исключения наружу.

Никогда не используйте исключения для управления потоком выполнения. Например, этот код неправильный:

Серьезно, а что, если ошибка IOException говорит “диск заполнен”? Вы все равно будете предполагать, что размер файла равен нулю и продолжите?

Для отступов главное правило заключается в том, что скобка должна либо заканчивать строку, либо быть закрытой в той же строке (обратное правило относится к закрывающей скобке). Например, следующий пример неверен, потому что первая скобка не закрыта в той же строке, а после неё есть символы. Вторая скобка также нарушает правило, потому что перед ней есть символы и она не открыта в той же строке.

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

Второе важное правило отступов гласит, что вы должны поместить как можно больше на одной строке - в пределах 80 символов. Приведенный выше пример недействителен, так как его можно уплотнить.

Redundant Constants

Константы класса следует использовать, когда вы хотите передавать информацию между методами класса, и эта информация является характеристикой вашего класса. Не используйте константы вместо строковых или числовых литералов - это очень плохая практика, которая приводит к загрязнению кода. Константы (как и любой объект в ООП) должны иметь значение в реальном мире. Какое значение имеют эти константы в реальном мире:

Еще одна типичная ошибка - использовать константы в модульных тестах для избежания дублирования строк/чисел в методах тестирования. Не делайте этого! Каждый метод тестирования должен работать с собственным набором входных значений.

Используйте новые тексты и числа в каждом новом методе тестирования. Они независимы. Так зачем им нужно общее значение констант ввода?

Это пример связывания данных в тестовом методе:

На последней строке мы связываем "Jeff" с той же строковой литералой из первой строки. Если через несколько месяцев кто-то захочет изменить значение на третьей строке, ему/ей придется потратить дополнительное время на поиск других мест, где используется "Jeff" в том же методе.

Чтобы избежать такой связности данных, следует ввести переменную. Более подробно об этом здесь: Несколько мыслей о создании рабочей среды для модульного тестирования.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-27 at 10:47

sixnines availability badge   GitHub stars