196

Идемпотентные операции в программировании

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

Пусть исходными данными будет число 5, а операцией будет "умножить на 2". В зависимости от количества n применений операции будем получать разный результат:

n = 0 -> 5
n = 1 -> 10
n = 2 -> 20 и так далее

Ничего удивительного. Но если возьмем операцию "умножить на 0" то результат будет следующий:

n = 0 -> 5
n = 1 -> 0
n = 2 -> 0 и так далее

Видно, что после n = 1 результат не меняется. Свойство операции давать одинаковый результат при однократном и многократном применении называется идемпотентностью. Получается, что операция "умножить на 0" идемпотентна, а "умножить на 2" нет.

Рассмотрим более близкую к бизнесу ситуацию. За баланс пользователя сотового оператора отвечает один сервис, а обработкой платежей занимается другой. Пользователь хочет пополнить телефон, деньги с карты уже списали, и осталось дождаться когда увеличится баланс. Нужно чтобы сервис баланса выполнил операцию "зачислить пользователю Васе 100р", а поручение на это дает сервис платежей:

Подача поручения и успешный ответ

Подача поручения и успешный ответ

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

  • в момент отправки поручения - тогда Вася не увидит свои 100р, будет писать в техподдержку

  • в момент доставки ответа - тогда пользователь увидит зачисление

Проблема в том, что сервис платежей не может достоверно понять, было обработано поручение или нет. Он видит только что не пришел положительный ответ. Сетевые проблемы исчезают так же быстро как появляются, и можно было бы попробовать отправить поручение еще раз (retry). Но что если в первый раз поручение таки было успешно обработано, и в случае ретрая баланс пользователя будет увеличен еще раз, в сумме на 200р?

Представим что операция увеличения баланса - идемпотентная. Тогда можно было бы ретраить подачу поручения множество раз (n >= 1), и в конечном счете получить успешный ответ. При этом повторные начисления будут исключены (так как результат операции для n > 1 такой же как для n = 1).

Чтобы операция пополнения баланса стала идемпотентной, нужно сначала предусмотреть возможность установить уникальность операции. Если Вася пополнял баланс на 100р дважды - вчера и сегодня - то такие операции должны интерпретироваться как разные. Получается, можно было бы различать операции по такому набору атрибутов: {имя пользователя, сумма, дата}. Еще лучше использовать синтетический идентификатор, например id операции списания с карты.

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

Если тема показалась интересной, и есть пожелания разобрать еще что-нибудь из бекенда, пишите их в комментарии. Всем удачных проектов!

Лига программистов

2.3K постов12K подписчика

Правила сообщества

- Будьте взаимовежливы, аргументируйте критику

- Приветствуются любые посты по тематике программирования

- Если ваш пост содержит ссылки на внешние ресурсы - он должен быть самодостаточным. Вариации на тему "далее читайте в моей телеге" будут удаляться из сообщества

Вы смотрите срез комментариев. Показать все
12
Автор поста оценил этот комментарий

Это даже не псевдо науч поп, а что то на уровень ниже. Операция умножения - идемпотентная. Сколько 5 на 2 не умножай, всё равно будет 10. Операция умножения принимает 2 аргумента, и делать вывод о её идемпотентности на основе разных результатов при разных аргументах - некорректно.

раскрыть ветку (10)
5
Автор поста оценил этот комментарий

Рассматривайте не операцию умножения (бинарную), а унарный оператор "умножить на два". Тогда всё будет отлично.

раскрыть ветку (3)
1
Автор поста оценил этот комментарий

А что это меняет? В унарном операторе "Умножить на 2" меняют аргумент и получают разные результаты (вот удивительно-то!)

раскрыть ветку (2)
2
Автор поста оценил этот комментарий

В случае из примера операция состоит из трёх команд: получить текущее значение переменной, использовать его как аргумент функции умножения, сохранить результат в эту же переменную.

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

Основное расхождение здесь в понимании, что считать результатом работы. Можно ли считать возвращаемое значение результатом работы, или обязательно должны быть эффекты вроде сохранения результата в память?

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Вот! Вот правильно.

Но тогда это не операция "Умножить на два")

1
Автор поста оценил этот комментарий
Держи плюсик))

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

А вот если мультипликатор будет браться например из базы, то она таковой уже не будет
credo in veritate
Автор поста оценил этот комментарий

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

раскрыть ветку (4)
2
Автор поста оценил этот комментарий

По Вашему суждению получается, что идемпотентных операций не может быть, что лишено смысла

раскрыть ветку (3)
credo in veritate
Автор поста оценил этот комментарий

Теорию вероятности знаете? Любая система имеет допустимый % ошибки и приемлемый уровень дублирования для принятой модели OSI. Т.о. индемпотентной операция будет после n-принятых подтвержденных операций и/или получившей валидный хеш операции. Вряд-ли скриптер сайтика будет перепроверять математические операции (привет джаваскрипт), а вот к чему может привести игнорирование на серьезных проектах - поинтересуйтесь из отчёта крушения Луны-25 ...

раскрыть ветку (2)
1
Автор поста оценил этот комментарий

Это всё понятно, сюда же можно вспомнить выборы в Бельгии в 2003 году. Это баги реализации. По определению операция умножения идемпотентна. Её реализации - да, могут быть разными.

раскрыть ветку (1)
0
credo in veritate
Автор поста оценил этот комментарий

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

Вы смотрите срез комментариев. Чтобы написать комментарий, перейдите к общему списку

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества