Комментарии 69
процесс покупки должен быть тотальным (завершиться при любых входных данных с ожидаемым результатом за конечное время)
пользователь должен оказаться в одном из двух возможных состояний: либо с товаром и меньшим количеством денег на балансе, либо без товара но с той же суммой, что у него была до начала этой возни
магазин должен оказаться в одном из двух возможных состояний: либо без товара и бо́льшим количеством денег на балансе, либо с товаром и с той же суммой, что у него была до начала этой возни
По сути произошел Event Storming (на мой взгляд). Сейчас углубляюсь в эту тематику (bounded context, domain, coupling & etc), очень нравится и верю что в этом есть смысл)
Event Storming
Ох, и минуты не проходит, чтобы кто-то не переназвал какую-нибудь штуку, которой триста лет в обед, — новым модным словом.
Я просто бизнес-требования перечислил :) Думая, как нормальный человек, а не как программист. Если это теперь принято называть EventStorming — то в моё время это было принято называть просто Постановка задачи.
:)
Вот это самомнение!
Упомянуты какие-то крайние абстрактные случаи без единого примера.
Без них создается устойчивое впечатление что автор получил психологическую травму и действительно не умеет работать с базой.
Наличие в этом уравнении сущности «сеть» — сразу ломает все гарантии, потому что не существует способа синхронизировать состояние в базе там и в приложении здесь.
А должен быть? Как это связано с транзакциями?
Если нужно приостановить параллельные изменения в базе пока приложение обрабатывает загруженное состояние, для этого используются мьютексы. Внутри транзакции можно использовать FOR UPDATE.
Если в этот момент просто отловить ошибку и попытаться транзакцию повторить (что, смею предположить, делает примерно 90% всего клиентского кода в мире)
Не знаю, как в других языках, но в веб-проектах на PHP такое встречается крайне редко. База недоступна, процесс пишет в лог и падает с исключением. Fail-fast и всё такое. Я такое встречал только пару раз в фоновых консольных командах, которые обрабатывают много записей, чтобы переподключиться заново.
мы стартуем транзакцию из приложения, и тут отваливается сеть
транзакция будет применена неизвестное количество раз в диапазоне
Что значит "применена"? Если коммита не было, то изменения не записаны.
Если с точки зрения приложения база недоступна, то оно должно считать подключение недействительным и переподключиться, а не пытаться отправлять данные в тот же сокет. Тогда для базы это будет означать новую транзакцию, а не продолжение той же.
Я не могу триста раз повторять то, что написано в тексте выше и то, что я вам уже триста раз написал там и тут в комментариях.
Вы не пытаетесь понять, о чем идет речь, вы вспоминаете, что у вас в руке молоток, и начинаете играть в крота.
Как это связано с транзакциями?
Транзакция в общем случае не обеспечивает никаких гарантий. Об этом текст.
Внутри транзакции можно использовать FOR UPDATE.
Вы бы хоть по ссылке сходили, которую я в текст добавил, про то, как там с гарантиями консистентности в постгресе и к чему приводят форапдейты в сериалайзд изолэйшн левеле.
База недоступна […]
База доступна в момент обращения к ней, а потом соединение рвётся. В тексте это очень внятно написано.
для базы это будет означать новую транзакцию
Разумеется. И списание средств произойдёт пять раз, или сколько раз вы там жобу повторяете.
Вы не пытаетесь понять, о чем идет речь
Вот именно что пытаюсь. Я вам задавал много вопросов, чтобы понять, как у вас это организовано, вы на них не отвечаете. А мысли читать я не умею.
Hidden text
https://habr.com/ru/articles/910210/#comment_28318262
"потом сервер с этим процессом отключился, потому что в нем сломался жесткий диск, и что дальше?"
https://habr.com/ru/articles/876742/comments/#comment_28036226
"Как ваш гринтред будет подхватывать данные из персистентного хранилища (которое не база) после перезапуска на другом сервере в случае падения или деплоя новой версии кода, и получать по нему и данным из базы актуальное значения остатка для записи в переменую?"
https://habr.com/ru/articles/910210/comments/#comment_28320786
"Я легко мог бы и тут показать, как такие задачи решаются без реляций, но сегодня воскресенье, а подаю я только по пятницам."
Вы бы хоть по ссылке сходили, которую я в текст добавил
Понятия не имею, что вам не понравилось в документации, там все стандартно написано. А мысли, как я уже сказал, я читать не умею. Предлагаю вам перестать говорить загадками и цитировать то, что вы имеете в виду.
И независимо от того, что вы считаете проблемами с консистентностью, для приостановки параллельных изменений все равно можно использовать FOR UPDATE, он для этого и сделан. Поэтому я так и написал.
И списание средств произойдёт сколько раз вы там жобу повторяете.
С чего оно произойдет, если первая транзакция не закоммичена? Через некоторое время она откатится по таймауту.
База доступна в момент обращения к ней, а потом соединение рвётся. В тексте это очень внятно написано.
Я предполагал, что в моем тексте это тоже достаточно внятно написано, но ок, поясню подробнее.
База доступна в момент обращения к ней, а потом соединение рвётся. Если приложение узнало, что "вызов падает по таймауту", то с точки зрения приложения это означает, что база недоступна. Драйвер БД в этой ситуации обычно генерирует что-то вроде ConnectionTimeoutException. Если приложение зачем-то хочет повторить операцию, оно должно поймать его и открыть новое подключение.
Да, если это произошло во время отправки "COMMIT", решение тоже есть, и даже писать код не надо, потому что он должен быть написан в любом случае.
Hidden text
Проверка поля status после получения лока и перед вызовом логики.
Я знаю, как правильно реализовать этот сценарий с базой
Распределенная транзакция
Eventual consistency и задача в поставленной формулировке не решается принципиально
То есть будет потенциально бесконечный ряд уточнений как там в кошельке, как там на прилавке. С быстро растущей вероятностью выполнения условий, но никогда не 100%
Кстати, куда потерялось условие И?
Магазин продал И покупатель купил?
Вижу тут только по отдельности:
Магазин продал. То есть отдал товар и получил деньги
Покупатель купил. То есть отдал деньги и получил товар.
А товар физически один и это посильнее всех этих ваших программ. В общем, проблема в том что процесс покупки не чистый, а взаимодействует с контекстом, который может товар сломать, а деньги украсть
А если магазин отвечает только за свой инвариант, а покупатель только за свой, то возможен случай когда покупатель скажет что товар не получил, верните деньги, а магазин скажет что деньги не получил и товар не отдаст
Сначала нам говорят: делить на ноль нельзя. А потом оказывается, что ещё в XVII веке один маркиз по имени Гийом Франсуа Лопиталь научился.
Делить на ноль действительно нельзя, а операции с пределами - это операции с пределами. Дальше поток мысли читать не стал.
На самом деле возможность делить на ноль зависит от ситуации. Точнее от того, как мы определим операцию деления на некотором множестве.
В стандартной арифметике и подавляющем большинстве других разделов математики результат деления на ноль просто не определен. Как говорится, хоть обделитесь, а результата все равно не будет.
Но в некоторых случаях в качестве результата автоматически берется некое искусственное значение - бесконечность.
А в C++ деление числа с плавающей точкой на ноль даст вполне определенный результат - NaN.
А в C++ деление числа с плавающей точкой на ноль даст вполне определенный результат - NaN.
Только если std::numeric_limits<T>::is_iec559 == true
А бесконечность как будем определять? Как какое-то очень большое число? Или какое-то очень маленькое?
Да, я согласен, что мы можем "изобрести" свою математику со своими операциями. Но автор уверяет, что "в школе врут", это еще герцог доказал. На этом утверждении он строит обоснование актуальности своей статьи.
На этом утверждении он строит обоснование актуальности своей статьи.
Чё? Вы идиот?
А бесконечность как будем определять?
Есть такая штука, как "колесо", где бесконечность - это особое значение. Вот на этом колесе и смогли определить результат деления на ноль.Но там деление и даже сложение с вычитанием ведут себя весьма непривычно.
"в школе врут"
В школе таки не врут. В школе просто не вводят лишнего, ибо ни в одном из разделов математики, изучаемых в школах, результат деления на нуль не определен.
Можно, конечно, докопаться до тонкостей смысла слова "нельзя", т.е. "делить можно, результата не будет", но сути это не меняет.
Дальше поток мысли читать не стал.
Спасибо!
Посмотрел - у автора все статьи довольно эмоциональные, интересный подход. Может и правда, так до кого-то лучше доходит и заставляет задуматься о привычных вещах; плюсую, как говорится.
При этом, если решать эту задачу изначально в предположении, что никаких гарантий нет, на асинхронных сообщениях, то всё получится изящно и довольно бесхитростно.
Не, не получится. Я вам буду оппонировать книжкой Мартина Клеппмана "Высоконагруженные приложения" (она довольно увесистая и ей удобно оппонировать) - не получится. Будет тяжело, долго, дорого и всё время придётся думать, чем бы пожертвовать.
Да оперируйте хоть Брокгаузом, то, что кто-то не осилил — так себе аргумент.
Ой, у вас логика отклеилась; "кто-то не осилил" - это argumentum ad hominem circumstantiae (да, из "Википедии" скопировал :), логическая уловка, предположительно означающая, что конструктивных аргументов у вас [пока] нет.
Вот если бы вы взяли какой-нибудь, как сейчас говорят, "кейс" из Клеппмана, который он позиционирует как тяжёлый и показали изящный метод решения...
Ради бога, давайте хоть самый сложный кейс оттуда, я про этот талмуд (как и про его автора) впервые слышу, а платить деньгами и временем за нехудожественную литературу не готов.
А это уже "бритва Хитченса" - вы смещаете бремя доказательства своего первоначального тезиса ("всё получится изящно и довольно бесхитростно") на оппонента, предлагая мне дистиллировать сорокастраничный кейс с картинками и стишками в удобоваримую для нашей дискуссии форму.
А книжка, кстати, хорошая. Если у вас что-то распределённое и асинхронное, то прямо "маст хэв". Она же "книга с кабанчиком", погуглите, если интересно.
Да вы издеваетесь, что ли? У меня в открытом доступе куча решений, почти десяток библиотек, активно используемых сообществом, работодатель тоже, наверное, мне не просто так деньги платит — и я куда-то смещаю бремя доказательства. Какого еще нахрен доказательства? Доказательства чего? Вам с Клеппманом не надо? — Ну и отлично, проходите мимо, не задерживайте очередь.
Зачем я стану читать книгу, про которую (если вы верно передали суть) я просто из опыта знаю, что она либо поверхностна, либо просто неверна? Чтобы что? Вы бы стали читать книгу, в которой вам бы рассказывали, что Станислав Лем — негодный писатель, которого невозможно читать?
Кстати, ad hominem — в данном случае (выше) был бы с натяжкой применим, если бы вы привели пример из книги, а я бы сказал, что автор дурак. Вместо этого вы использовали ad vericundiam¹, апелляцию к авторитету, а я сказал — что это так себе аргумент. Да и авторитет так себе, если честно.
———
¹ Я ничего не гуглил и не копировал, на таком уровне «латынь» знают все более-менее образованные люди.
Да, всё верно, Клеппман – авторитет в области разработки распределённых высоконагруженных приложений, и для нашей дискуссии было бы полезно выбрать его (или другую соизмеримую величину) в качестве точки отсчёта, относительно которой мы могли, так сказать, перетягивать канат. Только в данном случае апелляция к авторитету – не увёртка, а довод.
Ну вот, вы повторно используете демагогический приём апелляции к личности, возвеличивая себя и тем самым принижая собеседника; мол, у меня и библиотеки, и зарплата, и латынь – имеет ли в подобных обстоятельствах мой оппонент право голоса? С вашей манерой использования ограниченного арсенала аргументов, перпендикулярных обсуждаемой теме, мы ожидаемо начали ходить по кругу, так что я, пожалуй, покину эту дискуссию.
Но напоследок сформулирую суть своего тезиса – возможно, найдутся дискутанты, способные подхватить клавиатуру, выпавшую из ослабевших рук – в вашей статье между утверждениями "общепринятые подходы не работают" и "лично у меня есть подходы, которые работают" есть огромная смысловая лакуна, но вы, вместо того, чтобы её заполнить, тем самым многократно повысив ценность материала, почему-то защищаете эту дыру с таким жаром, как будто в ней прячутся все выжившие дети и женщины Асгарда.
Тут типы не помогут
Тут вы, споря с виртуальным собеседником, приводите аргумент, что типы не всё решают. И делаете вывод, что они не спасают от багов. Это манипуляция.
Типы гарантируют, что в этой переменной может быть значение только такого типа. Не больше и не меньше.
И вот, наконец, мой любимый пример: транзакции в СУБД. Якобы они предоставляют гарантии консистентности.
Вообще ни разу. Транзакция даёт гарантию, что она либо выполнится целиком, либо не выполнится никак. Не больше и не меньше. Это инструмент, а обеспечить с помощью этого инструмента консистентность - это твоя задача, программист. Данные же твои. Схема данных твоя. Это ты определяешь, что является консистентностью, а что нет.
если полагаться только на базу и транзакции (и жобу, конечно)
Еще я знаю, что если опираться в этом решении на базу — решение получится либо не тотальным, либо неимоверно окостыленным.
Большинство, конечно, либо просто не подумает о крайних случаях
Давайте обсудим? Какие крайние случаи вы тут видите, как они решаются в вашем подходе?
Насколько я вижу, с базой нет особых проблем это сделать. Транзакции, мьютексы и поле state. Во всяком случае не больше, чем с другим подходом.
Тут миллиард случаев, которые (как я сказал) не приходят в голову, пока с ними не столкнешься. Еще я очень надеюсь, что слово «мьютекс» вы тут употребили случайно, потому что нет более верного сценария для дедлока, чем поженить транзакцию с мьютексом. «Поле стейт» — это вообще за гранью, конечно. Хотя бы из уважения к математикам называли бы его «статус».
Но если просите — пожалуйста. Возможнго, вам сначала придется понятрь, в чем именно проблема в этих разных случаях.
① продавец на вашем маркетплейсе торгует в тугриках, но цену на территории РФ, разумеется, выставляет в рублях, обновления цены присылаются через раббит, примерно раз в день; тут он по случаю купил подписку на обновление курса (раньше он руками ходит на блумберг) — и обновления стали приходить 1000 раз в секунду
② клиент обновил своё ПО и прислал обновление названий всех товаров в кодировке UTC2, потому что они так теперь хранятся у него
③ ваш маркетплейс решил сравнивать себя с конкурентами и подписался на их обновления
④ покупатель решил, что он умнее всех (как ни странно, это случай из жизни, если верить моему французскому приятелю), а зарплата у него завтра — поэтому он написал скрипт, который бронирует заказ, а потом тут же его отменяет, но перепутал секунды и миллисекунды.
Пока хватит, но 999 999 996 случаев у меня еще есть.
Да, правильнее было назвать status. Просто иногда называют state_id, вспомнилось, поэтому так написал.
Какие крайние случаи вы тут видите, как они решаются в вашем подходе?
Но если просите — пожалуйста.
Возможно, вам сначала придется понять, в чем именно проблема в этих разных случаях.
Ну то есть на вопрос вы не ответили. Просил я не то, что вы написали.
и обновления стали приходить 1000 раз в секунду
прислал обновление названий всех товаров в кодировке UTC2
и подписался на их обновления
но перепутал секунды и миллисекунды
С учетом общей информации в качестве ответа на мой вопрос о конкретике, могу ответить только "транзакции, мьютексы и поле state". Ну или status, если хотите. Но могу добавить, что ситуация "сотни параллельных обновлений" у нас была на практике, и прекрасно всё отработало.
Не могу сказать, что это крайние случаи, вполне стандартное ожидаемое поведение, особенно перед праздниками.
поженить транзакцию с мьютексом
Поскольку я предпочитаю вести дискуссию конструктивно, то напишу детали, как это работает.
В приложение приходит веб-запрос, в нем указан id сущности. Запрашивается лок на сочетание "название сущности + id" через Redis или advisory lock в базе. Лок должен быть на корень агрегата, а не на входящие в него сущности. Лок естественно имеет таймаут, поэтому никаких бесконечных дедлоков не возникает. После этого в приложение загружаются данные сущности. Не в транзакции, потому что логика может включать чтение с диска или сетевые запросы, и не стоит держать транзакцию всё это время открытой, а также чтобы не возиться с уровнями изоляции. Производятся необходимые бизнес-проверки, выполняется логика действия, запускается транзакция БД, сохраняются изменения (в режиме все или ни одного). После этого лок освобождается. При большой нагрузке на один ресурс (сущность) некоторые запросы могут получить ответ 429 "Попробуйте позже", и клиент должен повторить запрос. Многие сервисы умеют автоматически это делать. Там, где это не подходит, запросы складываются в очередь и обрабатываются позже. Прекрасно всё работает, изменения одной сущности происходят сериализовано, изменения разных сущностей параллельно.
Лок естественно имеет таймаут, поэтому никаких бесконечных дедлоков не возникает.
Простите, а вы точно знаете, что такое дедлок?
А что случится не в вашем мире розовых фей, а при атаке на определенный ID, например? (1000 разных запросов с одним и тем же ID сущности в секунду?)
А что будет, если редис отвалился?
Что будет, если при загрузке данных сущности — половина загрузилась, а потом сеть — тогось?
Производятся необходимые бизнес-проверки, выполняется логика действия […]
И вот тут-то соседний запрос и изменил эту сущность в базе до неузнаваемости. Что тогда?
Ну и
Просил я не то, что вы написали.
Бывает. Жизнь сурова.
Простите, а вы точно знаете, что такое дедлок?
Да. Подумайте, что означает первая часть слова, и сколько минимально сущностей в нем должно участвовать. Я говорю про одну сущность.
А что случится при атаке на определенный ID, например?
Я написал в предыдущем комментарии.
А что будет, если редис отвалился?
Internal server error в ответ на запрос. Я вам уже объяснял, что многим бизнесам не нужна ситуация, когда создание заказа происходит через 20 минут после запроса пользователя, когда редис поднимется.
Что будет, если при загрузке данных сущности — половина загрузилась, а потом сеть — тогось?
Предполагаю, что драйвер базы бросит исключение DataReadTimeout или что-то вроде того. Для точного ответа надо исходники драйвера смотреть. Почему это не надо предотвращать, см. предыдущий пункт.
И вот тут-то соседний запрос и изменил эту сущность в базе до неузнаваемости. Что тогда?
Простите, а вы точно знаете, что такое мьютекс?) Погуглите хотя бы, что означает название.
Соседний запрос (который веб) ничего в базу не отправляет, потому что запросил мьютекс на тот же id и ждет, пока он освободится.
Если же у вас одна часть приложения использует мьютексы, а другая нет, значит программист, который писал другую часть, не умеет работать с базой из приложения.
Бывает. Жизнь сурова.
Я в курсе, что глупых людей много, но предполагал, что вы не из них. И раз решили написать ответ, то будете отвечать на тот вопрос, который задан.
Просто для общего развития, термин deadlock в computer science означает вот это: https://en.wikipedia.org/wiki/Deadlock_(computer_science)
Простите, а вы точно знаете, что такое мьютекс?
Мьютекс в коде не может помешать изменить сущность в базе. Лок в базе — не может помешать изменить сущность в коде. Оба вместе — прямой путь к дедлоку.
предполагал, что вы не из них
Ну, это вы зря. Предполагать всегда надо самое худшее.
Просто для общего развития
Я вам уже сказал, что я знаю, что это такое. Что именно вам непонятно в этой фразе? Мои слова этому определению не противоречат.
В очередной раз предлагаю вам перестать говорить загадками. Есть что сказать, говорите прямо. Выглядит так, что вы боитесь оказаться неправы, хотя и говорите обратное. Поэтому уходите от ответа, используете умные слова и загадочные выражения, как гадалки с астрологами.
На всякий случай напомню, что термином "дедлок" называется ситуация, когда один процесс запрашивает локи в порядке (A, B), а другой в порядке (B, A), поэтому ждать освобождения локов они будут бесконечно. Когда оба процесса запрашивают только один лок, дедлока быть не может, просто по определению. Вот именно тому, которое вы привели.
Мьютекс в коде не может помешать изменить сущность в базе.
Может, если правильно его использовать, алгоритм я привел выше. Магии естественно не бывает, и надо для этого что-то сделать самому.
Ну то есть все-таки вы не умеете работать с базой из приложения, несмотря на весь ваш якобы большой опыт. Просто для общего развития - если в базу у вас может писать больше одного процесса приложения, вы должны в них использовать локи, иначе будет возможен race condition. Возможно вы предотвращаете его другими средствами, например не изменяете запись с одним id из разных процессов (подключений), но он возможен.
Оба вместе — прямой путь к дедлоку
Ну смотрите. В ваших представлениях это прямой путь. В реальности это не происходит. Значит ваши представления не соответствуют реальности. Предлагаю вам подумать, где именно.
Ну, это вы зря. Предполагать всегда надо самое худшее.
Нет. Такие случаи редки относительно общего количества людей, поэтому правильнее ожидать обратное. Иначе не получится общаться с другими людьми.
Вот в чем вы можете быть абсолютно уверены, так это в том, что я не боюсь показаться неправым в беседе с вами. Клянусь.
если в базу у вас может писать больше одного процесса приложения, вы должны в них использовать локи
Видите ли, это чушь. Я пишу в базу от сотен тысяч процессов, на языке, в котором нет такого примитива: лок. И ничё.
Этот текст (как все мои тексты, которые не касаются напрямую моих библиотек, которыми пользуются тысячи людей) — посвящены тому, что иногда имеет смысл покинуть башню из слоновой кости и оглядеться. Вы этого делать не желаете. Требуете от меня, чтобы я вам что-то объяснял и показывал.
Почитайте мои тексты про исходный код. Купите книжку, не знаю. Но я не нанимался вам что-то растолковывать.
я не боюсь показаться неправым
"хотя и говорите обратное"
Я пишу в базу от сотен тысяч процессов, на языке, в котором нет такого примитива: лок.
Такого примитива в большинстве языков нет, для этого используются отдельные библиотеки.
На всякий случай, под процессом я имел в виду код, который работает со своим подключением к БД, потому что из одного подключения запросы идут последовательно, и одновременных изменений одного ресурса быть не может. Ваш язык может и поддерживает сотни тысяч процессов, но вот базы данных типа PostgreSQL не поддерживают сотни тысяч одновременных подключений. Поэтому с точки зрения базы данных процессов у вас сильно меньше. Если вы используете одно подключение на все сотни тысяч процессов в контексте вашего языка, то в контексте моего утверждения и в контексте данной дискуссии у вас один процесс. Странно, что приходится объяснять такие банальные вещи.
И ничё.
Ну так многие и входные данные подставляют в SQL-запрос через sprintf, и ничё.
Мои тексты посвящены тому, что иногда имеет смысл покинуть башню из слоновой кости и оглядеться. Вы этого делать не желаете.
Требуете от меня, чтобы я вам что-то объяснял и показывал.
Я задаю вам вопросы по вашим текстам. Я желаю понять вашу точку зрения, но ваших текстах часто для этого недостаточно информации. По тому, что я понял, я вам объясняю, что уже огляделся, и то, что вы предлагаете мне не подходит. Это вы не желаете это понять.
В целом поддерживаю, однако вот это:
Простейший пример, с которым сталкивался лично я: мы стартуем транзакцию из приложения, и тут отваливается сеть. Вызов падает по таймауту. Если в этот момент просто отловить ошибку и попытаться транзакцию повторить (что, смею предположить, делает примерно 90% всего клиентского кода в мире) — транзакция будет применена неизвестное количество раз в диапазоне
[0, N+1)
— гдеN
— количество попыток повтора.
Говорит только о том, что ваша СУБД не поддерживает двухфазный коммит.
Или что моя клиентская библиотека (ORM) написана неаккуратно. Или что в данном случае разработчик забыл про двухфазный коммит, решил его конкретно тут не использовать, или еще по миллиону причин.
Если платёжный шлюз (который решает взять деньги или не брать) и отдел логистики (который решает отправлять заказ клиенту или нет) являются разными акторами, между которыми может пропасть связь (на произвольное время), то единственным решением, которое удовлетворяет условиям согласованности и конечности времени, является "никогда ничего не продавать", иначе (вне зависимо от конкретного протокола общения) необратимо порвав связь между ними можно получить неконсистентное положение (либо посылку товара без денег, либо получение денег без посылки товара). И это математическое утверждение, у которого есть доказательство, никаким простым способом это не обходится.
Обходится, конечно. Eventually.
Мы же требуем тотальность. Для Eventually Consistency есть требования, она "при любых входных данных" не наступает.
Мы требуем тотальность от функции покупки, очевидно, а не от окружающего мира.
Тогда что вкладывается в понятие "функция покупки", если она не от окружающего мира? От чего она?
В понятие «функция покупки» вкладывается следующий смысл: это функция, осуществляющая на машинном языке бизнес-операцию «покупка».
Сделать её тотальной не представляет никакой сложности.
Тотальную функцию сделать легко - просто ничего не делай (и тогда все ограничения выполнены - товар никогда не продан, деньги никогда не сняты).
Если мы хотим, чтобы она делала что-то более сложное, то нужно договориться о модели взаимодействия её с миром.
Какой у неё интерфейс?
Она взаимодействует с платёжным шлюзом и отделом логистики как с внешними агентами? Какие гарантии тогда требуются от этих агентов?
Она сама является и платёжным шлюзом, и отделом логистики?
Чего вы именно от меня хотите? Чтобы я рассказал, как строить консенсус? Как промышленность добивается отсутствия ситуации «необратимо порвав связь между ними»? Как работает акторная модель? Почему в CAP-теореме недостижимо только одно из трех, а не все три разом? Как такую задачу решает каждый конкретный маркетплейс?
Даже не так: что вы хотите донести до читателей? Если то, что я кругом неправ — не тужьтесь, я согласен, неправ, можете цитировать.
ожидание гарантий от какого-то стороннего кода — исключительно пагубная привычка
А ожидание гарантий от собственного кода хорошая?
что в IT нет и не может быть никаких гарантий
Может. Только вот это будет не тот IT, который Вы подразумеваете.
Таким комментариям самое место на форуме практикующих хиромантов. Либо рассказывайте, что у вас там за такой волшебный IT с гарантиями, либо нещщитово.
Можно сперва прочитать ответ об ожидании гарантий от собственного кода?
Доверие выше, чем к стороннему, гарантий по-прежнему никаких.
волшебный IT с гарантиями
Ничего волшебного в нём нет (разве что то, что привычное современное "as is" IT придётся выкинуть) - это давно известная формальная верификация. Она применима и к аппаратному, и к программному обеспечению. Постройте полностью формально верифицированную систему и будут Вам гарантии без привлечения хиромантов.
Смешно.
Агда, кок и лин — не позволят написать работоспособный код. Идрис не готов к продакшену. Полностью верифицировать можно только систему без сайд-эффектов.
Теоретиков вокруг вагон, мне бы поговорить с человеком, который сам пробовал, и у которого получилось.
Смешно
Для мира тотального "as is" иного и не ожидалось.
Агда, кок и лин — не позволят написать работоспособный код
Тогда как получилось хотя бы тут: https://habr.com/ru/articles/148769/ ?
Полностью верифицировать можно только систему без сайд-эффектов
Никто вроде и не обещал, что всё произойдёт по мановению волшебной палочки, без каких-либо усилий, включая изменение подходов к программированию.
как получилось хотя бы тут
Тут задача тривиальная, я это и на идрисе докажу, и даже банальным property-based тестированием. Расскажите, как на агде доказать консистентность оплаты и отгрузки товара.
Еще раз: теоретиков, умеющих решать тривиальные примеры — полно́, ценности от их потуг для индустрии — ровно ноль.
Добиться, чтобы при создании черновика документа он был сохранён в базе
Нас интересует не факт сохранения в базе, а появление возможности публикации.
Поэтому прикладной код должен предпринять определенные действия, если черновику была отдана команда сохраниться, а действие «публикация» — всё еще недоступно.
Бизнес в таких задачах обычно интерсует не действия вашего кода по показу ошибки "Публикация недоступна, попробуйте еще раз", а чтобы пользователь не терял данные в черновике, которые он редактировал полчаса. В числе прочего это означает, что если он нажал "Сохранить", а потом обновил страницу в браузере, то он должен увидеть свои изменения, а не так что они пропадают на полчаса, он начинает снова набирать, а потом они появляются. Или не появляются, потому что произошел деплой, и все несохраненные данные потерлись. Если вы это реализовали, то это и есть то, что бизнес понимает под словами "Сохранить черновик документа в базе", а уж готовую базу вы используете или самописный аналог, это ему неинтересно.
Отстаньте от меня со своим бизнесом, добром прошу. Вы настоящий бизнес никогда в глаза не видели.
Этому бизнесу надо, чтобы транзакция на 100 миллионов долларов прошла сейчас, а не через полсекунды. И много другого всякого, чему база мешает.
Вот это и есть то, что вы не желаете понять. Вашему бизнесу это надо. Моему бизнесу надо другое, и ваши подходы для этого не подходят. Я говорю про любой бизнес, а не только про тот, который вы считаете настоящим. Потому что другому бизнесу тоже нужны приложения.
Отстаньте от меня со своим бизнесом
Вы написали пример бизнес-требования, я написал свое мнение о нем. Здесь публичный форум, не нравятся комментарии, значит пишите на другой площадке, где их нет.
что на самом деле нет никаких гарантий
непонимание, что в IT нет и не может быть никаких гарантий
когда попытался рассказать
Это у вас есть непонимание, что все понимают, что в реальном физическом мире нет 100% гарантий, и любые гарантии инструментов работают только в предположении, что всё остальное работает нормально, и подразумевают сравнение ситуаций с инструментом и без. Все понимают, что в любой момент может прилететь метеорит и упасть на датацентр, и программные инструменты от этого не защитят.
Я пытался вам это объяснить, когда вы пытались рассказать, но видимо вы так и не поняли.
Опросите 10 синьёров бигтеха
скрывает внутреннюю кухню, не позволяя получить к ней доступ напрямую. Ха-ха-ха. Проект AspectJ
Cиньёры бигтеха понимают, что определенными функциями операционной системы можно записать любое значение по любому адресу пользовательского пространства, а шестнадцатиричным редактором любой машинный код в исполняемом файле.
И слово "гарантия" используют в относительном смысле, по сравнению с вариантом, когда некоторого инструмента нет, а не в абсолютном. В обоих вариантах (с инструментом и без) слово "гарантия" используется в предположении, что всё остальное работает без сбоев. То есть если вы меняете общий ресурс из разных процессов без мьютекса, то даже если всё остальное работает без сбоев, то у вас нет гарантий, что данные будут консистентные. А с мьютексом есть.
Странно, что приходится объяснять это человеку с опытом.
Если товар аннигилировал, а деньги пришли в результате сжигания квантово-связанной со счетом магазина банкноты в Зимбабве — всё хорошо.
Я вам это тоже в прошлый раз объяснял. Может быть для вашего бизнеса всё хорошо. А большинству бизнесов пропадание товаров обычно не нравится.
Вообще выглядит так, что вы тут имеете в виду что-то свое, что большинство и так использует и не задумывается. Ну там например когда приложение отправляет данные платежному провайдеру, а он потом вызывает специальный коллбэк в приложении со статусом прошла оплата или нет.
Но так как вы пояснения своих мыслей обычно не даете, несмотря на просьбы, то мы этого не узнаем.
любые гарантии инструментов работают только в предположении, что всё остальное работает нормально
Ну это уж совсем какой-то разврат.
На самом деле контракт подразумевает в числе прочего спецификацию, на какие ошибки окружения мы закладываемся.
Если у вас защищённая по военному классу ИБ система, то она должна предусматривать возможность попытки отредактировать исполняемый код в шестнадцатеричном редакторе.
Если у вас отказоустойчивая система для спутника, то она должна предусматривать возможность изменения битов в процессоре и памяти в результате действия космического излучения.
Если у вас банковская система, то она должна предусматривать возможность потери связи между процессинговым центром и банкоматом в момент расчёта.
Ну и т.д.
Но, вместе с тем, закладываться в бортовой программе спутника на действия хакера с HexEdit'ом нет смысла.
Ну это уж совсем какой-то разврат.
Вы в каждой функции пишете защиту от падения метеорита и космической радиации, которая случайным образом меняет биты в оперативной памяти?
На самом деле контракт подразумевает в числе прочего спецификацию, на какие ошибки окружения мы закладываемся.
Вы говорите про систему целиком, я говорю про конкретный инструмент, который решает некоторую задачу. Например "ООП", "мьютексы", "база данных", "транзакции", и другие, которые упомянуты в статье. Слово "гарантии" относительно функциональности этого инструмента не подразумевает то, что он магически будет вас защищать от любых способов обхода этих гарантий.
Я не даю пояснений, это правда. Я не учитель младших классов на ставке. Кто-то не понял? — Да насрать.
Когда гарантийный срок истёк