Pull to refresh

Comments 27

Ну вообще цель была остановить то, что у вас на правой картинке, как-то это задепрекейтить и начать писать более упорядоченно, перейдя на современный стек. Вижу по комментам, что у читателей сложилось противоположное мнение. Значит, я не до конца донес свою мысль. На то она и первая статья.)

Весьма неплохо.

Разумеется, во всех случаях, когда реально требовалась работа двух приложений - я всегда делал буквально два приложения в двух изолированных контейнерах и роутинг между ними возлагал на третье приложение - роутер (к примеру на nginx и карту URL внутри него). Но ваш велосипед тоже интересен.

Тут выходит вместо двух приложений стало три, да еще и за роутингом следить нужно отдельно.

Мы в свое время мигрировали с symfony 1 и использовали "Legacy Bridge", сразу решив, что вместе их не мешаем, изначальное приложение не трогаем. Любой новый функионла на новой версии, запрос на обновления фунционал это прееписываение старого роута на новой системе. Оставили только хотфиксы. Из минусов возможно пара роутов сейчас все еще крутится на symfony 1, кто знает.

Вот у вас первое приложение, в котором 180 тыс. строк PHP кода и 250 таблиц. Команда из 10 бэков. Стартап, который очень нервно считает свои деньги. Менеджмент льет на команду требования по выпуску десятков фичей.

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

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

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

Как опираться? Да так и опираться - данные шарить между приложениями. База-то одна остается.

Не очень понятно, зачем в названии статьи упомянут монолит. По идее, альтернативой монолиту может быть микросервисная архитектура, SOA, serverless - но у Вас не то и не другое. Просто впихнули элементы одного фреймворка в другой, а приложение как было монолитным, так и осталось.

Притом что тот же DI-контейнер в Yii2 вполне есть и переписать код на гибкие зависимости можно было даже без симфони, не скрещивая ежа с ужом.

Да, все верно: монолит как был, так и остался. Оттого и упомянут, что в микросервисной архитектуре подход к решению задачи был бы другим. Вернее, там такая задача и не встала бы скорее всего.

А на счет переписать 180 тыс. строк высокосвязанного кода в проекте, который нонстопом дорабатывает 10 бэков, выпуская по несколько фичей в день - это что-то за гранью реального.)

Ну симфони вы же туда вкрутили)

А какие конкретные цели преследовались, когда принималось такое решение? Просто начать дорабатывать новые фичи уже на базе другого фреймворка, обеспечив между ними мостик?

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

Хочется же и валидатор, и сериалайзер, и доктрину, и другие симфонийские радости.) Тут надо понимать, что помимо смены фреймворка была и смена парадигмы разработки и архитектурного подхода. Просто описать все это в одной статье нереально, я и так старался покомпактнее, а получился большой текст.)

Я единственно хотел бы подчеркнуть, что не симфони был вкручен в проект, а проект был обернут в симфони. Больше того, новый код писался в новых папках. То есть, мы старое легаси оставили в проекте, но старались его не трогать, то есть не дописывать без крайней нужды. А когда старый код вызывался, то это делалось это по уму (про это отдельную статью можно написать).

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

нет, случаем, грусти, что через год-два появится статья типа "как я ускорял заскорузлый проект на symfony/yii с помощью go и laravel"?)

Сто процентов нет такой грусти.) А вот о статье, как пользоваться профайлером xdebug для этих целей действительно подумываю.) Боюсь спросить, как Laravel ускоряет проекты.) На Yii2 действительно видел один раз проект лет пять назад, где загрузка самого фреймворка забирала почти 2 секунды в каждом запросе. Не погружался тогда в причины, т. к. не мой проект был. Что до Symfony, то тоже как-то раз видел долгоживущий проект, где почти все классы были загружены в DIC, что добавляло нормально времени на его загрузку. Но в целом, скорость не от фреймворка зависит, а от разработчика. На любом фреймворке и языке можно шляпу написать.)

На любом фреймворке и языке можно шляпу написать.)

Ну я собственно про это и написал.

Хочется увидеть в статьях про переход или внедрение

1. что-то измеримое. Типа у нас было 180 тыс строк. Это плохо или хорошо, чем и как измеряли. Их написала другая команда за такой-то период. До внедрения своего решения добавляли столько-то строк в месяц, после - вот столько. Было столько "фич" в месяц, стало столько. Про что вообще фичи. Просто в комментарий про "несколько фич в день" как-то не верится.

2. какие-то примеры кода, мясо так сказать бизнесовое. Типа вот так у нас формируется отчёт в прежнем коде, а вот так с новым подходом. Вот так сообщения пользователю отправлялись раньше, а теперь вот так. Смотрите, как здорово получилось. И можно тогда обсудить, действительно ли здорово. Или может средствами йии такое можно сделать.

3. как вообще донесли до бизнеса смену/дополнение фреймворка? обычно бизнесу-то всё равно, что там внутри. А фреймворк меняют, чтобы очередной руководитель смог в резюме добавить строчку про разработку вот с такой хорошей штукой.

А пока проект с symfony/yii выглядит так, что следующая команда будет поддерживать проект со шляпой в квадрате. С очередными тремя конвертами.

На счет ваших пожеланий: здесь жанр другой. Рассказываю что и как делал, вдруг кому потребуется повторить. Цели как-то рекламировать решение не было и агитировать повторять за мной.

Строчку в резюме обязательно добавлю, хоть и не руководитель и решения не принимал.)

Количество строк измеряли плагином статистика в шторме. Плохо или хорошо иметь 180 тыс. строк связанного кода, решайте сами. Мне - плохо. За сколько их написали - понятия не имею, и не знаю, чем такая информация может быть полезна.

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

А на счет того, как в ваших глазах выглядит проект: правда в глазах смотрящего. В моих глазах он стал выглядеть намного лучше. И если я ни текстом статьи ни ответами на ваши и подобные комментарии не смог донести, почему стало лучше, то уже, видимо и не смогу.

180 тысяч строк это примерно 90 - 120 файлов с классами в Битриксе, не так уж и много, чтобы это перелопатить на чистый Symfony.

Из статьи непонятно, как вы дружили orm-ы? Или просто два отдельных pdo коннекта к бд?

Да, два отдельных коннекта, каждый из которых является оберткой PDO. ActiveRecord и Доктрина друг другу никак не мешают. В Yii коннект к базе представлен, как и все прочее, компонентом фреймворка и доступен через глобальный объект \Yii. Когда иишный Appication инстанцируется, загружаются и все компоненты Yii. Соответственно, с этой секунды нам доступен как сам коннект (параметры которого берутся из конфига Yii), Так и все классы-наследники ActiveRecord, которые внутри себя дергают этот самый коннект через обращение к Yii::$app->getDb().

Соответственно, в симфонийском DIC у нас зарегистрирован доктриновский DBAL Connection, который также является оберткой над PDO и сконфигурирован из doctrine.yaml. Даже если представить себе ситуацию, когда мы в одной репе начнем дергать ActiveRecord и доктриновские EntityRepository одновременно, под капотом будут именно два PDO коннекта к одной и той же базе.

В плане работы с моделями подход такой: Легаси-модели, наследники ActiveRecord стараемся дорабатывать как можно реже, только при крайней нужде. При решении новых задач создаем новые модели, которые мапятся на те же таблицы. Для того, чтобы не терять темп разработки, разрешается в рамках задачи мапить только те поля, которые нужны для ее решения. То есть, если у нас старая модель ActiveRecord на 50 полей, то новую можно сделать только на 5 полей, если для решения текущей задачи их достаточно. При решении последующих задач новую модель можно дополнять полями, можно выделять новые модели, которые смотрят на ту же таблицу. Была у нас монструозная легаси-модель на 50 полей, а мы ее постепенно разбили на 5 новых красивых моделей, пусть они и наполняются данными из одной таблицы.

Надеюсь, понятно объяснил, тут уже начинается история про архитектуру, можно несколько отдельных статей написать.)

Спасибо, по сути сказанного всё понятно. Но ведь при таком подходе с транзакциями беда. Если при обработке одного запроса лезть в одну таблицу из двух pdo коннектов, они же будут друг друга блокировать на уровне бд...

Я уж молчу о том, что два коннекта это перерасход ресурсов на пустом месте

Очень хорошее замечание, спасибо. Тут надо понимать, что в описываемом проекте вообще нет хороших решений.) Есть тяжелый код, который надо дорабатывать, команда немаленькая, кодовая база ежедневно пополняется. Искался путь хоть как-то облегчить написание нового кода и задепрекейтить старый, трогать его как можно реже, что почти невозможно, т. к. все равно на старый код приходится опираться (тут уже надо интерфейсами отгораживаться, но я снова ухожу в архитектуру)).

Соответственно, если при решении своей задачи разработчик попал в ситуацию, которую вы описываете, то у него есть как минимум два пути:

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

  • Открыть транзакцию доктриновским коннектом, флашнуть те энтити, которые у него есть, а остальные данные изменить нативными SQL запросами (можно востользоваться DBALовским QueryBuilder).

Я однозначно за первый вариант: второй грязноват, да и новый мапинг в будущем все равно пригодится, ведь в идеале хотелось бы со временем покрыть доктриной все 250 таблиц и оставить старые ActiveRecord только как носители кусков бизнес-логики. Как я сказал, в этом проекте нет хороших решений, приходится работать с тем, что есть.)

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

Чтобы начать думать о том, о чем вы говорите, нужно сначала забороть все вот такие вот места.)

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

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

Ну а самое главное отличие состоит вот в чем: команде, описываемой в статье, на которую вы ссылаетесь, выделили время (и, судя по всему, немаленькое) на рефакторинг. В нашем случае было потрачено полтора месяца моего времени, и все. Остальная команда не отрывалась от решения бизнес-задач. Если б у нас была возможность всей командой хотя бы четверть времени тратить на рефакторинг на протяжении какого-то длительного времени (а судя по вашей статье, команда начала рефактор в 17 году и закончила в 20), то, можно было бы много крутых вещей сделать.) Причем, само решение осталось бы таким же, каким я его описал, но вот старого кода можно было бы ооочень много выпилить, перенеся те же модели полностью на доктриновский мапинг с выносом бизнес-логики в доменный слой.

Красиво описано!
Кейс, конечно, интересный. Как звучит один из принципов программирования — «Будь готов к изменениям».
Есть задача, будем делать)

Sign up to leave a comment.

Articles