ISSN 1992-6502 (P ri nt)_
2015. Т. 19, № 1 (67). С. 254-257
Ъыьмт QjrAQnQj
ISSN 2225-2789 (Online) http://journal.ugatu.ac.ru
004.415.2
Подход к проектированию обратимых операций
в программном обеспечении М. М. Гумеров
[email protected] ООО «МАСС МО»
Поступила в редакцию 13 ноября 2014 г.
Аннотация. Подвергается пересмотру и дополнению более ранняя работа автора о проектировании механизмов отмены выполняемых операций в программном обеспечении. Предлагается новый комплекс мер, позволяющий во многих случаях добиться аналогичного результата, но с меньшими жертвами в отношении читаемости кода и отхода от обычного стиля работы с объектами.
Ключевые слова: отмена операций; проектирование; объектно-реляционное отображение.
В своей диссертации [1] автор исследует некоторые вопросы проектирования механизмов отмены выполняемых операций в программном обеспечении. Поскольку комфортная работа с современными приложениями для редактирования каких-либо видов документов немыслима без возможности отмены ошибочных выполненных пользователем действий, а существующие опубликованные исследования обходили вниманием конкретную проблему, рассмотренную в диссертации, исследование в этом направлении было сочтено перспективным. Предлагаемый автором подход к проектированию включает использование неких идентификаторов для связывания тех объектов, в которые отображаются элементы документа в памяти работающего приложения.
Как показали позднейшие исследования автора, можно более точно выделить те свойства предложенного метода, которые позволяют решить проблему связей между объектами, и применять в проектировании именно их, не следуя этому методу полностью. В работе представлена система ограничений и правил проектирования, следование которой позволяет решить рассмотренную в [1] задачу несколько иным способом.
СУТЬ ЗАДАЧИ И РАННЕГО РЕШЕНИЯ
Автор предполагает, что объектно-ориентированная программа работает с содержимым документа не непосредственно, а через некоторое объектно-ориентированное представление -комплекс объектов в памяти. Элементы, из которых состоит документ, могут иметь связи друг с другом, а также на них могут ссылаться
другие объекты программы - например, хранящие информацию о проделанных операциях для обеспечения возможности отмены последних.
Суть проблемы - в следующем. Если элементы документа отображаются в объекты в оперативной памяти приложения, и связи между элементами отображаются в ссылки одних объектов на другие, и над каким-то элементом выполняется операция удаления, нужно каким-то образом удалить ссылки других объектов на соответствующий ему объект; аналогично при отмене операции удаления нужно установить этим объектам ссылки на восстановленный объект.
Например, какие-то объекты программы могут пожелать следить за изменением состояния других объектов, чтобы на эти изменения ответить собственными изменениями.
В диссертации [1] констатируется отсутствие опубликованных научных исследований обратимых операций. В то время как задача проектирования системы поддержки отмены абстрактных операций в приложениях рассматривается как научная в немалом числе исследований, причем уже в 2000-е годы ([2, 3] и даже, например, [4]), задачи проектирования отдельных типов таких операций с целью обеспечения их обратимости традиционно считаются инженерными, в результате чего всякий раз для всякой операции решаются заново ([5, 6]).
Автором же в [1] предпринята попытка проанализировать обобщенную задачу проектирования таких операций как научную, показана исключительность операции удаления элемента документа в приложениях-редакторах документов, и предложен был опять-таки обобщенный
подход к проектированию операций удаления в различных приложениях.
В качестве решения было предложено отказаться от таких ссылок. Предложено использование идентификации объектов не их положением в памяти (как работают указатели на объекты), а каким-либо другим ключом. Тем самым устраняется возможность того, что некий объект ссылается на другой, который в ходе работы удаляется, а затем восстанавливается (например, при отмене операции удаления), но уже в другом месте оперативной памяти.
Выбор такого решения опирается на ряд предположений.
1. Любой объект, на который делается ссылка, может быть уничтожен или перемещен в любой момент.
2. Состояние приложения включает в себя все содержимое обрабатываемого документа, отображенное на какие-то объекты (речь идет об объектах ООП).
В то же время, дальнейший проведенный автором анализ показывает, что эти предположения не являются чем-то неоспоримым. Рассмотрение возможностей некоторых существующих систем объектно-реляционного отображения (ORM), таких, как Hibernate, и, что важнее, практики их использования в разных проектах, и в том числе и в Web-приложениях, позволил прийти к выводу, что, во-первых, хранение документа целиком в памяти программы не всегда является хорошей идеей, во-вторых, отказ от этого приводит к тому, что многие элементы документа не присутствуют в памяти программы постоянно, а доступны лишь в какие-то моменты времени. Например, автору известны сценарии, в которых всякий раз, как программе требуется доступ к какому-то элементу документа, для этой части заново создается объект в памяти и заполняется содержимым этого элемента; известны и другие сценарии, когда единожды созданные объекты кэши-руются и могут использоваться повторно до тех пор, пока кэш не переполнится, что приведет к вытеснению из него части объектов.
Нетрудно видеть, что если всякий раз при необходимости доступа к неким данным для них создается новое объектное отображение в память, а в остальное время этих объектов в памяти нет - то в хранении информации о связях между элементами документа именно в оперативной памяти большую часть времени вообще нет необходимости. Вместо этого связи можно представлять в памяти каким-либо образом тоже именно в тот момент, когда соответствующие объекты отображаются в память.
Что до первого предположения, оно тоже не вполне верно. Так, скорее всего, объекты удаляются в процессе выполнения конкретных операций. Если некая операция не связана с удалением элементов документа, то вполне возможно ввести контракт, по которому в ходе этой операции никакие объекты не удаляются. А значит, как минимум, можно выделить некоторые периоды в работе программы, когда нет опасности удаления объектов, что снимает необходимость отказа от указателей в эти периоды.
ПРЕДЛАГАЕМЫЙ ПОДХОД
Новый подход к решению можно сформулировать так: ссылки между объектами можно по-прежнему представлять в виде классических указателей, но при этом всегда следует понимать, что полученная ссылка указывает на объект, который затем может быть уничтожен. Но тогда нужно дать более четкое определение понятию «затем», иначе это правило не лучше неопределенности. Предлагается такое: поскольку история изменений документа состоит из отдельных операций над ним, можно принять, что объекты гарантированно существуют до конца операции, но после окончания операции могут быть удалены и, возможно, заново прочитаны из БД уже в другой участок памяти. А могут и остаться в кэше и использоваться повторно. Схематично предлагаемый жизненный цикл ссылок на объекты в контексте последовательного изменения состояния последних представлен на рисунке, где элемент «экземпляр X в состоянии Y» показывает, что подпрограмма, к которой элемент отнесен на схеме, хранит ссылку на такой экземпляр.
Возможность ссылаться на объекты в ходе выполнения каких-то операций позволяет, например, без дополнительных ухищрений реализовать классическую для .Net привязку (binding) отдельных элементов управления из пользовательского интерфейса конкретной операции к каким-то свойствам объектов, которыми она оперирует. Конечно, можно сделать такое и с использованием ключей вместо указателей, но это означало бы дополнительное усложнение исходного кода. А при использовании указателей возможен такой способы подписки на события, который обычен для данного языка (например, механизм событий .Net Framework).
Например, имеется объект, с которым в связи «многие к одному» состоят несколько дочерних объектов; пользовательский интерфейс для некой операции редактирования предоставляет возможность добавить дочерний объект или из-
256
ИНФОРМАТИКА, ВЫЧИСЛИТЕЛЬНАЯ ТЕХНИКА И УПРАВЛЕНИЕ
менить свойства родительского. При этом среди свойств родительского объекта и дочерних есть такое, как «цвет». Если задать «цвет» родительского объекта, изменяется цвет всех дочерних; если задать «цвет» дочернего, отличный от цвета остальных, «цвет» родительского делается «неопределенным». Один из способов организовать такой интерфейс - подписаться к каждому из объектов на уведомления об изменении его свойств. Если свойства объектов отображаются в каких-то элементах управления, эти элементы тоже нужно обновить. В .NET Windows Forms связать элементы с данными можно при помощи Data Binging, и делать это удобно, имея возможность ссылаться на объекты при помощи обычных ссылок .Net.
Сопутствующая проблема - отслеживание изменений объектов - в этом случае также нуждается в анализе. Здесь помогает тот факт, что каждая операция подвергает изменениям определенный известный ей перечень объектов. Но тем не менее, ведь сама операция не знает логику, по которой одни объекты зависят от других. Поэтому, если для зависящих элементов документа не созданы объекты, вызов какой-то обработки при таких событиях становится проблемой, которую также следует решать. Тем не менее, в первом приближении будем считать,
что элементы в документе связаны просто для отражения каких-то структурных связей, а не для того, чтобы каскадировать (to cascade) изменения одних элементов на какие-то другие. В тех же случаях, когда этого недостаточно, можно, хотя это, вероятно, и не лучшие варианты, либо возложить запуск такой обработки на реализацию документа, либо на саму выполняемую операцию.
Если же почему-то есть необходимость иметь ссылку на элемент документа, которая переживет рамки одной операции, тогда уже следует ссылаться по ключу.
Следующий шаг заключается в осознании того, что между операциями приложение не простаивает - просто оно работает в read-only режиме. Могут переключаться режимы просмотра, изменяться просматриваемая область документа, обновляться содержимое каких-то представлений. Это означает, что между операциями возможно также выполнение кода, который будет запрашивать фрагменты документа и оперировать соответствующими объектами. И во многих случаях здесь кэширование уже созданных объектов (или результатов какой-то их обработки) просто необходимо.
Но, в общем-то, ничего не мешает разрешить такое кэширование (хоть вне операций,
Рис. Жизненный цикл ссылок на объекты, представляющие элементы документа
хоть внутри них). Только двух правил следует придерживаться:
1) обеспечить способ, которым пользователь кэша узнает, что кэш больше не соответствует данным документа;
2) кэш должен хранить копию данных и, если в используемом языке программирования существует понятие владельца в смысле кого-то, кто отвечает за удаление данного объекта, то владельцем кэша должен быть тот, кто его завел для себя (т. е. сам для себя сделал копию и когда не нужна более - удалил).
При необходимости созданная копия может подаваться сторонним расчетным функциям -в т.ч. и тем, которые в другой ситуации получают читаемые непосредственно из документа объекты. Откуда вытекает еще одно соглашение: если в какой-то метод пришел на вход объект, метод всегда должен понимать, что этот объект может быть лишь копией «для внутреннего пользования» - или, равным образом, это может быть не внутренняя копия, а созданный на время операции объект. То есть никакой метод не должен делать предположений о том, как возник пришедший ему на вход объект (впрочем, насколько автор себе представляет, никакому коду, кроме владельца «внутренних» копий, это и не интересно).
ЗАКЛЮЧЕНИЕ
Таким образом, предлагается методика проектирования, состоящая в применении следующих правил.
1. Если указатель на объект получен в некоторой операции, то в пределах операции можно использовать этот указатель.
2. Если указатель на объект получен вне операций, то как минимум до начала следующей операции можно продолжать его использовать. Либо - до того момента, пока каким-то способом не станет известно, что ссылка устарела.
3. Когда использование указателей для того, чтобы ссылаться на элементы документа в соответствии с пп. 1-2, становится более недопустимым, надлежит использовать другие механизмы - например, ранее предложенные автором в [1].
4. Допускается создание полных или частичных копий объектов, прочитанных из документа. Ответственность за жизненный цикл копии должен нести тот потребитель в программе, который их создал. Любой код, оперирующий объектами, которые могут отражать элементы документа, должен быть готов к тому, что ему могут подать на вход как объект, созданный из
элемента, так и его копию, и в идеале не должен пытаться выяснить, что из этого является истиной.
Следование этой методике позволяет добиться актуальности объектов, на которые отображается документ, и их связей во многих случаях даже без применения таких жестких мер, которые были предложены в [1].
СПИСОК ЛИТЕРАТУРЫ
1. Гумеров М. М. Проектирование обратимых операций над объектами на основе шаблонов при разработке программного обеспечения: дис. ... канд. техн. наук. Уфа, 2011. 118 с. [[ M. M. Gumerov, Design of Reversible Operations on Objects Based on Templates for Software Development, Cand. Sci. Thesis, (in Russian). Ufa, 2011. ]]
2. Choudhary R., Dewan P. "A general multi-user undo/redo model," in Proc. ECSCW, Stockholm, 1995, pp. 231246.
3. Berlage T., Genau A. "From undo to multi-user applications," in Proc. VCHCI '93, Sept. 1993, pp. 213-124.
4. Bernstein P. A., Hadzilacos V., Goodman N. Concurrency Control and Recovery in Database Systems. Addison Wesley, 1987, ISBN 9780201107159.
5. Пользователь DRogov. Технический отчет сотрудников Developer Express: «Undo/Redo — Хвост виляет собакой» [Эл. ресурс]. URL: habrahabr.ru/company/ devexpress/blog/104167/ (дата обращения 24.04.2014) [[ User DRogov, Developer Express: Technical Report 'Undo/Redo: Wagging The Dog'. Available: http://habrahabr.ru/ company/devexpress/blog/104167/ ]]
6. Zhang M., Wang K. "Implementing undo/redo in PDF Studio using object-oriented design pattern," in Proc. TOOLS-Asia'00, 2000, pp. 58.
ОБ АВТОРЕ
ГУМЕРОВ Максим Маратович, вед. спец. Дипл. инж.-программист (УГАТУ, 2004). Канд. техн. наук по мат. и прогр. обеспечению выч. машин, комплексов и компьютерных сетей (УГАТУ, 2011). Иссл. в обл. проектирования программного обеспечения.
METADATA
Title: Another approach to designing reversible operations in
software. Authors: M. M. Gumerov. Affiliation: «MASS MO» LLC, Russia. Email: [email protected] Language: Russian.
Source: Vestnik UGATU (scientific journal of Ufa State Aviation Technical University), vol. 19, no. 1 (67), pp. 254-257, 2015. ISSN 2225-2789 (Online), ISSN 1992-6502 (Print). Abstract: This paper reconsiders the results of author's earlier work [1]. The revised version suggests a new set of measures which in many cases provides a result analogous to [1] with less tendency to sacrifice customary style of handling objects in OOP languages. Key words: command; undo; object-oriented software design; object-relational mapping.
About the author:
GUMEROV, Maksim Maratovich, Senior Developer at «MASS MO» LLC. Dipl. software developer (USATU, 2004). Cand. of Tech. Sci. (UGATU, 2011).