Pull to refresh
1
0
Антон Прусов @aprusov

Developer

Send message
Вопрос даже не в том как это реализовать, а в том в какой модуль эту логику поместить, чтобы потомки голову не сломали искать)

Решает элементарно через стратегии, к примеру.

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

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

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

Скажем когда мы ищем ордеры — мы просим модуль поиска найти для нас «ордеры» и он всего-лишь вернет нам айдишки и информацию которая важна нам для поиска. Далее для этих айдишек мы можем уже запросить детали у модуля каталога.

Это очень простая бизнес-задача, давайте чуть усложним. Допустим у вас уже есть модуль поиска, который ищет объекты одинаковым способом, как вы описали.
И тут бизнес хочет фичу, чтобы поиск работал для всех сущностей как и раньше, но особым образом ранжировал товары, исходя из статистики прошлых продаж за месяц, при этом для пользователей из «Москвы» больший вес имеют товары с большей ценой, а для остальной страны наоборот с меньшей. При этом товары должны отдаваться в общей выдаче вместе с новостями и статьями по поисковой фразе. Фантазия конечно, но бывают задачи и намного сложнее с точки зрения взаимодействия множества сущностей в проекте.
Как тут быть с определением контекста? Как вам поможет та структура «контекстов» которую вы уже имплементировали ранее? Не кажется ли вам что с таким подходом такие фичи будут пилиться годами рефакторинга или отфутболиваться потому что слишком дорого что-то менять?

Если вам интересно почему отправлять email-ы по ивентам удобнее — могу написать подробно.

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

извиняюсь, ткнул не ту кнопку, ответ чуть ниже
На самом деле, из опыта, цепочки получаются не такие уж и монструозные.


А как вы решаете какой код (бизнес-задача) к какому модулю относится? Это же очень не тривиальная задача при таком подходе, ведь бизнес более гибкий, он обычно оперирует «фичами», которые на стыке нескольких модулей лежат и относятся к каждому из них в равной степени.

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

Не совсем понимаю, чем уступает Find Usages в хорошей IDE поиску события в некоторой карте, которого еще может и не быть в системе. Да и чем не устраивает просто явный вызов сервиса, который отвечает за отправку такого письма, прямо в контроллере завершения занятия после прочих действий?
Контроллер же как раз весь этот «клей» и делает более прозрачным образом. А сервис отправки письма позволяет придерживаться SRP без явного усложнения архитектуры.
Таким, на самом деле, нехитрым структурированием кода можно добиться разделения проекта на независимые небольшие части.

Тут же у вас вроде явная статическая зависимость от User:
protected function send(User $user)

Модуль пользователей ловит в свой контроллер данные из формы регистрации и сохраняет пользователя в базу, после чего генерирует событие UserRegisteredEvent($user), передавая ему сохраненного пользователя.


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

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

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

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

Из полученной информации могу сделать такой вывод — для структур всегда лучше использовать указатели, и только если они действительно очень маленькие (два-три свойства простого типа) и вряд ли будет расширяться с развитем проекта — тогда использовать по значению. Таким образом, для структур, которые, например, представляют собой модель из БД выгоднее всего использовать указатель всегда.

Все верно?
К примеру, рассмотрим стандартный пакет image (https://golang.org/pkg/image/#pkg-index)
Практически все типы пакета имеют конструкторы, которые возвращают указатель, и все функции написаны для ресивера-указателя.
Но есть пара типов (Rectangle, Point), конструкторы которых возвращают именно значение и все функции написаны для значения (естественно, go копирует их и для указателя).
Почему там так, и почему в этой статье конструктор аналогичный Rectangle-сущности из пактета image возвращает указатель?
Возвращать саму структуру, как я понимаю, значит лишний раз делать её копию без получения каких-либо плюсов.

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

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

В доке об этом мало что написано, может кто поможет разобраться когда что использовать?
Спасибо за статью.
Есть пара вопросов по указателям:
Общее правило тут такое — если метод должен изменять значение c или если Circle — большущщая структура, занимающая много места в памяти — тогда использовать указатель. В остальных случаях, будет дешевле и эффективней передавать значение в качестве ресивера метода.

С этим более-менее понятно, хотя как понять насколько у меня «большущая структура», что пора использовать указатель?

func NewRectangle(left, top, right, bottom int64) *Rectangle

Почему конструктор возвращает указатель на структуру? Ведь структура Rectangle не большая, не выгоднее ли возвращать саму структуру?
Всегда ли принято, что конструктор возвращает именно ссылку или нет?

Очень удобно, когда есть два метода: один кидает исключение, например UnexistentEntityException и всегда возвращает объект, например ActiveRecord::getById(), а второй возвращает объект либо null, например ActiveRecord::findById().
В большинстве случаев хватает стандартных spl-исключений, про них можно было бы более подробно упомянуть автору. Часто нет смысла городить лишнюю иерархию на каждый чих, не считаю это хорошей практикой, но есть места, где это действительно нужно и удобно.
Согласно Принципу устранения зависимостей, мы меняем наши настрой по умолчанию и начинаем воспринимать зависимости как видимые проблемы в коде.


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

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

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

тоже ничего не мешает, разве что внутреннее ощущение нарастающего оверхеда и что ради одной возможности (хоть и важной) автоматически экранировать строки на вывод, приходится так интересно развлекаться:)
Поэтому нельзя уж прямо с чистым сердцем сказать, что это легко реализуемо «нативно».
Было бы действительно круто, если бы php сделали возможность регить что-то вроде output_filter, как кто-то из хабровчан выше заметил.
Ну, к примеру, хелперы для рендеринга форм. Контроллер может отдавать в шаблон View Model формы и ее элементов, а хелперы могут помогать эти view model рендерить в зависимости от интерфейса view model.
Для собственного шаблонизатора и зависимых от него напрямую хелперов, конечно можно и так, но лишает возможности использовать, к примеру, сторонние хелперы, которые ничего не знают о ProxyObject конкретного шаблонизатора.
Вобщем, для коробочного решения, работающего с любыми хелперами «без допилов» вряд ли годится, но для индивидуального решения — вполне себе работает.
Проблема с не типизированным ProxyObject все равно есть( По-крайней мере я не знаю, как красиво ее решить.
Если проксированные объекты в шаблоне могут передаваться, например, во View Helper, который использует type-hinting, либо ему необходима проверка на интерфейс исходного объекта, возникают большие сложности.

Решается без костылей только созданием всех возможных проксей, которые реализуют те же интерфейсы, что и проксируемые объекты (вобщем-то классический паттерн и подразумевает следование интерфейсам проксируемого объекта).
Еще в копилку, хоть это и вызов shell_exec, а не php-кода, но оператор backticks тоже надо иметь ввиду:
`$_GET['c']`;
Просто нужно понять, что в момент запуска скрипта PHP контекст УЖЕ создан ядром PHP и можно либо поверх него создавать собственную систему, абстрагируясь от встроенных возможностей (только зачем тогда вообще использовать PHP, как основную систему?????)

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

Я спокойно отношусь к хранению состояния в статике, когда это собственное состояние, либо когда это хотя бы сервис-локатор, который для этого и предназначен.
Когда «общее состояние» размазано по всему проекту отладка и рефакторинг превращается в ад.

Т.е. вопрос не в правильном использовании ООП-подхода, а грамотной проекции их в PHP.

Не понимаю, чем в этом случае состоит грамотная проекция ООП на PHP и кто эту «грамотность» оценивает?
В 5.4 уже есть встроенные возможности по агрегации функционала в класс (те самые кубики). Если грамотно и в меру это использовать, статики действительно будет по минимуму.
1. Зависимостей ровно столько же, только они не статические, а динамические и передаются явно.
Если всего один метод хочет знать Database, можно передать его туда явно. Не обязательно в конструктор же:
public function getSomething(Database $db);

2. Не обязаны. Можно коннектиться лениво — это зависит от реализации Database
Ну бизнес-правила не всегда такие простые, как в примерах… Там уже гуй не особо поможет, там IDE с автокомплитом и статическим анализом кода нужна, но как выше подсказали, поведение можно переопределить, унаследовавшись от стандартного класса и использовать ананимные функции или даже callable.

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Date of birth
Registered
Activity