Pull to refresh

Comments 28

1.
… все колонки nullable()

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

2. не надо БДшный код пихать в миграции
хайповая тема — документарные БД, кому то нравиться, у нас не используются.
это был толстый сарказм
Лучше структурированных БД, пока ничего не придумали, поэтому лучше выжимать их них максимум.
Типы данных надо объявлять такими, какими они будут, это позволит:
— отправить мета инфу на фронт и обработать максимально эффективно 95% ошибок
— на уровне БД перехватить ошибки и проксировать их пользователю. Тут опять же максимальная производительность и минимальный код

Всё не то.
А если вам надо тип переменной изменить?
Например поле name сделали сначала 15 символов, потом поняли что надо 30, а потом поняли что надо 255. Рандомные миграции приведут к рандомной длине поля.
И очень интересно будет будущим разрабам смотреть в базе миллион колонок, которые давно уже не используются

Размер колонок меняется миграцией в любую сторону. Разве это проблема?
Но на самом дела колонки всегда надо создавать максимальной длины. Современным СУБД не важно колонка 10 символов или 100, если в неё пишется только 5, то места на диске будет занято только на 5 символов.
При желании тип колонки можно поменять в миграции. Если колонку добавили недавно, то это не проблема. Если колонку добавили давно, то просто добавляем новую колонку и работаем только с ней, старую колонку не пишем и не читаем.
Работать с таблицами через select *, это всегда был дурной тон. Всегда надо указывать колонки которые вас действительно интересуют.
И на самом деле в таблице должны быть колонки для индексов и одна колонка data в которую пишется json с бизнес данными. Но это высший пилотаж. Для тех кто понимает что такое база данных.
Если в таблице стало 200+ колонок и используется только 10. То почему не начать работать с новой таблицей?
Первый релиз делаем миграцию с новой таблицей и пишем посев данных с переносом данных из одной таблицы в другую, следующий релиз меняем в моделе имя таблицы и теперь мы работаем с новой таблицей в которой только нужные нам 10 колонок.

за полгода было написано 1000+ миграций

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

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


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

Какой то странный подход, что nullable — ради какого то мнимого удобства выпилить на корню все чеки на уровне бд. Ну блин в мускле можно strict отключить — чего мелочится. Что миграции которым похрен на что они накатываются. Всегда думал что миграции ровно и должны отваливаться с криками если та структура на которую они накатываются отличная от того что думал программист который их писал.
Люди из-за проблем с миграциями и деплоем кода в целом, запариваются за переход на сервисную модель, а потом и на микросервисы.
Есть разница между пет проектами, ин-хаус для фирмы на пару тысяч сотрудников и для приложения которое работает с десятками тысяч пользователей с функционалом объёма примерно обычной CRM системы, в которой лидов 100500 вариантов и каждый вариант обрабатывается уникальным образом.
Вы понимаете, что Вы внутренние проблемы, связанные с 'показом наработок аналитику' и 'слиянием веток' тянете в прод к заказчику?

Т.е., грубо говоря, когда заказчик спросит, почему БД разрослась до большого объёма и почему там есть колонки\таблицы, которые не используются, но замедляют работу и едят память, что Вы ответите?
Это все здорово. Представим гипотетическую ситуацию. Программист Петя решает добавить поле для указания должности и называет его position, за соседним столиком программист Вася решает добавить поле для указания семейного положения и звезды сходятся так что он тоже решает назвать его position. В случае когда миграции используются как должно — один из них получит отлуп. В вашем случае миграции выполнятся. И даже код работать будет. Вася в одну запись добавит женат, Петя в другую добавит должность программист. И вродь все ок. А через 3 дня у вас появится два багреквеста, один от клиента у которого должность — женат, а у другого у которого семейное положение — программист. Вы заходите в базу и видите что у вас есть 50% значений семейного положения и 50% значений поля должность — остальное ушло в /dev/null. Если у вас система мелкая и к этому времени накопилось 20 записей то ну как и бы и ладно, восстановим. А если система серьезная и к вам за это время прилетело 20 миллионов записей — то начальство вам организует тамаду и интересные конкурсы. То же самое с nullable — один косяк программиста и ура — конкурсы. И это мы рассматриваем простую ситуацию когда у вас банальный инсерт или апдейт. А если у вас какие нибудь транзакции на 25 таблиц, то начальство может вам не тамаду с конкурсами организовать а целый диснейленд.

И ровно попричине что ваша система серьезная и там много клиентов и всего такого — стоит озаботится тем что бы в базу ни в каком разе не могли попасть невалидные данные. И о чудо для этого в бд есть constraint на все случаи жизни. А в миграциях есть эксепшн который будет орать если его пытаются накатить не на то состоянии базы, которое использовал программист при создании
Система разделена на модули-сервисы, у каждой таблицы есть команда владелец.
Проблема не в том что таблицу правит два разных человека которые между собой не договариваются, проблема в том что для одной фичи нужны одни колонки, для другой другие, и какие то колонки могут после проверки гипотезы на драфте умереть на всегда.
А приложение не должно падать от таких вещей. Если приложению важно что бы какие то данные соответствовали каким то требованиям, то эти требования надо проверять на уровне приложения, а не БД, потому что БД одна, а версий приложения с десяток.
Перекраивать БД под каждую конкретную версию кода не реально (ветки фич иногда приходиться сливать в одну ветку и тестировать их совместную работу)
Мне кажется у вас не было опыта подобной разработки, поэтому вам сложно уловить на слух, это та вещи которую надо увидеть.
Приложение и не умирает. Умирает попытка выкатить миграцию в бд или код в систему. И это нормально. Вам ваши инструменты — как то ларавеловские миграции, или к примеру тот же гит сообщают что ваш код написан в состоянии системы далеком от текущего состояния. И это жжжж — не просто так. Это правильно. Это так должно быть. Для этого эти инструменты и придуманы. Можно пойти дальше — и автоматизировать резолв конфликтов в гите --ours — чо парится что состоянии системы изменилось, мы тут серьезные вещи пишем. Собственно имхо ваш подход к бд не сильно от этого решения отличается.
В приложении надо валидировать данные. Но и на уровне бд имхо должен быть бастион — который не даст внести невалидные данные.
У меня встречное впечатление. Что то в том как вы работаете и как у вас организованно — что то пошло не так, если вы выпиливаете constraint из бд и один из основных принципов работы миграций потому что иначе никак, иначе неудобно
И почему умрёт миграция по добавлению колонок? оно колонки добавит. А вот когда мы будем инсертить через модель новую запись у которой не все колонки заполнены (текущая версия не знает о колонке добавленной другой версией), тогда приложение упадёт.
Потому что она должна умереть если у вас состояние бд отличается от того что замыслил программист. Это следствие из смысла существования миграций. Если вы отказываетесь от этого смысла — они вообще вам не нужны. Можно фигачить через консоль запросы руками.
Схожая проблема и с отказом от constraint в бд. Там выше уже предлагали тупо писать в файл.

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

Чуть-чуть в курсе да. Я вас ровно возвращаю к ситуации которую я описал — про Петю и Васю. Когда в случае должной работы миграций — у вас выполнится одна миграция — вторая не выполнится потому что состояние БД уже не позволяет эту миграцию выполнить. Тот механизм который вы весело выпилили — со словами миграции должны накатываться бесконечно и откатываться бесконечно. То есть по факту миграциям плевать на какую версию структуры бд им накатываться как и версиям коду плевать с какой версией бд им работать. Собственно если учитывать что сам смысл миграций это поддержка консистентности между версиями кода и версиями бд — то получается вы выпилили главный механизм миграций. И заменили его на контроль человеком, «у каждой таблицы есть команда владелец». Это в корне не правильно, и причины для того что бы у вас в прод вываливалось такое веселье вы описали явно не достаточные.
Ровно так же причин не хватает выпиливать constraint из дб. Ну говорю ж к чему эти полумеры strict=off и льем туда вообще что захотим

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

З.З.Ы. Ваши слабые попытки намекнуть мне что я «ростом не вышел» — начинают чуток утомлять честно говоря. Вы уж либо их прекращайте, уверяю вас, я работал не только с пет проектами, знаю что такое миграции и даже сталкивался с последствиями решения — а давайте выпилим какие то проверки на уровне бд и через 3 месяца проверим чо там у нас получилось. Либо уж тогда делайте их более сильными — «дурак не фига не понимаешь» и закрываем общение.
я про Фому, вы про Ерёму. Главное назначение миграции это возможность как накатить так и откатить изменения в схеме БД без участия человека, в ручном режиме. Сделать эти изменения повторяемыми, не зависящими от среды.
Continuos delivery, миграции, репозитории нужны для переносимости кода, для отчуждаемости кода от разработчика.

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

Ваше возмущение по поводу владельцев кода, это что то с чем то. Вас не возмущает что работу между сотрудниками делят по отделам? что каждая команда отвечает за свой функционал или фичу? нет? странно.
Сервис ориентированная архитектура не слышали? Каждый микро-сервис со своим стеком технологий? нет?
Владелец продукта?
У кода не может быть владельца? у Фичи?
Главное назначение миграции я вам привел.

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

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

Так как я подустал читать аргументацию «да вы не знаете что это такое» — подытожу. Все что вы сделали в этой статье — дык это уменьшили контроль за состоянием данных в бд и за версионностью в бд — просто потому что вам неудобно, да и фикстуры медленно накатываются. У меня был опыт разбора проектов с таким подходом — уверяю вас ничего хорошего там не происходит. Судя по обсуждению — вам это только предстоит. Предсказываю: будет как с бэкапами — ситуации когда они нужны возникают очень редко, но та ситуация когда они нужны а их нет — запомнится раз и на всю жизнь, и в вашем случае вы в дальнейшем будете вешать ограничения на все движется, а на все что не движется — двигать и вешать, и в откатах миграций будете использовать drop а не dropIfExists — мало ли.

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

в таблице migrations (не в вашем случае, а в обычном) хранится список миграций, которые уже применены к БД, а так же очередность их применения. Чем вам не состояние БД?

Всё что можно проверять на уровне БД надо проверять на уровне БД:
— это быстрее и производительнее
— на уровне БД гарантирует консистентность данных

Например, решили сделать поле position обязательным, на основе того, что оно обязательное написали какие-то сервисы.
Пишем миграцицию:
ALTER mytable MODIFY position VARCHAR(191) NOT NULL
Миграция может отвалиться, тогда мы поймём что у нас есть данные, которые не соответствуют нашим представлениям.
Ну и тут 2 варианта:
— написать UPDATE и по определённым правилам обновить данные
— написать
ALTER mytable
ADD CONSTRAINT position_not_null_check
CHECK (position NOT NULL AND created_at > '2020-02-19')

В любом случае выполнив SHOW CREATE TABLE, я увижу каким критериям соответствуют данные и смогу правильно написать код их обработки.

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

А в чем проблема работать в одной БД, но добавлять таблицам префиксы для каждой версии кода?

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

Кроме того, у нас сейчас работа ведётся одновременно в 30-ти ветках, то есть одной таблицы будет 30-ть копий, влитые ветки в мастер ни кто не удаляет, то есть у нас на текущий момент могло бы быть 1800 версий одной и той же таблицы.

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

Префикс таблиц задается в конфигурации приложения. Как часто у вас проиходят сбои конфигов подключения к БД?


Сложно администрировать такое хозяйство.

Установите регламент префиксов. Например, instanse_{ISSUE_ID}_. Написать скрипт, который дропнет таблицы по префиксу, посмотреть в сторону вебхуков, которые могут дергать этот скрипт при удалении ветки.


По-моему, это куда меньшая боль, недели всё описанное выше.

в этом проекте накатить схему с нуля с посевом занимает от часа.

Но ведь с представленным вами механизмом все миграции накатываются каждый раз заново (у вас же таблица миграций остается пустая)?

Есть у нас ветка драфт, что бы пушить в драфт не надо делать МР, эта ветка нужна для того что бы программист мог по быстрому показать свои наработки бизнес аналитику, что бы фронт-энд мог интегрироваться с изменениями на бэк-энде

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

Ок, предлагаю вам решение этих проблем при которых не придется применять ваши правила, останутся стантартные, всем понятные, миграции от ларавел и вышеобозначенных проблем не будет — git-flow + capistrano/deployer/ansible в общем все чтоб автоматизировать деплой
В git-flow создаете новую фичу, в ней работает бекендщик, есть миграции, так же делает свои правки фронтендщик

Если нужно продемонстрировать — деплоером раскатываете на драфте изменения из нужной ветки
нужно откатить — откатываете и свежие миграции вместе с переключением на старый релиз.
Если несколько модулей будут создавать одинаковые колонки/таблицы — миграции и должны падать т.к. это конфликт
Если нужно проверить что приложение все еще корректно работает с новыми колонками — пишите тесты, как на фронтенд так и на бекенд
Итого получается что когда все правки сделаны и проверены фича финишируется, в дев ветку попадают ее миграции и далее уже тесты покажут а все ли хорошо, после чего это уже попадет в релиз. На выходе в миграциях будет корректная история изменений версий, не придется вставлять костыли, патчить таблицу с примененными миграциями, оставлять кучу неиспользуемых колонок
git-flow из примера не обязательно должна быть одноименная утилита, а похожая модель ветвления

Добрый день,


У меня два вопроса:


  1. Зачем так странно доставать билдер когда есть фасад Schema?
  2. Что такое DataModel? Если это ваша реальная модель (Eloquent), то вполне логичный вопрос: зачем вы модели используете в миграциях. Модель вещь переменная, сначала вы добавили таблицу, а через три месяца удалили. В миграциях кож последовательный, таблица должна быть добавлена и потом быть удалена. И на момент когда вы с нуля катите миграции DataModel уже не будет. Или вы предлагаете рефачить 100500 миграция каждый раз когда удаляете таблицу и Model из проекта?
Sign up to leave a comment.

Articles