Старые надежные структуры данных и их противоречивый доступ (запись).

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

В своей классической статье 1972 года Дэвид Парнас определил новую и основополагающую концепцию современной разработки программного обеспечения: Скрытие информации.

Правило простое:

Если мы скроем нашу реализацию, мы сможем изменять ее сколько угодно раз.

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

Давайте посмотрим, как смоделировать декартову точку:

Любой программный компонент, который манипулирует этими точками, будет связан с сохранением значений в виде декартовых координат x и y (Случайная реализация).

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



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

Поскольку это одна и та же точка в реальном мире, она обязательно должна быть представлена ​​одним и тем же объектом в нашей биекции.



Биекция всегда зависит от субъективности аспектов, которые мы пытаемся моделировать. Чтобы нарисовать многоугольник, декартова (1, 1) и полярная (√2, π / 8) точки являются одной и той же точкой.

Случай попытки представить несколько возможных математических представлений был бы другим, если бы мы программировали семантику Wolfram. В таком случае представление является частью проблемы, т. Е. Они будут моделироваться разными объектами.

Решение простое. Скрыть внутреннее представление.

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

Следующий эволюционный шаг

С появлением объектно-ориентированного программирования концепции инкапсуляции и сокрытия информации были доведены до атомарного предела. Мы больше не говорим об инкапсуляции в модуле, а в том же объекте.

Возвращаясь к предыдущему примеру, переходим от:

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

В хорошем дизайне объекты связаны с обязанностями (интерфейсами), а не с представлениями.

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

при изменении представления…

… Все продолжает работать правильно.

Алгоритмы и данные

Если бы мы работали по старому правилу:

программы = алгоритмы + структуры данных

… Тогда мы могли бы создавать отличное программное обеспечение с помощью сеттеров и геттеров.

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

Эти обязанности будут одинаковыми в отношении взаимного соответствия между этими объектами и реальным миром.



Инволюция

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

Давайте посмотрим на сеттеры и геттеры как на отдельные проблемы.

Сеттеры

Изменение внутреннего состояния объекта нарушает принцип неизменности. Это не рекомендуется, поскольку в реальном мире объекты не изменяются по своей сущности.



Единственный метод, разрешенный для записи в атрибуты, - это атомарная инициализация. С этого момента переменные должны быть доступны только для чтения.

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

Мы никогда не сможем объяснить бизнес-эксперту, какую ответственность несут эти методы от названия.

Представим себе многоугольник как структуру данных.

Предположим, что у многоугольника не менее трех вершин.

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

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

Попробуем добавить ограничение на количество вершин в конструкторе:

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

Если мы не используем наш сеттер…

Нам ничего не мешает запустить этот код:

На данный момент у нас есть два варианта:

  1. Дублируйте бизнес-логику в конструкторе и в сеттере.
  2. Устранение установщика навсегда в пользу неизменности

В случае принятия повторяющегося кода эффект пульсации начинает распространяться, когда наши ограничения растут. Например, если мы сделаем предусловие еще сильнее:

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

Правильный ответ, согласно нашим аксиомам дизайна, - второй.

Повторяющаяся или отсутствующая логика проверки инварианта

Многие объекты имеют инварианты, которые гарантируют их связность и достоверность представления для поддержания взаимного однозначности реального мира. Разрешение частичной настройки (атрибута) заставит нас контролировать инварианты представления в более чем одном месте, генерируя повторяющийся код, который всегда подвержен ошибкам при изменении ссылки и игнорировании другие ссылки.

Код генерируется без контроля

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



Это средство распространяет проблему, наличие этого инструмента дает ощущение, что это общепринятая практика.

Рекомендации

  • Не используйте сеттеры. Для этого нет веских причин.
  • Наличие методов с именем setSomething… () - это запах кода.
  • Не имеют публичных атрибутов. Для практических целей это все равно, что иметь сеттеры и геттеры.
  • Не имеют общедоступных статических атрибутов. В дополнение к тому, что упомянуто выше, классы должны быть без состояния, и это запах кода, показывающий класс, который используется как глобальная переменная.
  • Избегайте анемичных объектов (содержащих только атрибуты без ответственности). Это запах кода, намекающий на отсутствие объекта на биекцию.




Выводы

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

Геттеры

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



Частично цель этой серии статей - создать пространство для дебатов и дискуссий по дизайну программного обеспечения.



Ждем комментариев и предложений по этой статье.

Эта статья также доступна на испанском здесь.