Отступники
Кое-какой код из того, что сейчас работает у наших покупателей, я бы хотел переписать. Не потому, что он некрасивый, а по причинам куда как более приземленным...
Написана и давно работает библиотека, позволяющая рассматривать хранилище данных, например, базу MS SQL Server или Oracle, или набор XML-файлов, как совокупность объектов со связями. Это удобно, просто и понятно. Все обычно понимают суть спустя минут 5 после начала объяснения. Ну, к тому же мы написали генератор кода по определениям, как это сделали в своё время ребята из ThoughtWorks для библиотеки QuickFIX - для создания 5 классов, 3х процедур, одного view и таблицы требуется написать xml с описанием объекта и сгенерировать нужное. Итого - примерно минута or so. В общем, плодим сущности при всяком признаке надобности быстро и весело. И нам за это почти ничего не бывает, если только мы не отступаем от генеральной линии использования. Но некоторые случаи, такие, как тот, на исправление которого ушло 30 часов вместо 1го запланированного, вызывают у меня депрессию. Смотрите.
Объект со связями, находящимися в однотипной коллекции может понадобиться не всегда. Поэтому загрузка связей выполняется по требованию: если к свойству не обращаются, то и грузиться данные не будут (это экономия времени и памяти). Но если к свойству обращаются, то программист обязан придать результату вызова свойства детерминистичности: у одного и того же объекта вне зависимости от плотности потока космических лучей всякий вызов должен возвращать один и тот же набор данных. А также программист обязан не допускать деградации свойств объекта, удерживая объект на возможно более высокой ступени организации. Вроде два правила. Но что бывает, если от них отступить (а такие отступления всегда случаются в спешке, горячке, когда, по идее, ничего похожего и близко нельзя делать) - вот этого я бы никому не пожелал.
Отложенная загрузка выполняется так:
public Channel AssociatedChannel
{
get
{
if (m_Channel == null)
{
if (!IsNew)
{
IAdvancedRelationMining m = new RelationEngine();
m_Channel = m.GetOwners(this, null).First;
}
else
m_Channel = new Channel();
}
return m_Channel;
}
set
{
m_Channel = value;
MakeDirty();
NotifyPropertyChanged("AssociatedChannel");
}
} То есть, при получении свойства надо удостовериться в том, что 2 условия выполняются:
1. Получаемое поле - null, т.е., к нему ещё не обращались
2. Объект, содержащий поле - не новый (он у нас новый, если его Id < 0)
Если нарушить вышеприведённые правила, например, позволить объекту-контейнеру деградировать с инверсией Id, то получить то же самое значение свойства, которое было у этого объекта с ешё не инвертированным Id - не получится: поведение становится недетерминистическим, как GETDATE() в T-SQL или сумма на чеке, который я приношу из магазина. Последствия отступления от правил:
1. Из отведённого на поиск и исправление ошибки 1(одного) часа потрачено 30 (тридцать)
2. Проблема заключалась в инверсии, применявшейся к объекту, у которого ещё не вызывалось это свойство, и соответствующее поле объекта было равно null.
Причиной таких катаклизмов в нашем мирке является то, что вышеприведённый фрагмент написан человеком с одними представлениями о жизни, а применяется человеком с другими.

Комментариев нет:
Отправить комментарий