Правильный код: правила хорошего тона начинающего программиста

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

Правило №1: в любой непонятной ситуации выбрасывайте исключение

thrown exceptions

Приведем пример:

List<String> getSearchResults(...) {
  try {
    List<String> results = // запрос к REST для вызова сервиса поиска
    return results;
  } catch (RemoteInvocationException e) {
    return Collections.emptyList();
  }
}

Этот кусок кода вызвал сбой в одном из мобильных приложений. Чтобы найти источник проблем, специалисты “набросали” исключений и пытались отловить баг. В процессе работы программа получала ответ от сервера “OK” и на запрос возвращала пустой ответ.

Если бы разработчики сразу позаботились о блоках try-catch, то API могло выдать exception, и проблема была бы сразу решена.

Бывают разные ситуации, в которых вернется пустой объект после  ожидаемого exception . Пустыми объектами в Java могут быть Optional.empty(), null или пустой список. Чаще всего это происходит во время парсинга URL. Перед тем, как вернуть null, если полученная ссылка не парсится стандартными методами, нужно найти в коде или источнике причину ее неправильного формирования.

Пустые объекты – это плохо, и лучше их не использовать. Если вам что-то показалось подозрительным, необходимо создать исключение.

Правило №2: используйте строгую типизацию

Строгая типизация

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

void doOperation(String opType, Data data); 
// где opType это "insert", "append" или "delete", здесь должен быть enum

String fetchWebsite(String url);
// где url это "https://google.com", здесь должна быть ссылка

String parseId(Input input);
// возвращаемый тип String, но на самом деле Long со значением "6345789"

Данный код яркий представитель Stringly typed программирования. Это такой процесс программирования, в котором разработчик очень часто использует строковые значения переменных, когда есть более логичная альтернатива.

Использование строгой типизации дает разработчикам возможность защититься от горы ошибок. Именно по этой причине большинство современных программистов переходят на типизированные языки, такие как Java.

Существует много источников, откуда берутся Stringly types, вот некоторые из них:

  • различные запросы и HTTP-ссылки;
  • JSON;
  • БД без поддержки enums;
  • не валидные дополнения.

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

// Шаг 1: Возьмем QueryParam, представляющий пару имя компании/id и парсим его
// пример: context=Pair(Proglib,456)
Pair<String, Long> companyMember = parseQueryParam("context");
// тут должно вылететь исключение, если данные изменены

// Шаг 2: Выполняем остальной код программы
// почти весь код должен быть в этой области

// Шаг 3: Преобразование возвращаемого параметра в String
String redirectLink = serializeQueryParam("context");

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

Правило №3: используйте Optionals вместо null

Правильный код

Самое долгожданное изменение, которого все так давно ждали в Java, – это класс Optionals, значительно облегчающий обработку исключений типа NullPointerException (NPE), которое обычно приводит к самым большим неприятностям, многочасовому дебаггингу и дорогостоящим простоям.

Optionals подключают в правильный код с целью полного исключения появления NPE в коде, при условии правильного использования.

Приведем правила применения Optionals в своем проекте:

  • Не нужно вызывать .get() каждый раз, когда необходимо задействовать Optionals.
  • Если проект все еще не имеет дефолтного значения, то методы .map() и .flatMap() позволят временно выступить в этой роли.
  • Если подключаемое расширение возвращает null, то оберните код при помощи Optional.ofNullable().
  • Используйте Optional как возвращаемый параметр метода.

Правило №4: применяйте “unlift” везде, где возможно

Если писать правильный код, то желательно избегать методов, указанных в примере ниже:

// ИЗБЕГАЕМ ЭТОГО:
CompletableFuture<T> method(CompletableFuture<S> param);
// ЭТО ХОРОШО: 
T method(S param);

// ИЗБЕГАЕМ ЭТОГО:
List<T> method(List<S> param);
// ЭТО ХОРОШО:
T method(S param);

// ИЗБЕГАЕМ ЭТОГО: 
T method(A param1, B param2, Optional<C> param3);
// ЭТО ХОРОШО:
T method(A param1, B param2, C param3);
T method(A param1, B param2);

Все описанные методы используют объекты-оболочки, такие как Optional, List или Task. Куда более недопустимо, если возвращаемое значение того же типа (т. е. метод принимает и возвращает Optional). Рассмотрим несколько примеров:

  1. Promise<A> method(Promise<B> param) – не такой гибкий, как having.
  2. A method(B param)

Если у вас в коде есть Promise<B>, то воспользуйтесь первым вариантом или вторым при помощи “lifting” функции .map (например, promise.map(method)).

Оригинал

Другие материалы по теме:

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ