Версионный документ
Однa из проблем, которую постоянно решают разработчики информационно-учетных систем
- как разделить ввод данных и их актуализацию. Говоря человеческим языком, зачастую
требуется позволить пользователю вводить и многократно редактировать данные, чтобы
они до определенного момента не оказывали влияние на внутреннее состояние системы.
Этой цели служат, например, документы 1С, где документ сперва редактируется, а затем
проводится (возможно, другим лицом). Кроме того, иногда удобно иметь возможность
редактировать уже проведенный документ, а при сохранении изменений сперва отменить
актуальную версию документа, а потом применить (провести) отредактированную.
Паттерн версионный документ служит для решения именно этой постоянно возникающей
задачи, причем речь идет не о хронологической версионности, а об истории изменений.
Итак, что же представляет из себя версионный документ? С точки зрения пользователя
- это иерархическая структура: общая часть (она представлена строкой в
таблице версий документа) и одна или несколько табличных частей (принадлежащие
общей части наборы строк в одной или нескольких таблицах).
В начале редактировании документа создается временная версия, в которую копируются
табличные части из актуальной версии документа. При сохранении документа эта временная
версия объявляется актуальной для всего документа. Очевидно, что при таком подходе
документ могут легко одновременно редактировать несколько пользователей, не мешая
друг другу, и все их версии будут сохранены, только актуальной версией документа
в результате окажется версия того пользователя, который закончил редактирование
документа последним (он даже не узнает о том, что кто-то еще редактировал документ,
также как и тот, кто сохранил свои изменения раньше, может с удивлением узнать,
что они тут же были перекрыты более новой версией), однако ничья версия потеряна
не будет и, формально, можно восстановить любую (другое дело, что на практике этим
обычно не занимаются).
Естественно, что как только документ проведен, любые его изменения запрещаются.
В реализации это выглядит примерно так: на основе главной таблицы документа объявляется
бизнес-объект специального вида, имеющий методы:
- Create
- Start Edit
- Update Version
- Confirm Edit
- Cancel Edit
- Delete
- Load
- Commit
- Rollback
Роль табличных частей документа выполняют обычные
простые объекты, которым в качестве родительского объекта задан документ.
Тогда при генерировании хранимой процедуры создания новой версии для редактирования
генерируется и код, копирующий табличные части из актуальной версии в новую (а заодно
и код, удаляющий табличные части перед удалением ненужной версии при отказе от редактирования).
Естественно, что выполнение всех проверок и действий, осуществляемых при проведении
документа - это уже забота разработчика. Итак, версионные документ позволяет:
- Разделить редактирование сложной иерархической структуры данных и ее актуализацию
- Обеспечить сохранение истории редактирования документа
- Одновременно редактировать документ нескольким пользователям независимо друг от
друга
Вообще говоря, возможность конкурентного редактирования - это не самый полезный
побочный эффект, однако при наличии большого желания и яркой фантазии можно реализовать
слияняие изменений (которое merge), хотя проще блокировать документ при начале редактирования
(минус в том, что нужно следить за сбросом блокировки по прошествии некоторого времени,
если пользователь уснул). Кроме того, можно принцип "последний всегда прав" заменить
принципом "первый всегда прав" - запретить сохранение документа, если актуальная
версия документа отличается от той, которая была взята за основу в момент начачла
редактирования.