То что описано в первом абзаце - и есть криво спроектированная архитектура, насколько я понимаю. То что используется в разных слоях/сервисах/пакетах, должно быть вынесено в отдельное место. И если в use_cases есть несколько сервисов/пакетов, которые потенциально могу обращаться друг к дружке - это косяк, безусловно. Нужно выделить эту самую общую сущность из них. Но это уже отдельная тема, ИМХО. Про более низкий уровень архитектуры. И да, она важная. Сталкивался с таким. Когда в слое service (use_case) джун сделал тупо несколько CRUD-сервисов. Пока были обращения к одной таблице внутри метода - всё было ок. Типа записать/прочитать таблицу users... Ну а потом стало весело )))
Ну моя статья не про разработку структуры данных ). Вы пишете о зацикленности в структуре данных (моделях, таблицах БД). Это отдельная тема. Стучаться минуя слои - нехорошо, ИМХО. Лишние три строчки кода на вызов - не такая большая издержка чтобы ломать идеологию. Ну и как аналогия - клавиатура ПК не может обратиться к жесткому диску, минуя процессор )) Есть такая штука Теория разбитых окон. Одно окно разобьешь - со временем все повыбивают ))
В целом вы конечно правы. Но хочется, чтобы работа приносила какой-то кайф. Не всё ж деньгами меряется. А за велосипед из костылей потом стыдно перед людьми и самому смотреть противно )))
Собственно если в двух словах о том, что я предлагаю: Объекты из верхнего слоя могут обращаться к объектам нижнего слоя, но не наоборот. Нижележайщий слой относится к тому что выше - как сервер к клиенту. Клиент может вызывать методы сервера, но сервер не может вызывать методы клиента. Таким образом, вызовы распространяются всегда в одну сторону "сверху вниз", что исключает зацикленные ссылки между слоями. Порядок слоев сверху вниз: "api" -> "service" -> "controller". Всё. В этом суть моего предложения.
"где границы связности сущностей?!" - не понял ваш вопрос. Если вы о моделях (DTO), то общие живут в отдельной папке internal/models не общие - соответственно в <layer>/models. Что вы подразумеваете под "связывать в логике"? Моя идея (не моя изначально конечно) - вся бизнес-логика - только в слое service. Проверка доступов очевидно не относится к бизнес-логике. Бизнес-логику (именно "бизнес") лучше не размазывать по слоям а сосредоточить в слое service. Тогда и понимать код и сопровождать будет проще. Ну это вроде как очевидный тезис... Например: репозиторий выполняет только атомарные функции с одной таблицей - читать/писать/изменять/удалять. Если нужно создать запись в таблице "заказы" и при этом изменить запись в таблице "оплаты" - делаем один метод "СоздатьЗаказ" в слое service, который в транзакции делает два обращения к репозиторию. Но именно в слое service - я об этом. Если же у вас возникает зацикленный импорт - верный признак ошибочной архитектуры.
Поддерживаю. Хорошее решение. Вопрос "А зачем?" на эту тему давно себе не задаю, после трех месяцев, потраченных на перевод кода проекта с MS SQL на PostgreSQL. Там SQL и код приложения были в одной куче и это был реально трэш ))
Нет, не догадаюсь и догадываться не хочу, уж простите. Если вы не хотите быть понятым, с чего вдруг мне прикладывать к этому усилия ))) И кстати, никакого псевдокода в вашем примере нет. Это скорее недоразумение, а не пример ))
Копья ломаются по поводу того, что пагинация по limit/offset - плохо или вообще - пагинация зло. Но, по предложенному способу вроде замечаний особо нет )). Дело в том, что есть случаи, когда и объем и нагрузка небольшие и заказчик хочет вот простейшую пагинацию. Это мой случай как раз. ИМХО, с ума сходить не стоит и лучше сделать простейшим способом. Ну а когда/если понадобится оптимизация - тогда и будем морщить лоб )). Спасибо, коллеги!
А как же условия WHERE, в котором может быть много разных полей? Например, отображение товара в интернет магазине с фильтрацией по куче разных параметров (полей)? Как СУБД осуществит фильтрацию, читая только таблицу первичного индекса? Ничего не понимаю...
То что описано в первом абзаце - и есть криво спроектированная архитектура, насколько я понимаю. То что используется в разных слоях/сервисах/пакетах, должно быть вынесено в отдельное место.
И если в use_cases есть несколько сервисов/пакетов, которые потенциально могу обращаться друг к дружке - это косяк, безусловно. Нужно выделить эту самую общую сущность из них.
Но это уже отдельная тема, ИМХО. Про более низкий уровень архитектуры. И да, она важная.
Сталкивался с таким. Когда в слое service (use_case) джун сделал тупо несколько CRUD-сервисов. Пока были обращения к одной таблице внутри метода - всё было ок. Типа записать/прочитать таблицу users... Ну а потом стало весело )))
А есть бизнес-слои "одного уровня"Как это возможно?... Бизнес слой - это абстракция (папка service) и он один...
К сожалению, я не понимаю о чем вы говорите ((
"два слоя entity стучатся друг к другу - цикл" - какие слои entity? Зачем и как стучатся?... Извините.
Ну моя статья не про разработку структуры данных ). Вы пишете о зацикленности в структуре данных (моделях, таблицах БД). Это отдельная тема.
Стучаться минуя слои - нехорошо, ИМХО. Лишние три строчки кода на вызов - не такая большая издержка чтобы ломать идеологию. Ну и как аналогия - клавиатура ПК не может обратиться к жесткому диску, минуя процессор ))
Есть такая штука Теория разбитых окон. Одно окно разобьешь - со временем все повыбивают ))
В целом вы конечно правы. Но хочется, чтобы работа приносила какой-то кайф. Не всё ж деньгами меряется. А за велосипед из костылей потом стыдно перед людьми и самому смотреть противно )))
Собственно если в двух словах о том, что я предлагаю: Объекты из верхнего слоя могут обращаться к объектам нижнего слоя, но не наоборот. Нижележайщий слой относится к тому что выше - как сервер к клиенту. Клиент может вызывать методы сервера, но сервер не может вызывать методы клиента. Таким образом, вызовы распространяются всегда в одну сторону "сверху вниз", что исключает зацикленные ссылки между слоями. Порядок слоев сверху вниз: "api" -> "service" -> "controller". Всё. В этом суть моего предложения.
"где границы связности сущностей?!" - не понял ваш вопрос. Если вы о моделях (DTO), то общие живут в отдельной папке internal/models не общие - соответственно в <layer>/models. Что вы подразумеваете под "связывать в логике"?
Моя идея (не моя изначально конечно) - вся бизнес-логика - только в слое service. Проверка доступов очевидно не относится к бизнес-логике. Бизнес-логику (именно "бизнес") лучше не размазывать по слоям а сосредоточить в слое service. Тогда и понимать код и сопровождать будет проще. Ну это вроде как очевидный тезис...
Например: репозиторий выполняет только атомарные функции с одной таблицей - читать/писать/изменять/удалять. Если нужно создать запись в таблице "заказы" и при этом изменить запись в таблице "оплаты" - делаем один метод "СоздатьЗаказ" в слое service, который в транзакции делает два обращения к репозиторию. Но именно в слое service - я об этом.
Если же у вас возникает зацикленный импорт - верный признак ошибочной архитектуры.
Поддерживаю. Хорошее решение. Вопрос "А зачем?" на эту тему давно себе не задаю, после трех месяцев, потраченных на перевод кода проекта с MS SQL на PostgreSQL. Там SQL и код приложения были в одной куче и это был реально трэш ))
"спустя четно потраченные нервы" - это звучит! )))) Вы сделали мой вечер!
Илья, спасибо! Прям ровно то, что я искал! С меня причитается! ))
Нет, не догадаюсь и догадываться не хочу, уж простите. Если вы не хотите быть понятым, с чего вдруг мне прикладывать к этому усилия ))) И кстати, никакого псевдокода в вашем примере нет. Это скорее недоразумение, а не пример ))
как можно сравнивать с чем-то id, когда это UUID?
Это не скелет, увы. Это просто непонятная строчка ))
" id > lastpage" - очаровательно :). Особенно учитывая то, что это разные типы данных в моём случае
Ни одного противоречия нет. Вы придираетесь )
Под морщить лоб я понимаю либо отказ от пагинации либо оптимизация для снижения нагрузки )
Копья ломаются по поводу того, что пагинация по limit/offset - плохо или вообще - пагинация зло. Но, по предложенному способу вроде замечаний особо нет )). Дело в том, что есть случаи, когда и объем и нагрузка небольшие и заказчик хочет вот простейшую пагинацию. Это мой случай как раз. ИМХО, с ума сходить не стоит и лучше сделать простейшим способом. Ну а когда/если понадобится оптимизация - тогда и будем морщить лоб )). Спасибо, коллеги!
А как же условия WHERE, в котором может быть много разных полей? Например, отображение товара в интернет магазине с фильтрацией по куче разных параметров (полей)? Как СУБД осуществит фильтрацию, читая только таблицу первичного индекса? Ничего не понимаю...
Не очень понял, почему
SELECT id FROM mega_tableбудет существенно быстрее, чемSELECT * FROM mega_tablСкиньте, плз, ссылку - что почитать про передовую мысль и last_id. Буду благодарен!