Ошибки и их исправление в эргономике API и GUI

(Продолжение. Начало в №25)


Отображение полей хранилища как есть

Нужно расширить определения "UNIQUE" и "PRIMARY KEY" до "UNIQUE SUBSTITUTE af" и "PRIMARY KEY SUBSTITUTE af", где "af" (another field) - имя другой колонки той же таблицы. Машина демонстраций из записей, на которые ссылаются внешние ключи, извлекает значения af-полей и демонстрирует их вместо значений самих внешних ключей. Для этого, разумеется, ей нужно считать из системных таблиц схему хранилища (т.е. схему базы данных, из которой удалена машина 'join'). При нажатии "Enter" на поле, содержащем внешний ключ, машина открывает новое окно с той единственной записью, на которую ключ ссылается. Нажатие некоторой кнопки "All" нового окна - или пункта меню окна, или кнопки клавиатуры - отображает все записи той другой таблицы, можно делать скроллинг; а нажатие некоторой "Choice" на какой-либо записи закрывает окно и копирует её физический ключ во внешний ключ записи в первом окне. Каждое окно является точкой останова (savepoint); нажимая некоторую "Back", пользователь не только закрывает окно, но и откатывает все сделанные в нем изменения. Машина отображает комментарии к колонкам вместо их названий. Можно добавить второй комментарий для колонки, в котором указать, что сначала нужно показать в новом окне не ту вторую таблицу, на которую колонка ссылается, а третью таблицу, на которую вторая таблица ссылается - пользователь сначала выберет в третьей, потом во второй. Вот сколько запросов, произведенных машиной автоматически, порождает один print-SELECT ее клиента.

Ну а теперь главное: позволим упоминать в запросе несуществующие, виртуальные колонки, которые представляют таблицы, ссылающиеся на данную - "SELECT v1, v2 FROM tab1 CULTIVATE v1 BY tab2(fld2), v1 BY tab3(fld3)". В таких колонках демонстрируется название таблицы, ссылающейся на них; а при попытке ввода в такое поле открывается новое окно и отображаются записи, ссылающиеся на данное поле (нажатие "All" в окне демонстрирует все записи той другой таблицы, ссылающиеся записи выделяются цветом фона). Если в машине установлен сессионный параметр показывать по умолчанию все возможные виртуальные и невиртуальные колонки, то, запросив любые поля любой таблицы, пользователь может дальше путешествовать по всему хранилищу независимо от его схемы, редактировать и заполнять его вообще без программирования, ему остается только создать саму схему хранилища. Разумеется, необходимы кнопки "Add" и "Delete" для добавления-удаления записей. Также полезны будут "Next", симметричная "Back", чтобы накатывать изменения, и "Commit".

При этом слово LIMIT ("SELECT ... LIMIT 10") относится не только к парсеру хранилища, но и к парсеру машины демонстраций: последняя должна создать полосу прокрутки по правому боку этих 10 записей, при нажатии "стрелки-вниз" на последней записи - автоматически запросить cледующую порцию "SELECT ... FROM ... DOWNWARD ... LIMIT 10" (где DOWNWARD перечисляет значения полей последней записи), при нажатии "стрелки-вверх" на первой записи второй порции - запросить предыдущую порцию "SELECT ... FROM ... UPWARD ... LIMIT 10" (где UPWARD перечисляет значения полей первой записи). И высоту слайдера в полосе прокрутки установить в соответствии с результатом "SELECT COUNT(*)".

 

И еще следовало бы добавить вот какой новизны. Если колонка таблицы содержит картинки или фильмы, то они воспроизводятся в поле. А не вычерпываются вручную пользователем на каком-то сервере приложений, а потом же вручную визуализируются в окне с помощью вызовов библиотек. Изменение размеров поля означает масштабирование картинки и фильма. Показ единственной картинки достигается запросом единственного поля. Ширина колонок и высота строк, координаты таблицы на экране, а также возможные другие параметры визуализации данной таблицы, отличные от принятых по умолчанию или вычисленных эвристически, могут быть перечислены в других таблицах, на которые она ссылается с помощью "CREATE TABLE tab1(..., STYLED BY tab2, tab3)"; или заданы при извлечении информации с помощью "SELECT ... FROM ... STYLING ..."; или изменены пользователем прямо на экране путем манипуляций мышью.

И раз уж мы упомянули о видео, не будем также заставлять пользователя строить диаграммы вручную через машину проекций. Ему будет удобнее достать записи из таблицы обычным SELECT, а после STYLING указать тип диаграммы (график, гистограмма, "торт", "японские свечи", "векторное поле") и какие колонки таблицы для каких параметров диаграммы предназначены. Однако вернемся к визуализации строковых и числовых данных.

Другой подход к экономии сил, принципиально отличный от виртуальных колонок, проистекает из схемы IDEF1 для полей экрана в любом ПО. Эта схема полностью повторяет схему хранилища. Желая видеть, например, департаменты и их сотрудников, но не желая видеть отделы, из которых департаменты состоят, мы можем писать "SELECT Departments.Persons FROM Departments.Sections.Persons". В декартовом произведении машины 'join' невозможно различить, какие записи таблицы "Departments" каким записям таблицы "Persons" соответствуют, т.е. часть информации из хранилища при извлечении теряется. Из-за этого делают не один запрос, а столько, сколько записей в таблицах. Нотация оказывается загаженной циклами и вспомогательными операторами, время выполнения - бoльшим. Но выражение типа "tablename1.tablename2" позволяет унести ранее терявшуюся информацию. Расположение на экране структур "Departments" и "Persons" относительно друг друга, вычисляемое машиной демонстраций эвристически, можно переопределить после служебного слова STYLING.

Иначе можно отобразить две таблицы конструкцией "SELECT ... ALSO SELECT ...". Если таблицы главная и подчиненная, то в подчиненной видны только записи, ссылающиеся на текущую запись главной. Если несколько главных и одна подчиненная - то в подчиненной только записи, ссылающиеся на текущие записи главных. Если подчиненная "s" несколькими своими колонками ссылается на главную "m", то "SELECT ... INFLUENCE m(m3) TO s(s5), ..." снимает неопределенность. Визуализация на сервере устраняет необходимость размещать на клиенте программу, написанную на Delphi и прочих компилирующих RAD, или runtime библиотеку Oracle Developer и ему подобных, подключение которых - целая проблема для пользователя; устраняет необходимость компилировать программу под JVM, функциональность которой не в тандеме с оконным сервером, или транслировать под интерпретатор JS, который дублирует оконный сервер и даже с Web SQL Database, AJAX и SVG не расчитан подо все use-case-ы. Кроме того, загрузка одного и того же сегмента кода в память многих клиентов (вместо памяти одного сервера) требует увеличения совокупной памяти вычислительной среды, а необходимость отвечать в реальном времени - тиражирования ядер и кэшей сервера на клиентах и их простаивания в течение больших пауз. И все это в эпоху повсеместного проникновения Интернета. Кто-то и на этих искусственных барьерах вытаскивает из нас деньги. А когда подсчитаешь, то идея совмещения X11 и SQL уже не кажется дикой. Т.е. идея устранить искусственное разделение на окно прикладной программы и окно терминала сегодняшних СУБД.

На языке запросов должен выполняться и просмотр таблицы как гиперкуба. Одна колонка содержит значения в узлах многомерного куба ("a" на рисунке ниже), другие колонки представляют координатные оси: их комментарии (а при отсутствии таковых - названия) отображаются как названия осей ("покупатель", "товар", "город" и т.д. - "H" и "h" на рисунке), их значения демонстрируются как отсчёты по этим осям (имена покупателей, названия товаров, названия городов - "V" и "v" на рисунке). В запросе "SELECT ... HEADER ... SIDER ... FROM" колонку для значений в узлах укажем после SELECT, колонки для горизонтальных осей (сверху вниз) перечислим через запятую после HEADER, для вертикальных (слева направо) - после SIDER. Названия осей можно перетаскивать мышью, как изменяя порядок осей, так и перемещая их из горизонтальных в вертикальные и обратно. Кроме того, по кнопке "Columns" можно получить список еще незадействованных колонок этой таблицы и выбрать какую-либо из них для значений в узлах или в качестве еще одной оси. Аналогично обычному просмотру таблицы, "LIMIT 9, 5" укажет, что большая часть данных не сразу отображается на экране, а подгружается по мере скроллинга; размер горизонтального и вертикального слайдеров машина демонстраций вычислит сама.

  H V V
H V V V V
H V V V V V V V V V
h h h    
v v v   a a a a a a a a a
v a a a a a a a a a
v a a a a a a a a a
v v a a a a a a a a a
v a a a a a a a a a

Чтобы увидеть таблицу с "медвежьим ухом" (внешний ключ ссылается на физический ключ той же таблицы) в виде дерева, а не как плоскую таблицу, а заодно чтобы разрешить неопределенность в случае нескольких "ушей", придется указать, какой из внешних ключей имеется в виду ("SELECT ... TREE ... FROM", колонка после SELECT содержит текст для узла дерева, а колонка после TREE определяет используемый внешний ключ). ORDER BY упорядочивает узлы одного уровня вложенности с общим родителем. Пользователь может на экране открывать и закрывать, добавлять и удалять, перемещать и копировать узлы, в т.ч. и между двумя SELECT TREE, выполненными в одну таблицу - действия мышью автоматически порождают SQL-запросы машины демонстраций в хранилище.

Параметры визуализации дерева могут быть следующими. IMAGE определяет BLOB-колонку с картинкой для узла или колонку-внешний-ключ, ссылающуюся на такой BLOB. SWITCH - булевскую колонку, указывающую, открыт или закрыт узел. Следующие параметры сами по себе являются булевскими. ONELINE указывает продемонстрировать узлы одного уровня вложенности в одной строке, а не друг под другом. CENTER - расположить дочерние узлы по центру родительского, а не сбоку (справа для арабского письма, слева - для всех остальных; если разные узлы на арабском и неарабском языке, то они по разные стороны от родительского). MARKER - отображать маркер в узле вместо плюсика и картинки, как в ненумерованном маркированном списке (как меняются фигурки маркера, в зависимости от глубины узла, рассказано ниже в разделе "Наблюдение текста"). COWPATH - демонстрировать дерево не традиционным образом, а показывать для узла, на котором находится фокус, только непосредственно вложенные в него узлы, но не более далеких его потомков; все родительские узлы вместе с тем, на котором находится фокус, не отображать, а перечислять через слэш в качестве заглавия всего дерева подобно тому, как путь отображается в программе TotalCommander. Ну и, наконец, параметр PAPER определяет текстовую колонку; если она определена, дерево отображается как документ, названия узлов - как названия подразделов документа, а содержимое текстовой колонки - как содержимое подразделов.

Электронная таблица a-la Excel похожа на двумерную сетку, задающую границы объемных фигур (sql50.euro.ru/sql5.19.2.pdf, с.229): в первой колонки, содержащие контент ячейки, отмечены как "VARCHAR CELL", во второй - колонки, содержащие точки, отмечены как "NUMBER ARRAY[3] DOT"; в первой в дереве на один уровень выше расположены строки электронной таблицы, во второй - четырехугольники. В обеих записи остальных уровней не визуализируются. Отображаются электронная таблица и объемная фигура одним и тем же SELECT.

С незапамятных времен во всех кодировках текста есть непечатные символы для управления этим самым текстом. Будем использовать их для вставки маркированных списков, электронных таблиц, гипер-ссылок, а также - если мы имеем дело с формой - элементов управления. Все эти объекты находятся в отдельных полях хранилища, а не содержатся посреди текста, что является результатом перехода от файлового мировозрения к структурному. Непечатные символы ограничивают SELECT, извлекающий эти объекты. Если пользователь в оконном сервере отредактирует маркированный список или электронную таблицу, машина демонстраций скопирует изменения в хранилище, если установит чекбокс или переключит радиобокс - изменит состояние соответствующего поля хранилища, если нажмет кнопку - напрямую скомандует запустить её триггер. В отличие от применяемой сегодня последовательной передачи переменной по траектории "стандартная библиотека ввода-вывода - программа - библиотека для хранилища" (причем процедуры для передачи в одном и в другом направлении разные), наш SELECT скорее является просто адресом объекта в хранилище. Такой способ действительно доступен массам населения - в отличие от применяемого сегодня. Контраст становится особенно разительным в случае Веб. Кроме прочего, хранилище может быть изменено и внешним агентом, что позволяет динамически расширять списки и деревья.

По поводу представления в хранилище нужно заметить, что выпадающий список с единственным выбором функционально совпадает с радио-группой, а с множественным выбором - с группой чекбоксов. А значит расставлять их надо не по одному каждый раз вручную в собственной программе, а переложить эту работу на машину демонстраций. У нас горизонтальное направление письма, а не вертикальное; поэтому боксы с легендами, вытянутые в горизонтальную линию, не дают визуального ощущения их группового единства; кроме того, очень малое количество легенд можно расположить в один ряд. Поэтому боксы располагают вертикально. Достаточно после STYLING или с помощью STYLED BY определить способ отображения - выпадающим списком или группой боксов. Пусть за это отвечает параметр ANGLE (подробнее о нем ниже), равенство его NULL означает выпадающий список, равенство нулю или любому другому числу - группу боксов. С чек-ситуацией всё понятно - нужно запросить булевскую колонку таблицы. Для радио-варианта в качестве механизма извлечения из хранилища будем использовать "SELECT ... FROM a ALSO SELECT ... FROM b FILLING a(a1) BY b(b1) STYLING angle=0", где поле 'a1' в результате действий пользователя должно принять одно из значений колонки 'b1', показ единственного поля 'a1' достигается запросом единственной строки таблицы 'a', одна из таблиц самостоятельно не демонстрируется вообще - 'b' при 'angle=null', 'a' при 'angle=0'. В последнем случае запрос более одной строки таблицы 'a' является ошибкой, ибо поле-приемник неизвестно.

Применительно к хранению также нужно заметить, что в некоторых случаях логика приложения такова, что гипер-ссылка более естественно выглядела бы в виде кнопки. Таким образом структуре в хранилище, отображаемой как кнопка, иногда соответствует триггер, иногда - адрес. Пометим её поля или одно поле, содержащее массив чисел с размерами кнопки, визуальным типом BUTTON, чтобы структура не отобразилась как строка таблицы. Все остальные числа структуры содержат адреса одного и того же документа; их много на случай, если некоторые адреса окажутся битыми. Машина демонстраций перепроверяет их автоматически один за другим при нажатии структуры (кнопки или ссылки) в оконном сервере и извлекает документ с первым действительным адресом. Не будем требовать, чтобы были возможны либо триггеры, либо адреса. Но если хоть один адрес есть, структура отображается как ссылка, даже если установлен триггер. Единственное ограничение целостности, налагаемое хранилищем на BUTTON-структуру - текствое поле в ней должно быть одно. Оно содержит надпись кнопки или ссылки в формате, указанном в последнем разделе статьи "Чего не было в кодировках, и до чего до сих пор так и не додумались" ("КВ" №13, следует добавить, что в той статье не упомянут спецсимвол для обозначения ударений, отличный от диакретиков, и что 7-й бит байта-предсказателя обозначает тень текста).

Итого, для вывода любых данных в три оператора CREATE TABLE, INSERT, SELECT выводим в три оператора и "Hello, world". Stdin и stdout, как мы помним, отсутствуют - существует только копирование записей или обновление полей.


Промежуточные итоги

Print-SELECT в составе ОС наконец-то позволяет простому смертному не реализовывать интерфейс, а получать его даром; модуль транзакций, триггеров и прав на структуру вместо обмена сообщениями IPC и прав на файл позволяет удалить второй барьер "Vendor lock-in"; этот же модуль вместе с оконным сервером - навязать совместимый формат передачи данных и убрать драйверы; машины проекций и демонстраций изымают существенные компоненты коммерческого ПО и некачественного бесплатного, облегчая компьютер и обеспечивая вынужденную совместимость. Сегодня не-выделение повторяющихся задач в отдельный сервис ОС порождает целый "зоопарк" компенсирующих друг друга процессов, а значит больше ошибок в коде, больше денег нужно отдать другим странам за успехи в физике твердого тела, больше мест для атаки как вирусам, так и хакерам. Именно этого должна избегать национальная ОС. В результате надстраивания одного над другим получается типичный клудж.

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

(Окончание следует)

Дмитрий ТЮРИН,
dmitryturin.narod.ru

Версия для печатиВерсия для печати

Номер: 

29 за 2010 год

Рубрика: 

Размышлизмы
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!