Найти тему

Несколько соображений о технической архитектуре

Есть один вопрос который как мне кажется недостаточно освещен в технической архитектуре. Это протекание абстракций конкретной интеграции в другие области приложения. Вот например. нам надо брать файлы из скажем OneDrive и складывать их скажем в БД. У нас понятно есть класс который это оркеструет и у него есть метод возьмиОттудаПоложиТуда(...). И есть два класса отвечающие за интеграцию с OneDrive и с БД Дальше у нас есть два варианта

1) мы вот те сущности которые нам возвращает OneDrive (файловые дескрипторы) передаем напрямую в оркестратор и пусть он сам там решает что и как.

2) мы на выходе из класса которые обслуживает OneDrive приводим все к УНИФИЦИРОВАННОМУ ВИДУ и дальше оркестратор работает с абстрактными интерфейсами и сущностями. А уже класс отвечающий за OneDrive или скажем YaDisk их реализует.

подход 1 имеет очевидный минус - в оркестратор поступает совершенно ему не нужнгые ДНК OneDrive и он зависит не только от своего класса, но и от SDK OneDrive. Если нам надо добавить второй сервис - начинается месиво. Точнее месиво начинается с третьего но не важно.

плюс подхода 1 в том, что не надо долго оборачивать то что идет из OneDrive в иерархию Борщей. Что получил, то и отдал. кода меньше, в ряде подробностей можно сильно глубоко не копаться.

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

минус подхода 2 в том, что у нас много лохматого код который просто перекладывает всякое разное между классами. Причем если полей скажем штук 20 это очень некрасивый и ломкий код. еще минус в том, что даже если вы описали универсальную структуру и она подходит для OneDrive и YaDisk может оказаться что интеграция условно с РамблерДиском потребует передать какой-нить id живой сессии которого у вас в структуре нет и надо его для всех добавлять. В результате у вас получится либо совершенно не читаемый Франкенштейн с ногами ластами и крыльями либо у вас будет разветвленная структура классов с универсальными методами и всем тем что мы видим в проектах Джакарты. Она всем хороша, но понять ее без пол литры часто бывает очень сложно, что в свою очередь опять ведет к ошибкам. Ну и расширять ее опять же не сахар.

Вопрос как быть. В целом я как правило скорее сторонник подхода 1. Но на количестве точек интеграции >5 это товарищи полный кирдык и я сам готов это признать

На мой взгляд ответ тут нам дает как это ни банально звучит в 2022 году функциональное программирование. Решение выглядит так:

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

Этот подход отличает от п2 два момента:

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

Из минусов тут - спеки вот этих функций и их зацепление друг с другом на 28-ом году объектного мира мозг большинства программистов скорее всего будет проектировать с трудом.

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

Если смотреть из функции - то обычно в нее проще передать много разного контекста, что концентрирует полезный код внутри тельца функции а не размазывает по 10050 фабрик классов.