четверг, 6 марта 2014 г.

Хранение объектов БД в памяти

В одном проекте появилась идея загрузить объекты из БД один раз, и работать с моделью домена в памяти, т.е. исключить постоянные запросы к БД. По необходимости выполнять сохранение данных в БД. По сути, в этом случае БД является просто хранилищем данных. В этом проекте в теории не могло быть больше двух клиентов, одновременная работа с одними и теми же данными тоже не должна была вестись. Так что идея вроде здравая. И использование методики разработки корпоративных приложений, когда хранение объектов в памяти клиентов может привести к рассогласованности с БД и нужно выполнять сохранение в БД как можно чаще, не требуется.
Но  оказалось, что при работе с ORM (qxorm) сложно обеспечить двустороннюю связь объектов на уровне указателей. Т.е. при наличии кода
MapPtr map(new Map());
qx::dao::fetch_by_id_with_relation("*->*->", map);
MapPtr mapFromRelation = map->programs().first()->map();

В результате map.data() не равен mapFromRelation.data(). Получается, что один объект может быть загружен несколько раз, и нельзя опираться на их идентичность на уровне указателей. Т.е. изменения атрибутов одного никак не повлияют на другого. И мы получим рассогласованность данных на GUI.
Была предпринята попытка добавить ленивую загрузку (lazy load) совместно с картой объектов (Identity Map). Но ничего конкретного не вышло, добавились другие проблемы: как  при удалении элемента очищать все зависимости из IM. К тому же не нравился подход к выборке коллекции объектов из IM, сначала приходилось выполнять запрос, затем искать в карте объектов и только после этого возвращать результат.

ps: при хранении в памяти всей модели предметной области для обеспечения целостности, чтобы не было проблем при сохранении со всеми реляциями предполагалось, что при добавлении/редактировании/удалении объектов будет обязательно выполняться метод validate().

Redmine plugins

При подключении плагина редмайна имя при регистрации должно совпадать с именем каталога плагина. В противном случае, не находит вьюхи и все такое.

Автоматизация тестирования rails приложений RSpec, Cucumber, Capybara

RSpec используется для тестирования бизнес логики.
По Cucumber и Capybara, скажу так: «огурец» будем использовать, как «парсер» текста интеграционных тестов, Capybara — как прослойку между Cucumber и драйвером, а так же для написания шагов автоматизации. Иными словами… на cucumber мы пишет наши тесты простым языком, а сами шаги реализуем с использованием Capybara. А Capybara уже взаимодействует с webdriver'ом, но это уже совсем другая история

Редактирование объектов с обновлением в разных вьюхах

Существует несколько подходов к редактированию объектов, когда требуется динамическое обновление связанных элементов в других представлениях. В качестве примера можно рассмотреть ГИС систему, в которой на карту требуется наносить точки с определенными атрибутами, главные из которых - это широта и долгота. В системе предусмотрено два вида отображения точек: в табличном списке и на карте ГИС. Редактирование точек можно производить при помощи дополнительного окна с детальной информацией по точке, а также с помощью перемещения точек непосредственно на карте. При этом, во всех представлениях должны динамически изменяться атрибуты. Возможные варианты редактирования:
  1. из окна редактирования без явной кнопки save (типа редактор свойств) или из карты. Объекты хранятся в памяти и всегда используются один указатель во всех представлениях. При изменении свойства объекта испускается сигнал об изменении, на который подписаны представления. Представления обновляются по этому сигналу. По сути это классический Model-View. Одна модель - много наблюдателей. В качестве модели выступает Point
  2. из окна редактирования точки с наличием кнопки save или из карты (save срабатывает при отпускании точки на карте). При хранении объектов в памяти динамическое обновление будет выполняться, но по кнопке save фиксация изменений может не пройти (например, запись в БД). В этом случае нужно по кнопке отмена откатить изменения. Соответственно, необходим клон объекта на момент начала редактирования, чтобы из него можно было восстановить начальное состояние. 
  3. при работе с БД, ормом и passive view, когда на уровне представления хранятся только идентификаторы объектов и загруженные атрибуты. Очевидно, необходим дополнительный объект, который бы занимался оповещением объектов уровня представления. По событию обновления координат, обновлялись бы другие представления. При невозможности сохранения или отмене проводилось бы соответствующее  оповещение.
Если не нужно автоматическое обновление на всех представлениях в динамике, а только по факту успешного сохранение, то можно при вызове окна редактора заполнять контролы данными из объекта (по сути копия данных), по кнопке сохранить извлекаем данные из контролов во временный объект, сохраняем, если успешно, то обновляем атрибуты исходного (для случая хранения объектов в памяти). В случае passive view исходного не будет, нужно просто запросить новые данные для вью. Т.е. в случае работы с БД получаем из контролов данные, сохраняем, оповещаем по id, что сохранение прошло, всем заинтересованным обновиться, они выбирают свежие данные из БД и обновляют вью.