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

Developer

Send message
Название статьи не соответствует действительности. Тут скорее лишь попытка применения теоретических знаний о DDD на простейшем сферическом примере в вакууме, делеком от реальных требований бизнеса.
Ожидал, наконец, увидеть применение на реальном проекте с историей о том как введенные на начальном этапе адовы слои абстракции DDD помогали (или же мешали) развитию проекта в будущем.
Можно парсить на сущности (теги), используя XMLReader, а затем эту сущность разбирать уже через DomDocument. Таким образом, памяти будет кушать не много, а DomDocument куда более приятен и расширяем, хотя, конечно, по скорости будет чуть медленнее.

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

А может вы поделитесь опытом на серьезном ресурсе? Автор поделился своей практикой и он молодец.
Напишите, пожалуйста, чем конкретно он не прав и где ошибся в терминологии, а так же приведя примеры из своей практики, как вы сделали «по книжке» и это принесло профит проекту — в этом и ценность ресурса, не так ли?
Оба паттерна (AR, DM) имеют свои плюсы и минусы. Отделение логики персистентного хранения может быть реализовано и в нормальном AR.
AR вполне решает многие задачи и отлично тестируется (не верьте мифам о том что это не так). Далеко не всегда нужен DM с IdentityMap и UnitOfWork.
Хватит уже смотреть на них как на черное и белое.
Без понимания «зачем» никакого улучшения качества кода не будет, имхо. Будет только хуже.
Главное чтобы не получилось так, что когда ребенку задашь вопрос «а почему ты именно так сделал, можно же было по-другому?», он не ответил «так правильно.», без аргументов
Он уместен всегда, поскольку практически не требует усилий и работы мозга.

Конечно, следование любому паттерну или лучшей практике особо не требует усилий и работы мозга, в этом есть некоторая проблема, я считаю. Работы мозга «писателя» кода действительно особо не требуется, а вот «читатель» потом голову ломать будет, зачем здесь выделен тип исключения если он нигде не используется, что автор имел ввиду, можно ли это выпилить?

Можно пример?

Не понял какой пример вы хотите. Из личного опыта? Пожалуйста — проект, в котором я сейчас работаю (maxposter.ru). Нишевой проект, который «заточен» под автосалоны, под капотом довольно сложная бизнес-логика, аналитика, агрегация биллингов разных площадок, всяческие сложные мониторинги и логирование, которые чем-то похожи, но меняются раз в пол года без согласования с нами, и для которых не возможно выделить удачную абстракцию, которая будет сколько-нибудь жизнеспособной и помогла бы быстро решать проблемы. Именно здесь мы в команде пришли к выводу, что DDD не всегда применим, часто надо быть проще и жить будет легче. Проект успешно развивается командой, покрыт тестами, деплоится каждый день «по кнопке», имеет несколько микросервисов написанных на nodejs / golang которые тоже деплоятся «по кнопке». Основное наше конкурентное преимущество — качество и работоспособность сервиса и быстрое изменение кода под сложившуюся ситуацию. Мы с этим успешно справляется и дело тут далеко не в лучших практиках, иерархии типизированных исключений и удачных абстракциях.

При этом профита дает много.

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

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

Разве я говорил что я против этого, я как раз за, если это действительно зачем-то нужно и этот «компонент» выделили из приложения для переиспользования.
Я высказываю мнение против слепого следования практике «Для каждой ситуации — свой тип» исключения.
Не вижу смысла принципиально отличать код библиотечный и нет. Считаю качества он должен быть одинакового.

И библиотечный код и код конечного проекта конечно же должен быть одинаково качественны, с этим никто не спорит.
Вопрос в выборе того самого «должного уровня абстракции», о котором вы пишите.
Вы же понимаете, что создатели библиотечного кода решают несколько другие задачи, чем создатели конечного проекта и уровень абcтракции не соизмерим?

Что значит "довели"? Просто изначально были выбраны более простые решения и подходы, а потом выяснилось что их не хватает да и вообще, могли упереться в то, что и язык был выбран не удачно.
К примеру, можно взять за основу laravel, и быстро накидать довольно не плохой прототип проекта, используя магию, статические фасады, автоматическую инъекцию сервисов, все что ускорит получение результата, но не является "best practice". А можно долго и нудно конфигурировать Симфони, Доктрину и получить тот же результат, но с лучшими свойствами "качества" но за большее время. Так вот иногда время, которое экономится в ущерб качеству важно, ибо пока вы пишите православный слоистый код, вводите иерархию исключений, конкуренты берут и делают в 2 раза быстрее на коленке, и вы весь свой идеальный код несете на свалку. А конкуренты переписывают все на праволавную Симфони и начинают использовать лучшие практики именно в этот момент

Я понял ваше мнение, не буду переубеждать. Просто высказываю альтернативный подход, который тоже работает. Мой опыт привел меня от слоистой архитектуры с преждевременным вводом абстракций к подходу: "напиши просто, насколько это возможно, покрой тестами, чтобы можно было расширить и порефакторить". А после того как я пописал на golang довольно не простые сервисы минималистично и просто, я по другому посмотрел на современные практики в разработке и считаю что некоторые из них монструозны и не всегда уместны.

Нам возможно нужно отловить и обработать определенные исключения вроде «картинка слишком большая» и нам не хочется ловить исключения драйверов.


Я понимаю и осознаю пользу типизированных исключений, я против бездумного следования шаблону «а давайте на каждый чих сделаем новый тип исключений». Я за планомерный рефакторинг: изначально кидаем исключение общего типа, к примеру из SPL, если нужно как-то отдельно обрабатывать, вводим новый тип или маркерный интерфейс для множества ситуаций. Не понимаю, в чем проблема сделать это именно тогда когда понадобилось?
DataBaseException судя по названию больше к инфраструктурному слою относится же, а не к слою приложения, разве нет?
Смысл в том, что на верхнем уровне нам не интересно, какой драйвер и какая библиотека используется для работы с БД

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

Описываемый способ является де-факто стандартом в сообществе: он используется во многих серьёзных библиотеках и фреймворках. В том числе Zend, Symfony.

Кстати, а вы не задумывались, что описанный подход как раз таки уместен в переиспользуемых библиотеках/фреймворках и несколько избыточен для большинства (не говорю про все) конечных проектов?

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

Вы серьезно? А как же нишевые проекты, коих большинство и которые живут себе припеваючи, покрыты автотестами и вполне себе поддерживаются и развиваются без сферических абстракций в вакууме? Вы думаете если вы напишете идеальный код и напичкаете его точками расширений, то проект из интернет-магазинчика вырастет до уровня Яндекса или Гугла ?)
Ну и в конце концов, проект написанный плохо может быть легко переписан с нуля, если уж выстрелил и даже на другом языке. Примеров масса…

Каждая новая исключительная ситуация должна приводить к созданию нового типа (класса) исключения. Имя класса должно семантично описывать эту ситуацию.


Но вы же сами себе противоречите, приводя такой пример:

        try {
            $this->connection->query($data);
        } catch (\PDOException $e) {
            throw new DataBaseException(\i18n('Error on sql query execution: ' . $e->getMessage(), $e->getCode()), $e);
        }


То есть вы перехватываете исключение общего вида (\PDOException) и вводите свое исключение общего вида DataBaseException. Какой в этом смысл? Чем DataBaseException лучше \PDOException? Даже Query из него не вытащить же.

При проектировании приложения, абстракция — это то, что добавляет гибкости, и позволяет откладывать конкретные решения и детальную реализацию, пока не известны все нюансы, а требования к коду ещё не известны, либо могут поменяться. Это инвестиция, которая окупается со временем.

С этим, опять же, можно поспорить. Эта инвестиция может и не окупиться со временем с большой вероятностью, все зависит от проекта. Надо понимать что делаешь и для чего, а не реализовывать шаблоны типа «каждая новая исключительная ситуация должна приводить к созданию нового типа (класса) исключения», мало ли понадобиться в будущем… Для большинства конечных проектов вполне достаточно стандартных исключений.
Представьте себе что хороший монолит от микросервисов отличается только тем, что ивенты ходят в пределах одной машины а не между разными машинами.

Не считаю это признаком «хорошести» монолита. Все-таки критерии «хороший» / «плохой» тут вообще не уместны, мне больше по душе понятие «приемлемый», когда архитектура успешно решает все бизнес задачи и разработка нормально поддерживает и развивает кодовую базу.
Эвенты это всего лишь способ слабого взаимодействия модулей, это не серебряная пуля, которая решает проблемы да и не всегда эти проблемы то и есть даже в крупных проектах. Эвент — это осознанная точка расширения, пихать их бездумно «на будущее» очень большая ошибка, имхо
Так кто ж спорит что никуда, там им самое место. Но мы же говорим про монилит )
Мы же про большие проекты а не бложики.

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

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

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

Даже банальный вынос куска кода в метод снижает сложность.

С этим согласен, но опять же мера нужна — иногда выделение в 100500 мелких методов усложняет понимание кода. Именно поэтому есть рефакторинги Extract Method и обратный ему Inline Method, все это очень зависит от конкретной задачи и даже от конкретной команды и все приходит только с опытом, нет готовых рецептов на все случаи.
Абстракции как раз снижают сложность.

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

Ели абстракция идет лесом, то увы, была выбрана неверная абстракция

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

Information

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