Чистая архитектура (логический дизайн) и чистый код (физический дизайн) имеют общий ключ к успеху, а именно разделение задач/ответственности и сохранение их независимости. Если с этой точки зрения логическая схема не является чистой, за ней последует физический план.
Единая ответственность
Давайте подумаем: техническое задание (или Спецификация работы, или Требования к работе): Заказчик утверждает: Как пользователь, я могу отмечать различные документы.
Агент
В системе, которую увидит пользователь, он ставит теги, тогда как на самом деле за него работает класс/модуль. И это мы называем «Агент», который несет ответственность за то, чтобы это произошло. В этом случае мы называем этого агента «Tagger», который реализует концепцию «Tagged» с объектом, называемым «Tag», на объектах, которые называются «Tagable».
Смерть логического дизайна
Основная проблема возникает, когда мы делаем это тегирование с помощью 100–500 строк кода и не заботимся о создании объектов, думая о том, что такое действие, кто является агентом и каковы его объекты. Поскольку требования меняются каждый раз, когда нам приходится корректировать код, применение методов объектной ориентации становится невозможным.
Почему это происходит, поскольку мы явно избегаем логического проектирования и сразу приступаем к физическому проектированию. В настоящее время я вижу в названии архитектуры все, что связано с проектированием развертывания и стека технологий, и среди них — коммуникация. Я редко вижу, чтобы люди уделяли время логическому дизайну предметной области и сразу же переходили к коду после WBS.
Действие к агенту существительному
Глагол к его существительному к интерфейсу
Определить глагол из требований и преобразовать его в понятие с герундием (ing) не так уж сложно.
Я хочу пометить/Возможность пометить — — → Пометка → Интерфейс
Tagging { doTag(Tag t, Taggable object);}
Я хочу назначать типы/Возможность назначать типы — — → Классификация
Classifying { doClassify(Type t, Classifiable object);}
Я хочу создать версию/Возможность создавать версии — — → Управление версиями
Versioning { doVersion(Version t, Versionable object);}
Агент Существительное (суффикс - или, эээ)
Теперь тот, кто реализует эту концепцию Действия, становится Агентом (Исполнителем).
Тегирование — — —› Тегирование — —› Реализация
Tagger Implements Tagging { doTag(Tag t, Taggable object){ ##TODO: any business logic e.g. check if tag exists object.tag(t); } }
Концепция действия/Интерфейс в сравнении с чертами объекта/Интерфейс (тегирование и тегирование)
Чтобы агент выполнил действие над объектом, объект должен быть совместим с этим действием. Эта совместимость объекта является его способностью/чертой/интерфейсом для взаимодействия с агентом.
Taggable { tag(Tag t);}
И когда объект реализует это
Object implements Taggable { tag(Tag t){ this.setTagId(t.getId()); // any other business logics. } }
Возможность повторного использования и изменения требований
Теперь, когда мы видим, что существуют разные виды концепций тегирования, например. Ручная пометка, автоматическая пометка, затем просто расширяйте концепцию/интерфейс и расширяйте реализацию следующим образом. И когда мы увидим, что есть разные типы тегов, сделайте то же самое с концепцией тегов и их реализациями. Создавая абстрактные и базовые классы, мы можем создавать повторно используемый код и даже применять шаблоны, если это необходимо.
Мышление/Концепция всегда на первом месте
Каков основной вывод здесь, если мы не можем определить концепцию действия и назвать ее, существует огромная вероятность того, что мы не понимаем единой ответственности, и в итоге мы получим беспорядочный дизайн и код.
###
Отказ от ответственности: взгляды, отраженные в этой статье, являются взглядами автора и не обязательно отражают взгляды любого бывшего или настоящего работодателя автора.