Идентификаторы для распределённых систем

Каждый объект в информационной системе имеет некоторый признак по которому его можно однозначно идентифицировать — идентификатор. Если речь идёт о простых системах, то там вполне достаточно целочисленных идентификаторов, генерируемых средствами СУБД, или UUID. Они просты в использовании и понимании, но в то же время их возможностей недостаточно при построении распределённых систем, либо их поддержка создаёт определённые сложности.

Читать далее Идентификаторы для распределённых систем

Ветвление кода без исключений

Использование исключений для управления потоком выполнения является достаточно распространённой практикой. Однако во многих статьях и книгах, посвящённым лучшим практикам, например в замечательной книге Джошуа Блоха “Java — Эффективное программирование“ (Effective Java, Joshua Bloch), даётся рекомендация не использовать исключения как способ ветвления кода.

Читать далее Ветвление кода без исключений

Гексагональная архитектура, и как я к ней пришёл

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

Читать далее Гексагональная архитектура, и как я к ней пришёл

Инверсия управления: внедрение и поиск зависимостей

Инверсия управления — один из популярных принципов объектно-ориентированного программирования, при помощи которого можно снизить связанность между компонентами, а так же повысить модульность и расширяемость ПО.

Читать далее Инверсия управления: внедрение и поиск зависимостей

Многоуровневая архитектура в проекте на Java (Часть 2)

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

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

Читать далее Многоуровневая архитектура в проекте на Java (Часть 2)

Многоуровневая архитектура в проекте на Java (Часть 1)

В настоящее время в разработке ПО достаточно часто применяется многоуровневая архитектура или многослойная архитектура (n-tier architecture), в рамках которой компоненты проекта разделяются на уровни (или слои). Классическое приложение с многоуровневой архитектурой, чаще всего, состоит из 3 или 4 уровней, хотя их может быть и больше, учитывая возможность разделения некоторых уровней на подуровни. Одним из примеров многоуровневой архитектуры является предметно-ориентированное проектирование (Domain-driven Design, DDD), где основное внимание сконцентрировано на предметном уровне.

Читать далее Многоуровневая архитектура в проекте на Java (Часть 1)

SOLID на практике — Принцип подстановки Барбары Лисков

Принцип подстановки [Барбары] Лисков (Liskov Substitution PrincipleLSP, буква L в аббревиатуре SOLID), сформулирован Барбарой Лисков в 1987 году и звучит следующим образом:

Пусть q(x) является свойством, верным относительно объектов x некоторого типа T. Тогда q(y) также должно быть верным для объектов y типа S, где S является подтипом типа T.

Упрощенное описание этого принципа предложил Роберт Мартин:

Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа, не зная об этом.

Иными словами, поведение реализующих и наследующих классов не должно противоречить поведению базовых типов.

Читать далее SOLID на практике — Принцип подстановки Барбары Лисков

SOLID на практике — принцип инверсии зависимостей

Принцип инверсии зависимостей (Dependency Inversion PrincipleDIP, буква D в аббревиатуре SOLID), описанный Робертом Мартином, состоит из двух постулатов:

  • Высокоуровневые модули не должны зависеть от низкоуровневых; и те и другие должны зависеть от абстракций
  • Абстракции не должны зависеть от деталей, детали должны зависеть от абстракций

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

  • Взаимодействие между классами должно быть реализовано через интерфейсы или абстрактные классы
  • Типами всех членов классов должны быть интерфейсы или абстрактные классы
  • Классы, являющиеся конечными реализациями не должны расширяться (или должны быть финальными)
  • Аналогично методы не должны перекрываться при наследовании (или быть финальными)

Читать далее SOLID на практике — принцип инверсии зависимостей

SOLID на практике — принцип единственной ответственности

Принцип единственной ответственности (Single Responsibility Principle — SRP, буква S в аббревиатуре SOLID), описанный Робертом Мартином, гласит: «Класс должен иметь только одну причину для изменения».

Обратите внимание на следующий код:

В примере приведён метод сохранения изменений в записи типа Topic. Однако этот метод выполняет слишком много действий: валидацию полученных данных, поиск существующего объекта типа Topic, проверку прав доступа пользователя на этот объект, применение и сохранение изменений. И все эти действия могут меняться независимо друг от друга.

Следуя логике принципа единственной ответственности, нам следует выделить работу с источником данных, валидацию и проверку прав доступа, как минимум, в отдельные методы, а наиболее правильно — в отдельные классы.

Выделение логики в отдельные методы

В первом варианте мы разделим логику между методами класса TopicService. Кроме этого данные, получаемые методом update, логично будет инкапсулировать в одном классе:

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

Теперь этот код на уровне методов соответствует принципу единственной ответственности, чего не скажешь о всём классе TopicService. Не смотря на то, что методы findOneById, save, checkAccess и validate скрыты от внешнего наблюдателя, класс всё равно выполняет много действий.

Однако даже при этом код уже более удобен для понимания, а так же пригоден для повторного использования.

Выделение логики в отдельные классы

При выделении логики валидации, проверки прав и работы с источниками данных в отдельные классы, код приложения станет ещё удобнее и понятнее.

Таким образом мы получим класс, работающий с источником данных:

Класс, выполняющий валидацию UpdateTopicAction:

Класс, проверяющий доступ пользователя к объекту Topic:

Итоговый вид нашего сервиса будет следующим:

Таким образом мы на практике применили принцип единой ответственности.