29 авг. 2009 г.

Доказательство от противного

Если бы полная мультинаправленная асинхронная неограниченная дельта репликация была возможна, то мир баз данных выглядел бы совсем иначе. Возьмем наших клиентов. Даже у крупных — размер БД измеряется десятками Гб, в то время как винчестеры современных настольных компьютеров имеют емкость до Тб, а то и более. В схеме с репликацией оператор работал бы на автономной копии БД, а когда возникала необходимость, скидывал бы дельту на центральную базу и загружал себе изменения, сделанные другими пользователями.

Плюсы очевидны:
  • устойчивость к потере данных (никакой RAID не сравнится)
  • возможность работать без подключения к сети
  • распределение нагрузки на все компьютеры
Правда и минусы имеются: злоумышленнику гораздо легче умыкнуть одну из сотни копий БД, разбросанных по рабочим станциям предприятия, да и мощности рядового компьютера может не хватить для построения тяжелого отчета по всему массиву данных в приемлемые сроки.

28 авг. 2009 г.

BS-Client? Скажем нет!

Новая программа банк-клиент, используемая БелАПБ, не перестает радовать своими сообщениями. Казалось бы пустяк: в текстовом файле с платежкой дата указана не в том формате. Нормальная программа так и сказала бы: в файле таком-то в строке такой-то дата указана в неправильном формате. И, возможно, даже подсказала бы верный формат: yyyy-mm-dd. Но, BS-Client идет дальше, значительно дальше:

EBLLError : Error in external call in module 'ACBAPBIMP.BLL' at line 376:
EVDBEngineError:Invalid data size 213471868, must be 4
CallStack:
Line 0376. Module ACBAPBIMP.BLL
Line 1136. Module ACBAPBIMP.BLL
Line 1590. Module ACBAPBIMP.BLL; LibraryName:acbapbimp.bll;
FunctionName:impbapb_crystal; SchemeName: LinkBS; SchemeType:
stSimple(0); OperationName: ImportBAPB; OperationType: otSimpleBLL(0)
-------------------------------------------
Module  :
Thread : 00000B58 (LinkBS.ImportBAPB)
Instance: 3402
PID/Comp/User: 3956/BUH2/Администратор

Формат текстового файла экспорта этой программы заслуживает отдельного упоминания. XML, JSON, YAML, INI — это всё для лузеров. Мысль конечно прослеживается: сделаем простой формат, текстовый файл, где одна строка содержит одно поле. По первому символу в строке будем узнавать, что за поле. Для обозначения полей будем использовать латинские символы и цифры. Только потом оказалось, что полей больше чем доступных символов. Вместо очевидного решения использовать два первых символа, для новых полей начали использовать коомбинацию из ^ и символа латинского алфавита или цифры. Без документации под рукой не упомнишь что есть что. Например, просто 6 — это УНН плательщика, а ^6 — это уже Тип конверсии. Да еще повсюду, какие-то магические ограничения: "ширина строк не более 113 символов" — цитата из спецификации. О форматах дат и чисел по большей части надо догадываться самому. Например, в документации по рублевому импорту поле "Сумма платежа" описано как "20,2 (разделитель – ‘.’или’,’)". Оно же для валютной платежки — "Сумма перевода (дробная часть ч/з «,», 2 знака)".

Тры з чвэрцю

Пачынаючы з восені 1999, атрымоўваецца, што мы працуем з БМКК 10 год. Адлегласьць да Бярозы 250 км. Разам са зваротным шляхам будзе 500 км. Частата наведваньняў, прыблізна, адзін чалавека-выезд раз на два тыдні, альбо 26 на год. Тады агулам адолена 26 * 10 * 500 = 130 000 км! Тры з чвэрцю зямных экватары!

25 авг. 2009 г.

Двоякий исследователь

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

Очевидно,  что презентационная часть должна быть отделена от системы разграничения прав. Заодно и визуальную организацию следует пересмотреть. Древовидный список — это, конечно, самое простое и первое, что приходит на ум, но, работать с базой на которую загружено много прикладных настроек, через Исследователь неудобно. Так как команд даже в одном разделе Исследователя, как правило, достаточно много, их следует развернуть в двухмерную сетку. Тогда напрашивается организация Исследователя ввиде набора вкладок, где каждая вкладка — это раздел. На вкладке выводим пиктограммки команд. Их тоже группируем, уже по подразделам. Например: вкладка "Зарплата". На ней несколько визуально выделенных областей: документы, справочники, отчеты, параметры и т.д.

Где-то вверху исследователя должна располагаться строка поиска. Вводим в ней последовательность символов и получаем все найденные команды, отсортированные по релевантности. Сначала показываем по вхождению в наименование самой команды, потом по вхождению в наименование раздела, в который входит команда и т.д. по иерархии разделов-подразделов в GD_COMMAND.

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

Известная истина гласит: все новое — это хорошо забытое старое. Если мы выводим пиктограммки команд в двухмерной сетке, да еще и визуально разделяем их по областям, то почему бы не нарисовать связи между ними? Что бы начинающему пользователю сходу было понятно что к чему. Рисуем и получаем...
Центр управления™ из нашей старой доброй программы Анжелика Бухгалтер!

В свое время, для отрисовки Центра управления был написан renderer, который принимал на вход особый двоичный код. Код хранился в *.RC файле и компилировался прямо в выполняемый модуль. Не очень удобочитаемый был код, надо сказать:

22 GSTOOLBAR
BEGIN
28
111
20
0
529
$04
$00
1
0
0
$04
$01
0
1
102
$04
$00
2
2
333
$08
$00
3
3

...

PS: Ради справедливости стоит заметить, что идея центра управления была подсмотрена нами 15 лет назад в австралийской программе MYOB.

22 авг. 2009 г.

Звычайны беларускі дурдом

Гісторыя з "рэклямай Гедыміна" атрымала сумны працяг. Усяго некалькі дзён правяселі плякаты, пакуль чыноўнікі з адміністрацыі прэзідэнта іх не забаранілі.
Пра гэта таксама піша Наша Ніва.

21 авг. 2009 г.

Бігборды з рэклямай Гедыміна :)

Заўважана днямі ў Менску:
Зьвярніце ўвагу на іконку! Фотаздымкі ўзяты з сайту marketing.by.

16 авг. 2009 г.

Delphi 2010. 8 days remaining...

This version in fact is the Delphi 2009 re-tooled and bug free (at least, it is promised). The same was with transition from Delphi 4 to Delphi 5. Is it time to move?

15 авг. 2009 г.

Параллельными курсами

В статье про организацию репликации читаем:
Для унификации желательно, чтобы в каждой таблице, включенной в процесс синхронизации был суррогатный первичный ключ (ID) - обычно INTEGER. Впрочем, чаще всего так и есть. Как же мы можем обеспечить уникальную идентификацию записей.
...
Можно сделать первичным ключем строку спецального формата, например XXXX-YYYY-ZZZZZZZZ, где XXXX - это идентификатор базы данных, где запись была создана впервые, YYYY - идентификатор таблицы, ZZZZZZZZ - идентификатор записи внутри конкретной таблицы конкретной БД.
Практически наш RUID, только что нам нет смысла хранить ID таблицы, так как идентификатор записи уникален в пределах одной базы данных. Наше отличие — для хранения RUID используется отдельная таблица. Была идея хранить RUID непосредственно в каждой таблице, но от нее отказались по соображениям экономии места. Не каждая запись нуждается в получении загранпаспорта.

Там же:
На мой взгляд, для InterBase лучшим вариантом является следующий - ID для всех таблиц генерируется обычным триггером, выбирающим значения из генератора. При этом начальное значение генератора различно для разных БД, за счет чего обеспечится уникальность ID по всем БД. Данный подход характерен для InterBase. Применение его для других СУБД может быть ограничено невозможностью задать начальное значение для счетчика автоинкрементных полей.
Аналогичная идея была в Гедымине. Для смещения идентификаторов в каждой базе планировалось применять свое значение генератора gd_g_offset. Типичный код триггера на присвоение идентификатора записи:

CREATE TRIGGER gd_bi_command FOR gd_command
  BEFORE INSERT
  POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
  NEW.ID = GEN_ID(gd_g_unique, 1) + GEN_ID(gd_g_offset, 0);
END

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

PS: Перенос прикладных настроек — это по сути односторонняя репликация в урезанном виде.

PPS: Подборка материалов по репликации (синхронизации) БД.

12 авг. 2009 г.

Firebird 2.5 Beta 2 released

Among others:

"Testing suggests that the performance of Classic in this version will be be significantly faster than previous Classic versions."

"The client libraries, including the embedded one, can now be used in multi-threaded applications without any application-level synchronization."

3 авг. 2009 г.

Четыре списка параметров запроса

В окне SQL редактора (TfrmSQLEditorSyn) список параметров запроса присутствует четыре (!) раза:
  1. Непосредственно в самой компоненте ibqryWork.
  2. В отдельном списке FParams, который служит для хранения значений параметров между выполнениями запроса.
  3. Внутри окна запроса значений параметров у пользователя — TdlgInputParam.
  4. В поле SQL_PARAMS в таблице GD_SQL_HISTORY.
В добавок существуют два алгоритма преобразования списка параметров в текст и обратно:
  1. В окне TdlgInputParam для сохранения в файл.
  2. Для сохранения в таблице с историей запросов.
Для сохранения в файле (мемо поле) используется TStringList, который заполняется следующим образом: каждое поле — отдельная строка в формате имя_поля=значение_поля. Разумеется, что значение поля получается преобразованием в строковый формат согласно региональных установок, действующих в данный момент на компьютере.