Здравствуйте,
занимаясь разработкой "клиентских" приложений для всяких Web 2.0 часто приходится писать компоненты-контроллеры (С в шаблоне MVC), которые выполняют последовательные, но асинхронные действия, и во время ожидая завершения асинхронной операции дергать их за методы, изменяющие их состояние не желательно (можно конечно, но это сильно усложняет компонент). Хорошей абстракцией для таких контроллеров является детерминированный конечный автомат, и в Драконе, с помощью силуэта, хорошо изображать диаграмму переходов такого автомата, правда с асинхронностью проблемы, но если сразу принять что все события асинхронны, то жить можно.
Одна проблема - если в автомате больше 5-7 состояний то его диаграмма превращается в этакую ленту (малая высота, большая ширина), с которой не удобно работать. Я проанализировал свои контроллеры и заметил что часто встречаются состояния, переход в которые происходит только из одного предшествующего состояния, по сути были бы переходы синхронными это было бы одно состояние. Такие состояния я называю "вспомогательными".
Например, в браузере достаточно сложно, иногда невозможно, сделать настоящий модальный диалог (если мы хотим чтобы приложение было одинаково совместимо со всеми браузерами), и допустим у нас выполняется некий асинхронный XHR (XmlHttpRequest) запрос к серверу, во время запроса, наш вид (V в MVC) мирно показывает индикатор выполнения запроса, и вдруг сервер "отвалился" (у пользователя кратковременно пропала связь с сетью), в таком случае контроллер, у меня, показывает модальное сообщение: "дескать нет соединения с сервером, не желает ли пользователь запрос повторить?". Пользователь в свою очередь может либо нажать кнопку "Повторить", либо "Отменить" операцию. При успешном завершении или отмене операции вид переключается в изначальное состояние, показывает какую нибудь форму ввода данных вместо индикатора выполнения запроса. Здесь - ожидание выполнения запроса сервером, и показывание предупреждения пользователю - два разных состояния контроллера. Пример диаграммы для контроллера формы сброса пароля пользователя дан ниже.
Вложение:
PasswordResetLinear.png [ 67.68 КБ | Просмотров: 12888 ]
Тут простым состоянием является (Prompting for retry).
Запрос на сброс пароля достаточно простой, сервер может вернуть 3 класса ответов:
- успех
- ошибка - сервер на обслуживании
- ошибка - любая другая (которая не факт что проявится при следующем запросе, запрос мог не пройти, сервер мог не успеть запрос обработать, словить исключение из-за недостатка памяти, и т.д., т.е. такая ошибка которая не зависит от данных переданных клиентом и может быть исправлена повторным запросом).
Проблемы начинаются когда бизнес логика достаточно сложная и сервер может возвращать ошибки с разными кодами, на каждый из которых надо как-то уведомлять пользователя. Например, при аутентификации пользователя, в приложении над которым я сейчас работаю, сервер может вернуть ошибки:
- неверные логин/пароль
- неверный пароль и осталось попыток N из M
- неверный пароль и пользователь заблокирован (и теперь должен пароль сбрасывать и восстанавливать)
- требуется ввести код доступа полученный по SMS
- требуется ввести код доступа со скрэтч-карты
- пользователь заблокирован администратором
- пользователь опознан, но он ещё не завершил процесс активации
- пользователь может аутентифицироваться только по SSO (через OpenID или SAML)
8 - вариантов, 8 - вспомогательных состояний, диаграмма переходов превращается в ленту (почти Мёбиуса), работать неудобно
Мое предложение - изображать такие вспомогательные состояния в той же ветке силуэта что и состояние из которого совершается переход во вспомогательное так, как показано ниже, см. ветку (Requesting):
Вложение:
PasswordResetPlanar1.png [ 77.09 КБ | Просмотров: 12888 ]
В таком случае диаграмма может принять вид более близкий к листу или области просмотра / редактирования редактора диаграмм.
Если присмотреться, то в диаграммах выше есть ещё одно вспомогательное состояние - (Prompting for email), если также вынести его предложенным способом, то получается вот такая диаграмма:
Вложение:
PasswordResetPlanar2.png [ 78.1 КБ | Просмотров: 12888 ]
Предложенным способом мы сохраняем асинхронную природу диаграммы и автомата, но прячем вспомогательные состояния на более низкий уровень, тем самым снижая уровень шума, привносимый ими в диаграмму, ну или просто более равномерно используем ограниченное горизонтальное и вертикальное пространство. Прошу высказываться
Спасибо.