Как стать автором
Обновить
26
2.4

Пользователь

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

Если уж мы айтишники, то попробую привести такой пример: это как по мере развития проекта небольшие по отдельности технические долги в итоге делают сопровождение и внедрение новых фич все труднее и затратнее, пока однажды затраты на проект не становятся больше прибыли, которую он приносит. При этом вы не можете сказать, какой конкретно костыль или кусок технического долга стал началом конца — только какой стал последним гвоздем в крышку гроба проекта. Количество перешло в качество. Проект загнил и развалился.
Ну так в статье и сказано, что бессмертие клетки — это следствие поломки в ней тех механизмов, которые не дают ей стать раковой. Это две стороны одной медали: хочешь получить клеточное бессмертие — получишь раковые клетки. Не хочешь, чтобы появился рак — получишь неизбежное старение (и, возможно, опять рак вместе с ним). Порадуемся за клетки HeLa, но их обладательница давным-давно мертва.
Если несколько филиалов пользуются общим справочником данных (в вашем примере это список моделей), то пусть либо пользуются общей базой данных (с шардингом заявок по филиалам, например), либо пусть филиалы получают этот справочник от головного офиса, через API — в real-time или же, в целях ускорения, с периодической синхронизацией (например, раз в сутки). Плюс, конечно же, очень желательно предусмотреть случаи, когда данные начинают рассогласовываться по вине той или другой стороны:
  • записи о моделях в базе данных головного офиса не должны удаляться, а только помечаться как удаленные — это общий сценарий для сохранения согласованности данных в связанных справочниках; такие записи пропадают из всех списков, но в случае объединения они обеспечивают корректную работу с устаревшими записями из региональных филиалов (в вашем примере — когда из региона придет заявка с моделью «ТАЗ-2107», а в БД головного офиса ее уже пометили как удаленную)
  • если регион может прислать неизвестную для головного офиса модель — приложение головного офиса должно уметь обработать эту ситуацию: записать заявку как «Неизвестная модель» и отправить модератору, или добавить новую модель в свой справочник, или еще что-то — зависит от бизнес-процесса, вопрос не в плоскости программирования;
  • если у регионов есть возможность добавлять свои модели, то эти модели должны попадать в общий справочник головного офиса;
  • возможно, головной офис просто должен быть умнее всех регионов и обеспечить распознавание нескольких разных моделей как одной и той же (регион А вводит «ТАЗ-2107», регион Б — «ВАЗ-7», а головной офис все их приводит к «ВАЗ-2107»)
  • прекратить порочную практику копания в базах данных напрямую (через какой-нибудь phpMyAdmin, mongo-shell и т.п.), т.е. когда данные изменяются мимо бизнес-логики, правил валидации и т.п. (например, когда кто-то в регионе берет и вручную правит название модели в локальной БД, а потом в головном офисе заявки не импортируются, потому что неизвестная модель)

Да, это много дополнительной работы по проектированию и кодингу, но в распределенных системах без этого не обойтись. А паттерн «shared database», на мой взгляд, — это такая фальшивая децентрализация: вроде бы приложения разные и даже лежат на разных серверах (почти микросервисы!), но раз база данных у них общая, то если с ней что-то случится — ломается абсолютно все.
Да, возможно. Но если каким-то из view начнут пользоваться более одного приложения, проблемы будут те же самые: нельзя лишний раз трогать ни view, ни код.
Можете подробнее описать, из-за чего появляются портянки неконсистентных данных? И как именно происходит синхронизация баз данных — мимо соответствующих приложений и их бизнес-логики, напрямую, как при репликации? В примере из статьи единственное, что связывает две базы данных — это идентификатор автомобиля. Вся остальная информация в базах данных приложений А и Б — разная: у приложения А это данные о ремонтах, механике, поломках и т.п. У приложения Б — заявки на ремонт. Соответственно, не очень понял, как может возникнуть портянка из неконсистентных записей.
В случае, когда нужно сохранить обратную совместимость API, можно просто добавить версионирование этого API: вот у нас старая версия, в ней поле называется surname, а вот более новая версия, в ней поле называется last_name. А как оно там хранится в БД, нам вообще не важно. А вот если база данных используется совместно (то есть приложений, которые лезут в нее напрямую, больше одного), такое версионирование не сделаешь (ну, кроме костыля с двумя полями).
Если говорить о единой БД, которую трудно изменить… Если уж возникла необходимость иметь несколько приложений, каждое из которых хранит данные в собственной БД, то частичная несогласованность данных — это норма. Данные в этих БД синхронизируются не напрямую, а через соответствующие приложения, с использованием event-driven архитектуры и бизнес-логики в коде соответствующих приложений. Пример, описанный в статье: в базу данных приложения Б добавляется новая запись — требуется ремонт автомобиля с номером «А001ВЕ» модели «ВАЗ-2107». Приложение Б испускает событие «новая заявка на ремонт», на которое подписано приложение А (через какой-нибудь брокер событий). В приложении А реакция на это событие — завести в своей БД новую карточку на автомобиль с таким идентификатором и моделью или повторно открыть уже существующую (если ремонт данного авто уже производился). По завершению технических работ по автомобилю приложение А испускает другое событие, на которое подписано приложение Б. В приложении Б реакция на это событие — закрыть соответствующую заявку по ремонту. Очень схематично, но в чем проблема такого подхода? Это ведь не две копии одной и той же БД у разных приложений, которые как-то синхронизируются в фоне или ночами, минуя бизнес-логику, это две разные БД, каждая со своей структурой, наполняемые и изменяемые только своими приложениями.
Видел подобный кейс, там в описанном сценарии (общая база данных на несколько независимо разрабатываемых приложений) изменения типа «а давайте переименуем вот этот столбец, а то имя неудачное» просто перестали происходить: во-первых, любое такое изменение роняет все остальные приложения; во-вторых, объем работы по переименованию соответствующего поля в коде, помноженный на количество приложений, где это необходимо сделать, да плюс требование выкатить все эти правки быстро, синхронно и без ошибок… нет, давайте просто оставим все как есть. Просто опишем подробно в документации, что в поле с именем «номер автомобиля» на самом деле хранится номер двигателя; впрочем, это и так все в компании знают… В результате структура базы данных стала открыта для расширения, но закрыта для изменения: можно расширять существующие поля и добавлять новые, но нельзя ничего удалять, переименовывать и изменять.
Получается, что программисты не очень сильно разбираются в предметной области, и поэтому вместо конкретной информационной системы, которая нужна заказчику, пишут некий универсальный абстрактный конструктор, с помощью которого заказчик сам создаст (а точнее, настроит) нужную конкретно ему систему: с необходимыми сущностями, полями, связями, операциями, правилами валидации и т.п. Так?
Предложенное вами решение работает при условии, что в программе есть отдельный слой бизнес-логики, — то есть объекты, которые представляют сущности из предметной области, а база данных используется лишь как хранилище этих объектов — причем хранилище со своей собственной структурой, не привязанной к структуре объектов предметной области. В этом подходе структура данных в БД и структура данных в предметной области разделены и могут меняться независимо друг от друга — надо только следить за правильностью конвертации одного в другое и обратно. Предметная область отдельно, хранилище отдельно, можно вносить изменения в них по отдельности.

Не буду говорить за энтерпрайз, но в Web-разработке очень многие информационные системы (не буду называть их веб-сайтами, потому что там бывает довольно сложная серверная логика) грешат тем, что в них модели данных из БД и модели предметной области — это одно и то же. Слоя бизнес-логики как такового нет, бизнес-логика размазана по коду модели и контроллера: в модели обычно правила валидации и описание структуры полей хранилища, в контроллере — извлечение нужной модели из хранилища, манипуляции с ней в зависимости от юзкейса, отдача данных клиенту и сохранение обратно в хранилище. Это де-факто стандартная практика, паттерн MVC. То есть объект извлекается из БД (в случае реляционной БД — с помощью какого-нибудь ORM-решения, в случае какого-нибудь MongoDB — напрямую из BSON) и затем используется «как есть» по всему программному коду, а затем, после необходимых изменений, сохраняется обратно в БД.

В этом случае нельзя просто так взять и поменять имя поля в объекте, потому что каждое поле модели напрямую проецируется в поле соответствующей записи в базе данных. Переименовали поле в модели? Получите ошибку, что в соответствующей таблице нет такого столбца. И наоборот, нельзя просто взять и переименовать поле в базе данных: посыпется с ошибками весь код, где используется значение соответствующего поля. База данных и код оказываются зацеплены. И хорошо еще, если код и БД полностью в вашем распоряжении — можно просто аккуратно изменить и то, и другое, и выкатить релиз с аккуратной миграцией. Но все особенно плохо, если такое приложение не одно, и команды разработки у приложений разные (как раз тот случай, что описан автором). В этом случае вам либо придется идти по описанному в статье пути, либо добавить-таки в свою программу слой бизнес-логики, который позволит вам отвязаться от структуры полей, навязанной общей базой данных.
Не обязательно. Достаточно просто не отключать версию бэка, которая используется таким фронтом. От фронта требуется лишь сообщить, какая версия API ему нужна (или, если он не сообщает, автоматом выставить какую-то версию по умолчанию). Другое дело, что для маршрутизации на нужную версию бэка нужен какой-то промежуточный слой (сервер Nginx, например, или тот же BFF).
Если изменения бэка не ломают совместимость (интерфейсы API, структуры данных и смысл полей) — фронт менять не нужно. А если нужно, значит совместимость (контракт) ломается. Почему не использовать версионирование API для этого? Фактически это оно и есть, но реализовано оно в BFF. То есть это такой двусторонний мультиадаптер с дополнительными функциями (кэширование, валидация и т.п.), сильно зацепленный и на фронт, и на бэк.
Из-за чего вообще возникла насущная потребность в BFF? Команда, пишущая бэк, полностью оторвана от команды, пишущей фронт? Почему бэкэнд сразу не пишется так, чтобы фронтэндерам не было больно при интеграции? Где элементарные правила, которых должны придерживаться разработчики бэка и которыми можно сильно ударить по пальцам бэкэндера, который:
  • извращается с регистром полей в ответе (можно не любить конкретно underscored_case, например, но правила есть правила, единообразие важнее творческого самовыражения и личного мнения! в конце концов, командная работа же!);
  • извращается с форматом возвращаемого результата (массив, объект или null как результат ответа на один и тот же запрос, который возвращает список — серьезно? как такого на работу взяли?);
  • не пишет документацию по своим API (как минимум: имя, тип, текстовое описание каждого параметра запроса и поля в ответе + пример реального запроса и реального ответа на такой запрос).

То есть бэкэндеры у вас пишут как Б-г на душу положит, а фронтэндерам, чтобы как-то интегрировать в клиентскую часть это «творчество», приходится писать целую обертку (BFF), которая более или менее скрывает за собой всю убогость, несогласованность и противоречивость бэка? Я правильно понял?
Всегда было интересно, как организован контроль подобных технически сложных систем. По идее, концепции модульного, функционального и интеграционного тестирования программного обеспечения должны были прийти именно из мира сборки материальных систем подобного уровня сложности. Как просчитываются риски и их наихудшие последствия? Вроде такого: да, это просто болт, но если он упадет внутрь, его поиск обойдется в N миллионов долларов, а если замкнет какой-то контур — то и того больше. Как выглядят модульные и интеграционные тесты подсистем? Какие ошибки на каком уровне отлавливаются? Какая защита от неправильного использования закладывается в конструкцию компонентов? Каким образом при столь изощренном многоуровневом контроле становятся возможными столь «глупые» ошибки, как описанная в статье? (хрестоматийный пример — шайба, испортившая зеркало «Хаббла»).
Если не ошибаюсь, для образования двойной системы из ранее гравитационно не связанных тел необходимо наличие третьего тела. Если его нет, два тела просто пролетят мимо друг друга, изменив первоначальные орбиты.
Да, непосредственных наблюдений еще не было, все существующие свидетельства существования облака Оорта только косвенные. Но это пока единственная модель, которая хорошо объясняет всю совокупность наблюдаемых фактов и согласуется с результатами численного моделирования.
Стоит заменить в тексте «спланированные системы» и «живые системы» на «хрупкие системы» и «антихрупкие системы» соответственно, как словно читаешь «Антихрупкость» Нассима Талеба. Антихрупкость — способность не просто выдерживать перемены, а становиться лучше и сильнее благодаря им.
1) «Зачем мне вообще система версионного контроля, если я работаю над кодом один?»
2) «Зачем создавать ветки, если можно коммитить все в master?»
3) «Зачем настраивать деплой через Git, если есть FTP?»
это называется «неомания»: когда нечто объявляется лучшим просто потому, что оно самое новое, самое свежее, самой последней версии

Информация

В рейтинге
1 278-й
Зарегистрирован
Активность