27 февр. 2011 г.

О легальном ПО и ценах для Беларуси

Одни наши клиенты, крупное промышленное предприятие, в ожидании комплексной проверки задумались о переходе на бесплатный Open Office. А мне вспомнились времена, когда приобретение легального программного обеспечения не представляло большой проблемы для предприятия, хотя лицензии тогда никто не проверял. После падения железного занавеса, в первой половине девяностых, американские компании пытались освоить местный рынок. Некоторые даже локализовывали свои продукты, но большинство поставляло обычные англоязычные версии по сниженым в разы ценам.

У организации, на которую мы тогда работали, на сеть из десяти компьютеров было приобретено десять копий Microsoft Windows for Workgroups 3.11 и одна коробка с Microsoft Windows 3.1. Последняя использовалась вообще считанное число раз и в основном для раскладки пасьянса.

На большой полке размещались коробки от средств разработки: Turbo Pascal 6.0, Borland Pascal 7.0, Paradox Engine 1.0, Borland Paradox 1.0 for Windows и Borland Delphi.

Надо заметить, что для покупки легального программного обеспечения тогда существовал серьезный стимул. В то время, как в книжных магазинах продавалось целых две книги по программированию, в коробке с программой шел полный комплект: руководство пользователя, руководство разработчика, руководство по отладке и т.п. Кое-что, позже и в переводе, можно было выловить на BBS и распечатать на матричном принтере, но, разумеется это не шло ни в какое сравнение с оригинальной книгой, качественно напечатанной на снежно белой бумаге.

На сегодняшний день, цены на ПО для Беларуси не отличаются от цен для всего остального мира. Как мне представляется, здесь западные компании просто недопонимают сложившуюся ситуацию и совершают большую ошибку. Снизив цену в 4-5 раз они могли бы в десятки раз повысить продажи и одним махом решить проблему пиратства.

18 февр. 2011 г.

Проверка прав на уровне записи

Разборка одного случая, когда запрос под Администратором выполнялся значительно быстрее чем под обычным пользователем, показала, что вина лежит на дополнительном условии с вызовом функции G_SEC_TEST.

Появление UDF функции в секции WHERE запроса часто сводит с ума оптимизатор и приводит к ужасным планам. Если проверку на права доступа перенести на уровень клиента, внутрь датасета, сразу после считывания записи с сервера и перед копированием ее во внутренний буфер, то получим выигрыш в тех случаях, когда у пользователя есть права на большинство записей в результате выборки. В противном случае — перенос проверки на клиента породит избыточный трафик по сети.

Слаще ли хрен редьки выяснить можно только экспериментальным путем.

Вот, если бы заранее знать долю записей на которые у текущего пользователя есть/отсутствуют права...

13 февр. 2011 г.

Замена парсера SQL

Существующий парсер SQL называется TsqlParser и используется внутри класса TatSQLSetup из модуля at_sql_setup.pas. TatSQLSetup отвечает за формирование запросов SELECT, UPDATE, INSERT внутри бизнес-объекта. На момент написания кода бизнес-объекта в Delphi, разработчик не знает какие поля будут позже добавлены настройщиком системы. Поэтому он пишет например так:
SELECT 
  * 
FROM 
  gd_contact z JOIN gd_people p 
    ON p.contactkey = z.id
Напоминаем, что главная таблица бизнес-объекта у нас всегда имеет алиас z.

Во время выполнения программы, после создания экземпляра бизнес-объекта, в процессе его открытия (не забываем, что БО является набором данных, т.н. датасетом), происходит последовательная разборка запроса, добавление списка пользовательских полей (для ссылок добавляются джоины на справочники), и обратная сборка запроса. Информация о пользовательских полях и их типах берется из глобального объекта atDatabase.

То ли существующий парсер работает достаточно медленно, то ли все дело в обращении к объекту atDatabase (точных замеров не производилось), после формирования запроса он кэшируется и создаваемые позже объекты такого же типа используют уже готовый текст запроса из кэша.

Собственно, задание:
  1. В классе TatSQLSetup заменить старый парсер на новый.
  2. Откомпилированную грамматику Firebird SQL подлинковать к экзешнику ввиде двоичного ресурса.
  3. Проверить быстродействие нового парсера и, возможно, отказаться от кэширования сформированного текста запроса.
  4. Код, использующий новый парсер, отделить от существующего условной компиляцией под символом NEW_SQL_PARSER.

10 февр. 2011 г.

Лучше поздно, чем никогда

Бывают такие баги/нюансы программного обеспечения, которые портят пользователям тонны крови, а исправить их, как оказывается в итоге, -- минутное дело. Но, всегда то руки не доходят, то лень, то нет времени, то религиозные ограничения не позволяют.

Вот и Микрософт по прошествии 16-ти лет отключила-таки автозапуск в операционной системе Windows XP. Впервые представленная еще в Windows 95 функция, служит лазейкой для, как минимум, 90% всех заражений компьютерными вирусами.

Атрибуты визуального отображения

Пусть бизнес-объект для текущей записи, в зависимости от значений полей, возвращает набор визуальных атрибутов. Например: normal, grayed, strong, accented и т.п. При отрисовке строки, грид будет брать из текущей визуальной темы шрифт, цвет фона и т.п. в соответствии с атрибутами бизнес-объекта. Тогда мы сможем управлять внешним видом данных в соответствии с природой конкретного бизнес-объекта. Так, для объекта пользователь системы, учетные записи из группы Администраторы можно выводить жирным шрифтом. В списке счетов-фактур можно выделять просроченные, оплаченные, частично оплаченные и т.д.

1 февр. 2011 г.

ORM с помощью updateable view

Бизнес-объекты скрывают от программиста реляционную структуру данных конкретной сущности (т.н. ORM). Например, последовательность методов Insert-заполнение полей-Post объекта типа TgdcCompany приведет к трем операциям INSERT в базу данных внутри метода InternalPostRecord, в таблицы gd_contact, gd_company и gd_companycode.

Такого же эффекта можно достичь средствами одного только SQL, используя обновляемые представления (updateable view).

Создадим представление для отображения данных бизнес-объекта Компания:
create view vcompany as
  select * from
    gd_contact c 
    join gd_company co on c.id=co.contactkey
    left join gd_companycode cc on cc.companykey = c.id
Создадим триггер:
recreate trigger vcompany_ai for vcompany
  after insert
  position 0
as
  declare variable id integer;
begin
  if (NEW.id IS NULL) then
    id = GEN_ID(gd_g_unique, 1);
  else
    id = NEW.id;
  insert into gd_contact (id, parent, contacttype, name)
    values (:id, NEW.parent, 3, NEW.name);
  insert into gd_company (contactkey, fullname)
    values (:id, NEW.name);
end
Теперь добавить компанию в базу данных можно с помощью команды:
insert into vcompany (name, parent)
  values ('Company name', some_existing_folder_id)
Аналогичным образом реализуем обновление и удаление данных.