Нужна надежная мотивация офисных сотрудников...
Участвуйте в вебинарах по умным зарплатам и самостоятельно разработайте систему мотивации
сегодня 10930 Подписчиков
Шаблон "Медленное быстрее" (иллюстрация описания приёма формализации задачи в программировании)
(Приведён в качестве примера к данному обсуждению).
Если задача связана с быстродействием, и Вы имеете противоречие:
попробуйте использовать приёмы "Заранее" и "Наоборот". Ниже приведены примеры.
Здравствуйте! Как в Вашем примере обрабатываются ошибки? Например, если данные до сервера не дойдут, то эти данные, появившись было на клиенте, затем исчезнут. Что думать пользователю? Или он получит сообщение: такие-то данные пропали, введите их еще раз?
Уважаемый Максим,
Аналогичную задачу я решал при разработке приложений для операционной системы "Андроид".
Изменения сразу сохраняются на "Клиенте" (быстрая операция), а данные о произошедших, относительно исходного состояния изменениях, складываются в "буфер", содержимое которого затем отправляется на сервер.
Отправляя данные на сервер, приложение ожидает получить от него ответ об успешном завершении передачи данных. "Клиент" очистит "буфер" тогда и только тогда, когда он получит извещение об успешном завершении операции.
В случае, если такого ответа получено не было, "Клиент" считает, что синхронизация не произошла, и хранит данные до следующей попытки связаться с сервером. В тот момент, когда он получит отчет об успешном завершении синхронизации, он этот "буфер" очистит.
Сервер может не откликнуться в следующих случаях:
1. Соединение не было установлено.
2. Соединение было установлено, но данные не были переданы полностью.
3. Соединение было установлено, данные были переданы и обработаны, но разрыв произошел при передаче ответа.
В последних двух случаях "Клиент" будет действовать так, как, если бы соединение не было установлено в принципе, и отправит данные повторно. В сущности какие неприятности это может вызвать?
Если запрос на удаление данных прошел дважды, то удаление того, чего и так нет, не вызовет никаких проблем. Тоже самое и с запросом на обновление. Если мы дважды применим одинаковые изменения к записи, то, в итоге, мы получим именно ту запись которую хотели. А на случай повторного добавления в базе на сервере заведен отдельный признак, который позволяет определить, добавлять эту запись или нет.
С уважением, Александр Сычёв.
Спасибо, Aлександр! Ваше приложение однопользовательское? При многопользовательском режиме во время повторного изменения может обнаружиться, что объект уже заблокирован другим пользователем, после чего его изменение "задним числом" может оказаться недопустимым. Например, другой пользователь перевел объект на статус, на котором нет прав объект изменять ( заказ уже ушел на склад для отгрузки, а менеджер не успел поправить позицию, хотя у него на мониторе все верно).
Не верно ли, что прием "использование данных до их сохранения" применим лишь для однопользовательского режима Или только для чтения данных? При многопользовательском изменении объектов придется ждать ответ сервера оБ успешной блокировке объекта.
Здравствуйте, Максим!
В моем примере речь идет о системе коллективной работы Asana (хотя аналогичный подход применяется и в других системах). В случае, если обновление данных на сервере не удалось, пользователь получает сообщение об этом, после чего система считает свой долг выполненным.
Большая часть операций в системе связана с добавлением в нее данных - задач, комментариев, файлов. Одновременно это наиболее "тяжелые" операции, т.к. они связаны с записью в БД. При этом данные операции не являются критичными и не могут нарушить целостность системы - в худшем случае, пользователь будет вынужден заново написать тот же комментарий, хотя обычно он сохраняется в локальном буфере и заново послать его можно одним кликом.
Есть несколько моментов, которые делают описанный подход успешным:
Уважаемый Максим,
Моё приложение является многопользовательским, но решение с буфером (в данном частном случае) не создает описываемых проблем. В дополнение к тому, о чём написал Дмитрий Гончаренко,
За счет того, что соединение с сервером держится постоянно, каждая такая операция занимает секунды - т.е. не очень долго - и информацию о неудавшейся записи пользователь получает очень быстро, не успев выйти за контекст событий (обычно он все еще находится на той же странице). Это облегчает ему повторную отправку в случае случайной неудачи и одновременно предостерегает его от накопления большого количества действий в локальном буфере - психологически некомфортно добавлять записи если видишь, что они не попадают на сервер.
хочу добавить, что в моём приложении именно этот эффект и наблюдается: действительно, порции отправляемых из каждого "буфера" в конкретный момент времени изменений малы, отправка изменений занимает секунды, so даже, когда изменения на сервер отправляются одновременно от множества Пользователей, коллизий не возникает. Хотя коллизии вероятны, но, всё же, "одновременность" с точностью до доли секунды, событие очень редкое. Но даже, если бы такая накладка произошла (или произошло иное неучтённое событие), то соответствующее противоречие решается версионностью произошедших изменений.
Тем не менее, если абстрагироваться от этого приложения и попробовать ответить на общий вопрос о границах применения приёма, то, да, можно смоделировать ситуацию, когда соответствующие коллизии очень вероятны. Например, когда множество Пользователей работает с большим объемом одних и тех же данных и интервалы времени, требуемые для передачи соответствующих изменений велики (занимают не секунды, а минуты для отправки даже маленькой порции данных).
Предположим, десятка три (или больше, чтобы повысить вероятность обращения к одним и тем же данным) торговых точек резервируют товары из общего единого складского сервиса, но они не обращаются к серверу сразу, а работают, как описано здесь (через буфер с отправкой изменений с небольшим сдвигом по времени). Но почему-то время доставки этих изменений на сервер и записи их очень велико (я не знаю, почему, моделирую). Например, занимает не секунды, а минуты.
В таком модельном случае, при частом одновременном резервировании одних и тех же номенклатурных позиций разными многочисленными Пользователями, вполне вероятна ситуация, когда данные "на Клиентах" почти постоянно не будут совпадать с данными на сервере. И - соответственно - очень часто будут отправляться запросы, которые сервер будет отклонять - так, что, в предельном итоге, "никто ничего не допросится", хотя товар на складе есть. И версионность нам тут тоже не поможет, поскольку мы никак не можем иметь несколько версий фактического объема товара на складе.
Я бы сказал, что применимость приёма обратно пропорциональна числу определяемому произведением количества Пользователей (одновременно работающих с одними и теми же данными) на время обработки изменений этих данных. Всё же, в очень большом числе случаев это произведение невелико. Поэтому приём имеет довольно широкий сегмент применения.
Каждый приём имеет границы применимости, в корневой ветке же обсуждения содержался вопрос о том, как формализовывать опыт. Соответственно, один из шаблонов описания приведён. Приём описанный здесь (по данному шаблону) не единственный. У разработчика должна быть большая картотека приёмов и алгоритм их выбора (в идеале).
Спасибо за Ваши вопросы,