Если нормально писать модули и компоненты то никакой проблемы нет (уже лет 5 наверное).
Все что внутри директории модуля /lib автоматически загружается (даже оказывается согласно PSR-4, но автору об этом знать не обязательно, пусть дальше живет в своих розовых фантазиях о ларавеле :)
PSR-4 это стандарт, а пространство имен уже языковая приблуда. В контексте компонентов пространство имен подразумевает директорию с компонентами одно вендора. Вас же почему-то не смущает, что пространство имен JS никакого отношения к PSR не имеет.
а) файл компонента component.php
Файл "class.php" в сторонке: ну да, ну да, пошел я на хер.
Спойлер: с трудом. Надо пойти в визуальный редактор, добавить тестовую страничку
Трудно - это наверное добавить вызов $APPLICATION->IncludeComponent там где это нужно без визуального редактора. Мне бы ваши трудности конечно.
Битрикс - не для хорошей жизни, терпеть его надо.
Когда нихера не умеешь и не знаешь, то вместо Битрикс с успехом можно подставить любую CMS и фреймворк ;-)
Время зависит от того какой у вас процесс разработки.
Если по SSH напрямую подключиться и на горячую внести правки, то это будет минут 20.
Если говорить про SVN: создали ветку, локально поправили, проверили, создали MR, отправили на ревью, смержили, отгрузили.
Если говорить про реалии: создали ветку, локально поправили, отвлекся на другую задачу (потерял контекст), вернулся к задаче (восстановил контекст), проверил, отвлекли в чате (потерял контекст), вернулся к задаче (восстановил контекст), создал MR, отправил на ревью, спустя 3 дня по ревью пришли правки, ну и т.д.
Так что 2-3 часа это оптимальный срок на решение задачи, а на написание кода действительно минут 10-20 потребуется :)
делов на минут 20... а тестировать то и нечего
Проверка правильной логики ресайза, проверка верстки, чтобы ресайз корректно садился, проверка на разных экранах/устройствах.
2-3 часа на тестирование отображения отресайзеной картинки, которые выливаются в 2 ветки условий в result_modifier.php с функцией CFile::ResizeImageGet?
И да, я имел ввиду трудозатраты на разработку, но тестинг точно займет не 2-3 часа, даже если это автотесты.
А по итогу всего-то надо было использовать встроенную функцию CFile::ResizeImageGet :-)
Теперь нам эту таблицу нужно скачать как обычную Excel таблицу
SQL запрос сделать товары join файлы, не?
И с помощью элемента множественная загрузка загружаем все наши фотографии.
Программисты, без комментариев.
Что вернет нам такой запрос? Таблицу с полными данными о файлах в файловой системе Битрикса
А все таки про SQL вы знаете :)
Ну и самый главный вопрос, а как вообще вас угораздило взяться за этот проект, если вы даже банально не можете положить рядом нужные скрипты на питоне и работать сразу с базой, а не "excel -> SQL -> загрузка файлов ручками -> поиск файлов в базе". Все решалось выводом отресайзеной картинки в шаблоне. Т.е. для тех кто работает с Битриксом часа 2-3, для вас наверное целая неделя ушла, оплата конечно соответствующая. Не стыдно так клиентов нагибать?)
Потому что Битрикс тоже умеет хранить категорию в отдельной таблице, конечно это делается через цать дополнительных запросов, и у Битрикса это не так быстро
А откуда вы знаете насколько Битрикс медленее? В нем как раз таки и реализован EAV : b_iblock_element (сущности), b_iblock_property (атрибуты), b_iblock_property_element (значения).
Запрос к категориям делается через 1 join, что мало похоже на "цать дополнительных запросов" :-)
Статья интересная (наверное). Но почему прочтения заголовка ожидалось прочитать про SOLID, а не про SOLIDWORKS? Какой-то дешевенький кликбейт получается.
Из каждого угла слышно "выходите из зоны комфорта". Ска, дайте пожалуйста хотя бы зайти в эту зону, прежде чем выходить из нее.
Это так, но ведь стресс возникает везде и всегда. Согласитесь, поднимать голос на коллег, швырять бумаги или как-то еще бунтовать, - не самое разумное решение. Даже на самой мирной и спокойной работе такие моменты случаются, когда хочется сделать именно как описано выше. Владеть собой и достойно коммуницировать свое недовольство - тоже навык. Но стресс нужно снимать так или иначе. Например, в спортивном зале, или просвещая себя любимым занятиям и хобби, например.
А зачем мучатся? Если ты не можешь ужиться в компании, или компания дерьмо, или у тебя постоянный стресс, то либо меняй себя, либо меняй окружение/компанию. Смысл страдать? Если аргумент "денюшки", ну тогда страдай дальше, раз нет возможности и желания изменить что-то.
Я понимаю ваш скепсис. Более того, я как и наверняка 99% людей миллион раз ходила на собеседования с HR и выходила со встреч разочарованная, непонятая и иногда облитая грязью. Но серьезно. Именно поэтому мы тут, на Хабре, пытаемся сказать вам, что не всегда все происходит именно так. И так быть не должно. Есть компании, где вам отзвонят, спросят про ваши впечатления и сомнения, посоветуют, как можно в будущем скорректировать самопрезентацию в будущем или на предстоящем собеседовании с непосредственным работодателем.
Эээ я прям удивлен что я 1% процент счастливчиков, у которых все ок на собеседованиях. Или может дело в том, что когда ты так себе специалист тебе и приходиться проходить миллион собеседования и слышать миллион отказов? И тут даже речь не про то, что я невероятный специалист (наверное), а про то что нужно адекватно себя оценивать.
Веселят такие ребята, которые: "Как это вы не готовы платить мне 100К в месяц за свободный график и удаленку? Я вообще-то студент (или еще круче "я онлайн-курсы прошел"), который только что выпустился и у меня нулевой опыт работы."
Да-да, именно вынесения всей каши из init.php в отдельный файл и инклудить его обратно в init - это тру ?
Вы наверное сами не понимаете о чем говорите:
# init.php
<?php
\Bitrix\Main\Loader::includeModule('module.name');
?>
# module.name/include.php
<?php
// подписка на события
// инциализация DI
?>
И в чем тут проблема? А если модулей несколько, то наверное вместо очередного инклуда модуля (и группирования кода по контексту a.k.a модулю), лучше конечно выносить это все в init.php, естественно (сарказм).
Ах да, наверное вы еще посоветуете не выносить обработчики событий в отдельный классы/функции, а прям в анонимной функции фигачить в init.php?
Хотелось бы конечно посмотреть на ваши проекты с вашей "хорошей практикой". Говнище редкостное наверное :)
Эвент диспетчер есть стандартный битриксовый, который вполне все потребности автора покрывает. Зачем нужно было тащить стороний?
Twig - фреймворк
Шаблонизатор. Битрикс по-умолчанию без него, и подавляющее большинство сайтов на Битрикс без шаблонизатора. И если этот чудо-сайт после уйдет кому-то другому на поддержку, то им весело и задорно придется разбираться в этом великолепии. Про документацию я думаю можно даже не мечтать в таких вот наследиях предыдущих разработчиков.
Но мы все знаем, к чему приводит привычка юзать init.php
Все мы это кто, говнокодеры? В init.php максимум, что нужно дак это вызывать 'Loader::includeModule', а все остальное уже размещать непосредственно в include.php модуля и/или доп файлах если include.php разрастается.
Также удручал тот факт, что шаблонизатор можно использовать только в компонентах, хотя это уже лучше, чем ничего.
А где еще вы их собираетесь использовать? Inline на публичных или админских страницах? Использование компонентов в целом хороший подход, когда у вас конкретный виджет (кусок кода) обособлен.
но т.к. опыта создания собственных событий у меня не было, то в силу собственной лени я решил не заморачиваться
Т.е. в целом вам лень написать 1 класс с двумя методами: 'addEventListener' которая добавит в массив колбэк и 'triggerEvent' которая прочитает из массива и выполнит колбэк?
Да, действительно, лень невообразимая, а заморочек и подавно не видно.
Хотя бы стоило добавить в конце листинг куска кода с использования Twig в компоненте
Название "анемичная модель" считаю некорректым, так как Entity - это скорее DTO, которое вполне описывает БД, и не соответствует значению слова "анемичность"
Выдержка из статьи: "Это просто данные, минимум логики". Собственно это и есть анемичная модель: сущности где куча гетеров и сеттеров без какой-либо логики.
Entity можно сделать отдельным низкоуровневым слоем (инфраструктурным). И тогда они будут отделены от слоев выше, где логика приложения, предметная область.
Дак они у вас и сейчас находятся там (правда инфраструктурный слой выше слоя приложения, слой данных вы наверное имели ввиду?), и очень жестко (1 в 1) завязаны на структуре БД и очень вряд ли отражают объекты с точки зрения предметной области.
С одной сущностью может быть связано много разной логики. Ответственность уже разделяется внутри модуля, если нужно. А модуль берет данные из ентити через инверсию зависимости, например. То есть, Entity реализует интерфейс, который определен в модуле. А в интерфейсе могут быть просто геттеры сеттеры, данные, в общем.
Мы все еще говорим про НЕ анемичную модель, ага.
Собственно, это и объясняется в том абзаце, только более подробно.
В том абзаце очень неожиданный вывод, что нужно сделать UserStore, что вообще не вяжется с предметной областью: есть склад, есть товар, который хранится на складе, есть пользователь который ответственный за склад и товары в нем.
А в вашем варианте получается: есть пользователь, есть склад пользователя, есть товар который хранится на складе пользователя. Получается что склад без пользователя/заведующего не может быть?
Если уж дальше разруливать эту ситуацию, то по хорошему должны быть контексты (в рамках статьи наверное модули):
товар, склад и заведующий склада (который никакого отношения не имеет к пользователю, имеет только ид, который в рамках приложения совпадает с ид пользователя)
пользователь который вообще никак не сопрекасается со складом и товарам
Подробнее посмотрите про ограниченный контекст.
Конечно, делать того, о чем вы говорите не стоит. Но можно туда написать хороший код, и тогда практически одним копипастом вы сможете перенести его в любой класс.
Не нужно строить иллюзий, "хороший код, там где не нужно" === "говнокод" :)
Названия слоев довольно условны, их может быть больше или меньше, а может и не быть, если модуль небольшой, например
Вот прям обидно стало за ребят, которые все эти слои "кровью и потом" и своим опытом выводили. А оказывается они условны.
Каждый слой отвечает за конкретную зону ответственности, конкретные действия и сущности, и определенным образом может, или не может, взаимодействовать с другими слоями.
Делаем по-простому, усложняя по мере необходимости. Либо сразу делаем сложно, если знаем, что это может понадобиться.
В целом плохая идея делать "сложно", чем проще система тем лучше. А делать что-то на будущее бред, поэтому что это будущее может не наступить (и скорее всего не наступит). Поэтому нужно делать ровно то что надо, но оставлять возможно для расширения.
Про SOLID не забываем, но тоже применяем по необходимости.
Что простите? Дак не забывать или делать? И что такое "по необходимости", когда это оправдано делать god-object "семирукицсемисис" который делает все что угодно? Или наследовать объекты с разным поведением только лишь для переиспользования кода?
Entity отображают таблицы, ... Это просто данные, минимум логики.
А в чем плюс анемичных моделей в сравнении с моделями домена?
Так мы не привязываем структуру наших классов с логикой к структуре таблиц БД
Именно так и вы привязываете структуру ваших классов к структуре БД, Entity же отражают структуру таблиц из БД из предложения выше.
Например, если логика относится к Product, кладем ее в ProductService. Если сервис будет расти, мы сможем выделить из него, например, ProductStoresService
Лучше бы сразу выделять сервис, возвращаясь к вопросу о SOLID и единственной ответственности, который будет работать только с одной сущностью.
А если будет происходить взаимодействие складов не только с товарами, а с чем-то еще, например, с пользователями, заведующими складами, то может появиться другой StoresService, в другой папке — UserStores
Эээ а зачем? Stores же в любом случае работает с Product и он является его частью. Или у вас склады могут существовать без товаров? Если у вас склад это независимая ни от чего сущность (т.е. может существовать сам собой без User и Product), то выделяйте его в отдельный модуль, иначе (даже по мере роста функционала), где изначально находился сервис там его и оставляется и расширяйте.
Если код небольшой, можно писать его прямо в контроллере. Но можно и в отдельном сервисе или нескольких сервисах
Опять таки, зачем изначально говнокодить? В контроллерах не должно быть бизнес-логики раз уж вы ее в сервисы отправили, иначе вы нарушаете свою же слоистость.
P.S. статье на хватает хотя бы листингов папок, чтобы наглядно видеть о чем речь.
P.S.S. есть подозрение, что вы либо не докрутили, либо целенаправленно не используете старые добрые слои: domain - data - service - infrastructure , и у вас получается кашка из-за этого. Ну и в целом у вас получается этакий DDD (только нет Domain Model (а зря) и разделения на Entity/Aggregate (хотя в целом можно и без него пережить) миксом с CQS (где UseCases это Command).
С наступлением пандемии, когда все ушли на удаленку, для описания задач и фичей мы использовали notepad, textedit, sublime - все, что попадало под руку, чтоб зафиксировать текст.
А таск менеджер использовать, нет? Он вроде и создан для того что копить и структурировать задачи.
А диаграммы нужны проекту для понимая проекта в целом, а не решения конкретно задачи. Т.е. диаграммы нужны всегда, а не только когда стоит какая-то задача.
А статья хорошая и инструмент полезный и нужный :)
Пол статьи убили на то, чтобы описать разницу моков и стабов (сомнительное конечно разделение при том что и то и другое моки) и только к концу главы пришли к примеру CQS, который все расставил бы по полочкам с самого начала. Воды, воды, еще больше воды!!!
Как по мне моки нужны только для ситуаций когда в момет выполнения тестов у нас нет нужной службы, либо она не нужна для теста (бд, брокер сообщение, почтовый сервер и т.д.). В остальном если строить тесты по принципу черного ящика (когда нам без разницы что внутри), то хрупкость тестов ооочень сложно достичь.
Примеры из статьи же:
Creating_a_report - зачем нам проверять сколько раз вызывался "GetNumberOfUsers" ? Нам важем результат, нам без разницы сколько раз вызывалась функция.
Purchase_fails_when_not_enough_inventory - зачем нам проверять что не удалялось именно 5 штук шампуней? Нам нужно убедиться, что вообще ничего не удалялось, т.е. метод RemoveInventory не вызывался (опять таки это зависит от заложенной логики)
Т.е. если подойти с другого бока к тестам нужно относиться (и стараться достичь этого) как к функциональному программированию: при отправке одних и тех же аругментов, мы должны получать ровно тот же результат, и как раз это должны обеспечивать моки (сохранение одинакого состояния от теста к тесту).
Если касаться же подхода проектирования, то на CQS очень хорошо ложатся тесты: каждой команде/запросу все необходимые сервисы/сущности передаются в конструкторе (если конечно передаются и в целом на проекте используется DI) и тестируется ровно один метод (execute/query). Таким образом при написании тестов мы сами контролируем какие зависимости отправлять, мы точно знаем, что должно происходить при выполнении команды/запроса, и нам абсолютно не важно* что происходит внутри, нам важно выполнение команды и один из ее возможных вариантов завершения.
А дополнительные размышления по поводу "хм, это мок или стаб?" только тормозят сам процесс написания теста. Конечно, такое разделение нужно для того, чтобы быстро понять надо ли проверять или нет, НО зачем вводить дополнительные условия (да к тому же еще и 5 вариантов моков), если это все должна диктовать бизнес-логика приложения? Если нам важно с точки зрения выполнения конкретной задачи выполняется тот или иной метод мока - то нужно это проверить. Если нам не важно и это никак не влияет на результат задачи - то нам и надо это проверять. И не нужно вводить дополнительные термины и строить теорию на ровном месте, где она абсолютно не нужно.
*По поводу "абсолютно не важно"небольшая ремарка: если в рамках бизнес-логики должно отправляться письмо клиенту, то это нам конечно нужно проверить (замокать EmailService), но нам точно неважно вызывался ли, и сколько раз, какой-то вспомогательный сервис, который никак не влияет на результат выполнения команды. Например, мы тестируем создание заказа на недостаточное количество товара, нам абсолютно без разницы запрашивалось ли количество товара на складе и сколько раз, нам важно, что заказ не будет создан по причине недостаточности товара (кинет соответствующее исключение или вернет ошибку).
Если нормально писать модули и компоненты то никакой проблемы нет (уже лет 5 наверное).
Все что внутри директории модуля
/lib
автоматически загружается (даже оказывается согласноPSR-4
, но автору об этом знать не обязательно, пусть дальше живет в своих розовых фантазиях о ларавеле :)PSR-4 это стандарт, а пространство имен уже языковая приблуда. В контексте компонентов пространство имен подразумевает директорию с компонентами одно вендора. Вас же почему-то не смущает, что пространство имен JS никакого отношения к PSR не имеет.
Файл "class.php" в сторонке: ну да, ну да, пошел я на хер.
Трудно - это наверное добавить вызов
$APPLICATION->IncludeComponent
там где это нужно без визуального редактора. Мне бы ваши трудности конечно.Когда нихера не умеешь и не знаешь, то вместо Битрикс с успехом можно подставить любую CMS и фреймворк ;-)
Не угодишь никому :)
Время зависит от того какой у вас процесс разработки.
Если по SSH напрямую подключиться и на горячую внести правки, то это будет минут 20.
Если говорить про SVN: создали ветку, локально поправили, проверили, создали MR, отправили на ревью, смержили, отгрузили.
Если говорить про реалии: создали ветку, локально поправили, отвлекся на другую задачу (потерял контекст), вернулся к задаче (восстановил контекст), проверил, отвлекли в чате (потерял контекст), вернулся к задаче (восстановил контекст), создал MR, отправил на ревью, спустя 3 дня по ревью пришли правки, ну и т.д.
Так что 2-3 часа это оптимальный срок на решение задачи, а на написание кода действительно минут 10-20 потребуется :)
Проверка правильной логики ресайза, проверка верстки, чтобы ресайз корректно садился, проверка на разных экранах/устройствах.
Не сказал бы что нечего)
2-3 часа на тестирование отображения отресайзеной картинки, которые выливаются в 2 ветки условий в result_modifier.php с функцией CFile::ResizeImageGet?
И да, я имел ввиду трудозатраты на разработку, но тестинг точно займет не 2-3 часа, даже если это автотесты.
А по итогу всего-то надо было использовать встроенную функцию
CFile::ResizeImageGet
:-)SQL запрос сделать товары join файлы, не?
Программисты, без комментариев.
А все таки про SQL вы знаете :)
Ну и самый главный вопрос, а как вообще вас угораздило взяться за этот проект, если вы даже банально не можете положить рядом нужные скрипты на питоне и работать сразу с базой, а не "excel -> SQL -> загрузка файлов ручками -> поиск файлов в базе". Все решалось выводом отресайзеной картинки в шаблоне.
Т.е. для тех кто работает с Битриксом часа 2-3, для вас наверное целая неделя ушла, оплата конечно соответствующая. Не стыдно так клиентов нагибать?)
Посмотрите в сторону того как фасетный индекс у Битрикс устроен, вопросы по поводу нескольких куч отпадут)
А откуда вы знаете насколько Битрикс медленее? В нем как раз таки и реализован EAV : b_iblock_element (сущности), b_iblock_property (атрибуты), b_iblock_property_element (значения).
Запрос к категориям делается через 1 join, что мало похоже на "цать дополнительных запросов" :-)
Маразм крепчал) Видимо вам будет трудно понять, что работая с Битрикс - работаешь на PHP, а вот работая с PHP - НЕ работаешь на Си.
По вашей логике работая со Spring НЕ работаешь на Java?)
Статья интересная (наверное). Но почему прочтения заголовка ожидалось прочитать про SOLID, а не про SOLIDWORKS? Какой-то дешевенький кликбейт получается.
Bitrix - CMS на языке PHP, поэтому ваша фраза "Переход с bitrix на любой универальный язык программирования" крайне неадекватна :)
Немного иронично что в статье "Regex for lazy developers" нет никакой информации про lazy выражения: https://regex101.com/r/id4r4i/1
Достатошно полезная штука, особенно в HTML.
Из каждого угла слышно "выходите из зоны комфорта". Ска, дайте пожалуйста хотя бы зайти в эту зону, прежде чем выходить из нее.
А зачем мучатся? Если ты не можешь ужиться в компании, или компания дерьмо, или у тебя постоянный стресс, то либо меняй себя, либо меняй окружение/компанию. Смысл страдать? Если аргумент "денюшки", ну тогда страдай дальше, раз нет возможности и желания изменить что-то.
Эээ я прям удивлен что я 1% процент счастливчиков, у которых все ок на собеседованиях. Или может дело в том, что когда ты так себе специалист тебе и приходиться проходить миллион собеседования и слышать миллион отказов? И тут даже речь не про то, что я невероятный специалист (наверное), а про то что нужно адекватно себя оценивать.
Веселят такие ребята, которые: "Как это вы не готовы платить мне 100К в месяц за свободный график и удаленку? Я вообще-то студент (или еще круче "я онлайн-курсы прошел"), который только что выпустился и у меня нулевой опыт работы."
Вы наверное сами не понимаете о чем говорите:
И в чем тут проблема? А если модулей несколько, то наверное вместо очередного инклуда модуля (и группирования кода по контексту a.k.a модулю), лучше конечно выносить это все в init.php, естественно (сарказм).
Ах да, наверное вы еще посоветуете не выносить обработчики событий в отдельный классы/функции, а прям в анонимной функции фигачить в init.php?
Хотелось бы конечно посмотреть на ваши проекты с вашей "хорошей практикой". Говнище редкостное наверное :)
Конечно же импортозамещением. Не на маркетинг ведутся, ага.
И на БУС и на Б24 можно поднимать адекватные проекты, если конечно ручки-не-криворучки, но видимо в этом случае как раз они.
Эвент диспетчер есть стандартный битриксовый, который вполне все потребности автора покрывает. Зачем нужно было тащить стороний?
Шаблонизатор. Битрикс по-умолчанию без него, и подавляющее большинство сайтов на Битрикс без шаблонизатора. И если этот чудо-сайт после уйдет кому-то другому на поддержку, то им весело и задорно придется разбираться в этом великолепии. Про документацию я думаю можно даже не мечтать в таких вот наследиях предыдущих разработчиков.
Все мы это кто, говнокодеры? В init.php максимум, что нужно дак это вызывать 'Loader::includeModule', а все остальное уже размещать непосредственно в include.php модуля и/или доп файлах если include.php разрастается.
А где еще вы их собираетесь использовать? Inline на публичных или админских страницах? Использование компонентов в целом хороший подход, когда у вас конкретный виджет (кусок кода) обособлен.
Т.е. в целом вам лень написать 1 класс с двумя методами: 'addEventListener' которая добавит в массив колбэк и 'triggerEvent' которая прочитает из массива и выполнит колбэк?
Да, действительно, лень невообразимая, а заморочек и подавно не видно.
Хотя бы стоило добавить в конце листинг куска кода с использования Twig в компоненте
Выдержка из статьи: "Это просто данные, минимум логики". Собственно это и есть анемичная модель: сущности где куча гетеров и сеттеров без какой-либо логики.
Дак они у вас и сейчас находятся там (правда инфраструктурный слой выше слоя приложения, слой данных вы наверное имели ввиду?), и очень жестко (1 в 1) завязаны на структуре БД и очень вряд ли отражают объекты с точки зрения предметной области.
Мы все еще говорим про НЕ анемичную модель, ага.
В том абзаце очень неожиданный вывод, что нужно сделать UserStore, что вообще не вяжется с предметной областью: есть склад, есть товар, который хранится на складе, есть пользователь который ответственный за склад и товары в нем.
А в вашем варианте получается: есть пользователь, есть склад пользователя, есть товар который хранится на складе пользователя. Получается что склад без пользователя/заведующего не может быть?
Если уж дальше разруливать эту ситуацию, то по хорошему должны быть контексты (в рамках статьи наверное модули):
товар, склад и заведующий склада (который никакого отношения не имеет к пользователю, имеет только ид, который в рамках приложения совпадает с ид пользователя)
пользователь который вообще никак не сопрекасается со складом и товарам
Подробнее посмотрите про ограниченный контекст.
Не нужно строить иллюзий, "хороший код, там где не нужно" === "говнокод" :)
Вот прям обидно стало за ребят, которые все эти слои "кровью и потом" и своим опытом выводили. А оказывается они условны.
Каждый слой отвечает за конкретную зону ответственности, конкретные действия и сущности, и определенным образом может, или не может, взаимодействовать с другими слоями.
В целом плохая идея делать "сложно", чем проще система тем лучше. А делать что-то на будущее бред, поэтому что это будущее может не наступить (и скорее всего не наступит). Поэтому нужно делать ровно то что надо, но оставлять возможно для расширения.
Что простите? Дак не забывать или делать? И что такое "по необходимости", когда это оправдано делать god-object "семирукицсемисис" который делает все что угодно? Или наследовать объекты с разным поведением только лишь для переиспользования кода?
А в чем плюс анемичных моделей в сравнении с моделями домена?
Именно так и вы привязываете структуру ваших классов к структуре БД, Entity же отражают структуру таблиц из БД из предложения выше.
Лучше бы сразу выделять сервис, возвращаясь к вопросу о SOLID и единственной ответственности, который будет работать только с одной сущностью.
Эээ а зачем? Stores же в любом случае работает с Product и он является его частью. Или у вас склады могут существовать без товаров? Если у вас склад это независимая ни от чего сущность (т.е. может существовать сам собой без User и Product), то выделяйте его в отдельный модуль, иначе (даже по мере роста функционала), где изначально находился сервис там его и оставляется и расширяйте.
Опять таки, зачем изначально говнокодить? В контроллерах не должно быть бизнес-логики раз уж вы ее в сервисы отправили, иначе вы нарушаете свою же слоистость.
P.S. статье на хватает хотя бы листингов папок, чтобы наглядно видеть о чем речь.
P.S.S. есть подозрение, что вы либо не докрутили, либо целенаправленно не используете старые добрые слои: domain - data - service - infrastructure , и у вас получается кашка из-за этого. Ну и в целом у вас получается этакий DDD (только нет Domain Model (а зря) и разделения на Entity/Aggregate (хотя в целом можно и без него пережить) миксом с CQS (где UseCases это Command).
А таск менеджер использовать, нет? Он вроде и создан для того что копить и структурировать задачи.
А диаграммы нужны проекту для понимая проекта в целом, а не решения конкретно задачи. Т.е. диаграммы нужны всегда, а не только когда стоит какая-то задача.
А статья хорошая и инструмент полезный и нужный :)
Пол статьи убили на то, чтобы описать разницу моков и стабов (сомнительное конечно разделение при том что и то и другое моки) и только к концу главы пришли к примеру CQS, который все расставил бы по полочкам с самого начала. Воды, воды, еще больше воды!!!
Как по мне моки нужны только для ситуаций когда в момет выполнения тестов у нас нет нужной службы, либо она не нужна для теста (бд, брокер сообщение, почтовый сервер и т.д.). В остальном если строить тесты по принципу черного ящика (когда нам без разницы что внутри), то хрупкость тестов ооочень сложно достичь.
Примеры из статьи же:
Creating_a_report - зачем нам проверять сколько раз вызывался "GetNumberOfUsers" ? Нам важем результат, нам без разницы сколько раз вызывалась функция.
Purchase_fails_when_not_enough_inventory - зачем нам проверять что не удалялось именно 5 штук шампуней? Нам нужно убедиться, что вообще ничего не удалялось, т.е. метод RemoveInventory не вызывался (опять таки это зависит от заложенной логики)
Т.е. если подойти с другого бока к тестам нужно относиться (и стараться достичь этого) как к функциональному программированию: при отправке одних и тех же аругментов, мы должны получать ровно тот же результат, и как раз это должны обеспечивать моки (сохранение одинакого состояния от теста к тесту).
Если касаться же подхода проектирования, то на CQS очень хорошо ложатся тесты: каждой команде/запросу все необходимые сервисы/сущности передаются в конструкторе (если конечно передаются и в целом на проекте используется DI) и тестируется ровно один метод (execute/query). Таким образом при написании тестов мы сами контролируем какие зависимости отправлять, мы точно знаем, что должно происходить при выполнении команды/запроса, и нам абсолютно не важно* что происходит внутри, нам важно выполнение команды и один из ее возможных вариантов завершения.
А дополнительные размышления по поводу "хм, это мок или стаб?" только тормозят сам процесс написания теста. Конечно, такое разделение нужно для того, чтобы быстро понять надо ли проверять или нет, НО зачем вводить дополнительные условия (да к тому же еще и 5 вариантов моков), если это все должна диктовать бизнес-логика приложения? Если нам важно с точки зрения выполнения конкретной задачи выполняется тот или иной метод мока - то нужно это проверить. Если нам не важно и это никак не влияет на результат задачи - то нам и надо это проверять. И не нужно вводить дополнительные термины и строить теорию на ровном месте, где она абсолютно не нужно.
*По поводу "абсолютно не важно" небольшая ремарка: если в рамках бизнес-логики должно отправляться письмо клиенту, то это нам конечно нужно проверить (замокать EmailService), но нам точно неважно вызывался ли, и сколько раз, какой-то вспомогательный сервис, который никак не влияет на результат выполнения команды. Например, мы тестируем создание заказа на недостаточное количество товара, нам абсолютно без разницы запрашивалось ли количество товара на складе и сколько раз, нам важно, что заказ не будет создан по причине недостаточности товара (кинет соответствующее исключение или вернет ошибку).