«Некоторые произведения, может быть, отличаются большей глубиной мысли
и лучшим знанием человеческой природы; иные книги, быть может,
не уступают моей в отношении оригинальности и объема,
но своей безнадежной, неизлечимой достоверностью она превосходит
все до сих пор обнаруженные сочинения.»
Дж.К.Джером. "Трое в одной лодке, не считая собаки"
Дабы не топтаться в парадном, покуривая мануалы, пытаясь вчитаться в рекламные буклеты или вслушаться в страстные заверения очередного волнистого попугайчика от АйТи, приглашаю Вас войти в мир Cache' с задворков — совершить этакое нелегальное погружение. Как человек, работающий с этой технологией не первый (а второй!) десяток лет и мало-мало знакомый с ней, надеюсь что смогу осилить роль гида в этом простеньком путешествии.
Интересующимся предметом разговора вкратце доложу: речь пойдет о СУБД с одной стороны достаточно неочевидной, с другой — претендующей на роль серебряной пули для разработчика всевозможных ИС, КИС, ИАрПи и проч. и проч. Если вы имеете хоть какое-то отношение к рынку программного обеспечения, потраченное время окупится — я попытался уместить сюда мой лучший опыт последних лет. Отнюдь не академический. И даже если Вы уже пытались постичь Cache' неудачно — поверьте, иногда зайти даже в самое респектабельное заведение из подворотни (с нужным провожатым) оказывается более результативно. И чего уж греха таить и скромничать — часто дело именно в спутнике.
Итак, первые пять минут на развертывание.
«И если тебе вдруг наскучит твой ласковый свет,
Тебе найдется место у нас, дождя хватит на всех.»
В.Цой
Будете смеяться, но самое сложное в этом процессе — установить и настроить веб-сервер. В т.ч. и потому, что коллеги из Intersystems не очень-то казисто отработали.
Я в качестве такового уже много лет полагаюсь на Apache. При тысячах пользователей вполне приемлемый вариант. Соцсети и прочие нагрузочные развлечения с их nginx'ами выходят за рамки обсуждения. Cache' в первую очередь СУБД, а потом — все остальное. Но! Захотите отмасштабировать — легко. Если Вы прямо сейчас позвоните по номеру 8-800-2600-… то я сделаю для вас не только масштабирование, но и индивидуальный амулет-оберёг от багов и дэдлоков, настроенный исключительно на Вашу ауру.
Но к делу. На http://www.apache.org/dist/httpd/binaries/win32/ забираем файл httpd-2.2.22-win32-x86-no_ssl.msi. Здесь версия 22, но если Вам достанется более поздняя, не страшно, главное чтобы 2.2. Если у Вас уже есть веб-сервер Apache, этот шаг опускаем — Cache' минимально затрагивает настройки — об этом после следующей картинки. Любителям IIS могу предложить лишь самостоятельно развлекаться с настройками — я на этих страницах предлагаю простой путь, а IIS вечно отирается в парадных.
Девять кликов, дважды введенное "localhost", немного перьев и… самое сложное позади.
Следующий шаг в два раза проще. Но нам понадобится зарегистрироваться: http://download.intersystems.com/download/. Придется заполнить аж 11 полей и нажать шесть галок (нет хуже маркетологов, чем у лучших производителей СУБД), но искусство требует жертв:
Успели за 5 минут? Я тоже!
Хотелось бы тут сказать "вуаля" и повтыкать восклицательных знаков, ан нет — ребята из Интерсистемз (далее я буду ласково говорить "ИС") снисходительно позволили и нам продемонстрировать, насколько хорошо мы владеем напильником.
Находим файл C:Program Files (x86)Apache Software FoundationApache2.2confhttpd.conf
В самом его низу (помните, мы из подворотни пришли) находим страшную конструкцию вида
#### BEGIN-CSP-SECTION() ####
LoadModule csp_module_sa "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/CSPGateway/CSPa22.dll"
Alias /csp/ "C:/InterSystems/TryCache/CSP/"<Directory "C:/InterSystems/TryCache/CSP">
AddType application/x-csp .csp .cls .zen .cxw
AllowOverride None
Order allow,deny
Allow from all
</Directory>
#### END-CSP-SECTION() ####
#### BEGIN-CSP-SECTION(TRYCACHE) ####
Alias /trycache/csp/ "C:/InterSystems/TryCache/CSP/"
#### END-CSP-SECTION(TRYCACHE) ####
Оставляем от нее лишь
#### BEGIN-CSP-SECTION() ####
LoadModule csp_module_sa "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/CSPGateway/CSPa22.dll"
#### END-CSP-SECTION() ####
Немного ее приукрасив, получим:
#### BEGIN-CSP-SECTION() ####
LoadModule csp_module_sa "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/CSPGateway/CSPa22.dll"
<Location /csp>
CSP On
SetHandler csp-handler-sa
</Location>
#### END-CSP-SECTION() ####
Счастье — в простоте. Я, строго говоря, уже и не помню, в чем отличие. Но то, что вы видите в итоге — работает. И еще как работает. А то, что записывается по-умолчанию — глючит так или иначе.
Как остановить и перезапустить Apache, надеюсь разберётесь. Подсказка: ищем в трее красное пёрышко с зелёной стрелкой — оно реагирует на мышь, поверьте.
Ну вот мы и в Cache'!
«Тут раздался страшный треск.
Алиса упала на кучу валежника и сухих листьев.
Она ничуть не ушиблась и быстро вскочила на ноги.»
Л.Кэрролл "Алиса в стране чудес"
Вы себе не представляете, как приятно приветствовать Вас в Cache' через пять минут общения. Ну а если чуть позже, то за плохие "эти ваши интернеты" я не отвечаю.
Проверяем, что все работает: http://localhost/csp/samples/ZENDemo.Home.cls — наблюдаем гипно-треугольник? Значит, все ок. Браузер может попросить отображать SVG-содержимое — я разрешил и вам советую.
Уже увидели кубик в трее? Если нет, показываю (ищем справа внизу экрана):
Вот от этого самого кубика и будет происходить все дальнейшее. Но только если он синий. А вот если кубик серый — значит Cache' у вас не запустилось — вэлкам ту каментс.
Самое время простить разработчиков за скверную конфигурацию Apache и настроиться на позитивный лад. Тем более, что в ближайшее время они, разрабы ИС, нас более чем не подведут.
Например, на кубик Cache' как ни дави — правой ли кнопкою, левою ли — меню всегда одинаковое:
Вначале подглянем в портал управления системой. Я знаю пару компаний, в которых никто не умеет им пользоваться вовсе и при этом заведения процветают. Нам же от портала нынче требуется, чтобы он создал область для работы.
Различаем базу данных и область:
База данных Cache' (Database) — это файл на диске, записи в котором принадлежат нашей БД на том простом основании, что они находятся в этом файле.
Область (Namespace) — это определение в конфигурации Cache', в котором собрана информация о том, какими БД и для каких целей мы пользуемся. Область может брать программы из одной БД, а данные — из другой. Это одна из основ масштабирования в Cache' — просто и очень удобно. Изменив определение области я могу мгновенно переключить всех пользователей системы на работу с обновленными программами, но с текущими данными — что я и делаю раз примерно в две недели — подменяю версии всех программ, а пользователи этого практически не замечают.
Создаем область:
Здесь, кстати, как раз заметно, что для области глобалы (разучите это слово — так в Cache' называются хранимые данные) и программы могут браться из различных баз данных.
Поскольку мы хотим для новой области создать новую БД, вначале делаем это:
Далее "Далее", еще раз "Далее" и "Завершить" — БД создана, а мы вернулись к созданию области:
И вот:
Завершена следующая пятиминутка общения с Cache'. У нас теперь собственное приватизированное поле для экспериментов. Результатов все еще нет, но через пару-тройку минут мы с Вами воздвигнем что-нибудь — гарантирую.
Студию в студию!
«Но куда-то шильцем сунул,
Что-то высмотрел в пыли,
Внутрь куда-то дунул, плюнул, -
Что ты думаешь, – пошли!»
А.Твардовский "Василий Тёркин"
У Вас тоже руки чешутся что-нибудь выдать на-гора? Солидарен. Давим на синий кубик справа внизу:
Студия спросит нас о том, с какой областью мы будем работать — выбираем BS и жмем OK, пароль нам пока не пригодится:
Изначально Студия Cache' предстает перед нами в виде довольно сложной конструкции:
Но немного поработав с крестиками и перетаскиванием, можно добиться адекватного представления. "Инспектор", "Просмотр" и проч. нам понадобятся, но позже, а на следующей картинке подсвечиваю, как их включить (четыре кнопки вверху), в случае-чего. Мне удобно так:
В этом месте борьба между желанием продемонстрировать очередной "Hello world!" и соответствовать реальности программирования была выиграна последней — играем по-взрослому.
Откуда берутся программы?
«Пирамидка оказалась несложным, но очень занятным механизмом —
своего рода фиксатором, превращавшим иллюзию в реальность.
Нужно лишь придумать что-то, а затем включить пирамидку, и созданное
воображением становится таким же реальным, как окружающий мир..»
К.Саймак "Пересадочная станция"
Воображение, как мне кажется, превосходно помогает проектировать ПО. Но при постановке задачи нет худшего советчика — и очень важно об этом не забывать. Поэтому поступим просто. Воспользуемся одной из моделей Library of Free Data Models from DatabaseAnswers.org. Таким образом, опустим как этап постановки задачи, так и проектирования. В любом случае Cache' здесь не помощник.
Модель возьмем, к примеру такую.
Реализовывать предлагаю слева-направо и сверху-вниз. Ну или примерно так.
Классы — это наше всё. О разделах Студии "Программы", "CSP-файлы" и о "Другое" забудьте. Это для ребят, заинтересованных фасадом. И для уважаемых
пенсионеровветеранов Cache'.
Итак, создаем класс легким движением правой кнопки:
Следует заметить, что классы в Cache' располагаются в пакетах. Например, так:
С изобретением названий пакетов и их вложенности рекомендую быть очень осторожными. Бритва Оккама, как ее мне когда-то преподнесли, говорит о том, что не стоит приумножать число сущностей сверх необходимого. Однако немногие с этим справляются. Ведь труднее всего понять банальную идею — ее можно знать, уметь воспроизводить её различными органами, учить ей других, уметь использовать. Но не понимать при этом. Принципы Ле Шателье, Гейзенберга, Оккама и Бутерброда многие люди не смогут понять никогда. Ведь они уверены, что УЖЕ их понимают.
Итак, после запроса создания класса нам покажут соответствующий диалог:
Как же называть пакеты и классы?
Тут впору вспомнить о шаблонах проектирования. Когда претендент на собеседовании на вопрос "Какие шаблоны чаще используете?" отвечает: "Разные — вот, конвейер хорошо идет...", — сразу понимаешь, что перед тобой человек ответственный и готовый к рутине. И не готовый давать названия пакетам в Cache'.
Cache'-проектировщик должен всегда мыслить объектами предметной области (Domain Model, DM). Ночь. Улица. Фонарь. Аптека. Кому неймется использовать абстракции — просьба входить с парадного. У нас здесь всё по-простому — всяческие "регистры учета" мы традиционно доводим до жидкого состояния и сливаем в. В качестве компенсации за мучения типа "ну как же это обозвать, чтобы было в DM?" рано или поздно наступает совершенная синергия — система начинает отвечать адекватно на воздействия, к которым проектировщик ее не готовил.
Признак того, что Вы знаете этот шаблон простой: На половину новых запросов заказчика Вам ничего не нужно делать. Система ведет себя точно так же, как и реальный бизнес — процветает.
DM — это главный шаблон. И он же пригодится нам первым.
Еще одна небольшая ремарка:
Cache' предлагает не просто хорошую реализацию модели предметной области. Здесь очень лаконичными и удобными средствами обеспечивается инкапсуляция не только данных, но и поведения объектов предметной области в соответствующие классы.
Итак, обзываем:
И сразу же давим "Завершить". Дело в том, что после нажатия "Далее" Вам покажут совершенно бесполезную дополнительную форму, так что не хочу тратить наше время.
Вот именно так выглядит болванка класса в Cache':
Не знаю, как у вас, а у меня сердце замирает, когда я вижу подобные конструкции. Ничего лишнего. Нет этих дурацких "public static void main" и прочих include stdio.h — свобода!
При всей видимой простоте — тысячи строк системного кода, любезно предоставленного ИС, уже сейчас (после компиляции, разумеется) позволят работать с этим классом. Мы еще ничего не делали, но система уже умеет создавать его экземпляры, удалять их, выполнять запросы и многое, многое другое. Только потому, что он унаследован от системного класса %Persistent, который реализует хранение объектов и доступ к ним.
Но без данных это делать не очень разумно. Наполним наш класс свойствами (прямо внутри окошка используем правую кнопку мыши):
Также предлагаю сразу жать "Завершить". Кнопку "Далее" мы используем, но чуть позже.
Сверяемся со схемой. Осталось еще два свойства сущности "Место представления"- добавляются они точно так же по правой кнопке. Или с помощью "Ctrl-C + Ctrl-V". Затем предлагаю сразу скомпилировать класс:
Теперь проверим, что этот класс работает.
Вначале пощупаем его как объект. Для простоты сделаем это через терминал Cache'. Жмем на кубик в трее, выбираем "Терминал":
Получаем терминальное окошко с командной строкой Cache'. "USER" это область по-умолчанию. Можете порыться в настройках, чтобы изменить ее на "BS".
Но есть способ проще — команда смены области "zn". После перехода в нашу область создаем экземпляр класса, заполняем его свойства и сохраняем:
Узел: papahost, Экземпляр: TRYCACHE
USER>zn "BS"
BS>set obj = ##class(place.One).%New() // Не заботимся о конструкторе
BS>set obj.Name = "Шапито" // Не заботимся о сеттерах-геттерах
BS>set obj.Description = "На площадке у вокзала"
BS>do obj.%Save() // Не заботимся о том, как происходит сохранение данных
Не пугайтесь. Это только для проверки. В реальной разработке объекты появляются и сохраняются более цивилизованно. Об этом немного ниже.
Все наши объекты представлены также и как SQL-таблицы. Вообще-то доступов к данным несколько — можно работать с ними как с объектами (выше мы это попробовали), как с таблицами (об этом чуть ниже), и получать к ним т.н. "прямой доступ". О последнем я здесь вообще умолчу — не зная о нем вы мало потеряете, а захотите разобраться, думаю осилите.
Для SQL-доступа к данным на нашем кубике нужно выбрать "Портал управления системой", и перейти к SQL-запросам:
Далее:
1. Выбираемаем нашу область"BS"
2. Вводим запрос "select * from place.One"
3. Исполняем запрос
4. Видим строчку таблицы, куда отобразился сохраненный нами объект.
SQL-доступ позволяет в полной мере использовать обычный SQL-синтаксис. Можете поэкспериментировать, однако есть один совет: я не использую команды INSERT, UPDATE и DELETE на классах предметной области. Обработка триггеров и событий (например при сохранении) может отличаться. И весь труд вложенный в реализацию предметной области пойдет прахом при использовании этих команд. Вместо команд SQL мы будем использовать методы %New(), %Save(), %DeleteId().
Итак, надеюсь, что у Вас тоже все получилось. То есть мы создали класс с простыми свойствами и убедились в его работоспособности.
Первое приложение
«Фигура по плэйбою, бельё Коко Шанель,
И что ни девочка то просто новая модель...
Аллоу попс, скажу я не таясь.
Аллоу попс, я выхожу на связь.»
И.Лагутенко
Я точно не помню, в какой версии Cache' появился ZEN, но точно знаю, что для меня с этого момента сверхтонкий клиент стал окончательно единственным и безальтернативным клиентом для Cache'. Скажу больше — если во времена CSP (Cache Server Pages — технология из серии asp, jsp и т.п.) переход от задачи на CSP+Cache к задаче на PHP+MySQL и обратно происходил спокойно и ровно, то с ZEN'ом это уже не так — трудозатраты при использовании ZEN (и БД, реализующей предметную область) настолько смехотворны, что любой иной способ проектирования, разработки и сопровождения воспринимается как каторжные работы. В общем, как в том бородатом анекдоте — не используя ZEN в Cache' на новых задачах Вы поступаете либо глупо, либо подло по отношению к заказчику.
И я писал это дольше времени, чем сейчас потрачу на демонстрацию. Жмем "Создать":
Переходим в закладку "Zen" и выбираем "Новая Zen-страница":
Далее нам предлагается форма для ввода. Скажу честно — работая с ZEN уже более 5 лет, я вижу ее наверное, в третий раз. В основном для создания страниц я копирую код наиболее подходящей страницы ZEN, уже созданной когда-то и вношу нужные изменения. Но для первой страницы воспользуемся ею:
Вы уже поняли, что zen-страницы — это те же классы. И они так же упакованы в пакеты. Придумаем название:
И сразу же жмем "Завершить". "Далее" прошу не трогать — Вы попадете в место, в котором испытываешь некоторую неловкость за поставщика продукта. Должно получиться так:
Ого навалило! Когда я говорил о том, что не пользуюсь шаблоном, я имел в виду именно подобные эффекты. Приводим в порядок и компилируем (Ctrl-F7):
В принципе, мы приложение создали. Не видите "Hello, world!"? Я тоже. Но приложение готово к работе. Перейти к нему можно нажав глобус в меню (правее кнопки компиляции) или "F5". Но есть два нюанса:
1. Адрес для просмотра будет выглядеть как http://localhost:57772/csp/bs/zui.Places.cls — дело в том, что при установке Cache' развертывает на 57772 порту веб-сервер для своих нужд и почему-то пытается через него же демонстрировать наши успехи в Студии. Этот веб-сервер имеет ряд ограничений и использовать его нам нежелательно. Поэтому настроим отображение страниц из Студии в нашем Apache — для этого в меню Студии выберем "Проект" — "Настройки", а во вкладке "Дополнительно" появившегося окна зачистим порт (уберем все, начиная с двоеточия, чтобы вышло localhost):
После чего в меню Студии сохраним проект — "Файл" — "Сохранить проект".
2. Дело в том, что когда мы создавали область, для нее система создала csp-приложение (ZEN работает поверх csp). Доступ к вновь созданному приложению ограничен — нам предложат ввести имя и пароль. И это хорошо! Но на создание пользователя и назначение ему прав придется потратить немного времени. Ждем на кубик и открываем "Портал управления системой"
(и когда-же наконец ИС уберет раздел DeepSee… или уволит этого маркетолога — назло не куплю!)
Кнопка "Создать Нового Пользователя" довольно заметна — и особенно режет глаз человеку, немного знакомому с Русским Языком. Интересно, переводчик сего тоже сдавал по нему ЕГЭ? Не похоже, что как мы — по-старинке. О безопасности, случись что займетесь Cache', рекомендую озаботиться — как минимум вникнуть в "Стандарт настроек безопасности СУБД Intersystems Cache'" — иногда месяц работы одного технического писателя полезнее года мытарства команды разработчиков — текст критически полезный. Если найдете, где в Портале находится аудит безопасности — тоже обязательно исследуйте — расширяет кругозор.
Для целей же знакомства поступим просто — создадим пользователя с правами %All — то есть "All Inclusive" — разрешено все — ИС умеет дать вам почувствовать себя богом (иногда):
Вводим имя и два раза пароль — больше ничего руками не трогаем. Пока. Жмем "Сохранить" и переходим в закладку "Роли". Выбираем роль %All, и назначаем ее пользователю:
Должно получиться так:
Вообще-то, Cache' (и ZEN) отлично реализует подход "пользователь-роль-ресурс". Но боюсь, моего времени на это может не хватить — экспериментируйте сами. Получите массу позитивных эмоций. Надеюсь. Но вернемся в Студию и нажмем "F5" (или глобус). Введем имя и пароль на zen-странице, открывается наше первое приложение:
И опять же — ничего лишнего. Красота! Трудно представить, что эту восхитительно чистую страницу мог испортить своим присутствием какой-то "Hello, world!" (иностранный агент).
Опытный разработчик поймет, чему я на самом деле радуюсь — конечно же отсутствию ошибок. Она вертится! 90% работы сделано.
Первое работающее(!) приложение
«Сделать хотел грозу — а получил козу,
Розовою козу с желтою полосой.
Вместо хвоста нога, а на ноге рога.
Я не хотел бы вновь встретиться с той козой.»
Неизвестный автор
Эта часть должна получиться немного короче предыдущей. Что закономерно — создать шедевр в виде чистой страницы гораздо сложнее, чем подготовить форму для ввода и отображения мест цирковых представлений.
Помните, что один объект класса "Место представления" мы уже сохранили в БД? Займемся его отображением. Для этого нам понадобится компонент ZEN с именем "tablePane":
Здесь и далее буду размещать исходники, которые можно загрузить в Студию из меню "Инструменты" — "Импортировать локально".
Исходник: places1.xml
Скомпилируем и посмотрим, что получилось:
С лэйаутом проблемы, но это дело поправимое. Главное, что мы научились отображать данные. Теперь займемся их записью с пользовательского интерфейса. О реализации шаблона MVC (model — view — controller) в документации по ZEN написано много, но я не читал и Вам не советую — лучше покажу, как это работает.
Для начала, нужно наш хранимый класс унаследовать от %ZEN.DataModel.Adaptor:
Исходник: one1.xml
А в классе интерфейса добавить:
1. Контроллер
2. Форму с указанием, что ее данными занимается наш контроллер
3. Методы обработки событий (здесь метод сохраняет данные и обновляет таблицу)
Исходник: places2.xml
В браузере:
Добавим запись:
Надеюсь, у вас тоже получилось?
Для того, чтобы при выборе строки таблицы в контроллер подгружались данные объекта, нам тоже понадобится немного кода. Заодно добавим удаление, отступы и прочие приятности.
Исходник: places3.xml
Оглядывая свой текст начиная с последнего заголовка, ощущаю явный недостаток пафоса и нескромности — а ведь мы сделали это — научились работать с данными СУБД в сверхтонком клиенте с использованием AJAX и много еще чего. Практически не подозревая об этом.
Связи
«Тайным действием систем,
Скрытых под сознанием,
Жопа связана со всем
Божьим мирозданием.»
И.Губерман
Интерсистемз предлагает несколько вариантов связей между объектами, живыми из которых являются два — свойство типа объект и отношение "один-ко-многим". Заклинаю вас всем своим опытом работы с Cache' — не используйте ни в коем случае свойства-коллекции объектов, отношения "родитель-потомок" и прочие "реализации отношения один-к-одному". Я лично склонен относить ситуации, когда возникает подобная извращенная необходимость, к огрехам проектирования. Мне тоже жаль труд тех программистов, кто писал реализцию "родителя-потомка", но этот труд был пустой тратой калорий и бюджета. Мусор.
Использование отношений типа "один-ко-многим" и свойств-объектов позволяет просто и универсально решать все проблемы связывания в системе. Все — возьмем к примеру наш цирк.
В объекте "Places" диаграммы мы видим свойство типа "Иностранный внешний ключ" (забудьте о таких, если собираетесь работать с Cache'), именованное "place_type_code", ссылающееся на класс "Ref_Place_Types".
"Ref" как бы указывает на то, что мы имеем дело со справочником, но я противник использования понятия "справочник" — если только мы не имеем дело со справочником мер и весов или таблицами Брадиса. Любой объект, который мы по-глупости обозвали справочником (таблицей справочных значений), в какой-то момент может обрести поведение и справочником быть перестанет — появятся новые свойства и новая логика — и ограничения, накладываемые на т.н. "справочник" могут сильно навредить работе.
Так что просто создадим класс "Тип места представления". Я нажал на нашем place.One в иерархии классов Студии правой кнопкой мыши и выбрал "Копировать", после чего немного поправил код класса. Точно также я создал и интерфейс для работы с типами площадок.
Исходники: type1.xml, placeTypes1.xml
В браузере это выглядит так:
Теперь нам нужно определить свойство "Тип" в классе "Место проведения представления". Немного подумав можно прийти к выводу, что для нас нежелательно беспрепятственное удаление типов — хотелось бы чтобы при удалении типа выполнялась проверка, а нет ли мест удаляемого типа. Поскольку логику для этого писать лень, а ограничений на использование отношений не заметно, опишем связь как "один-ко многим". В Студии в классе place.One правой кнопкой мыши выбираем "Добавить" — "Новое свойство".
* Свойства "Places" пока что нет в классе place.Type — поэтому в форме я набрал его руками — Студия позаботится о его создании:
После чего в двух описаниях классов появились блоки отвечающие за отношение "один-ко-многим":
В place.One:
/// Тип площадки
Relationship Type As place.Type [ Cardinality = one, Inverse = Places ];Index TypeIndex On Type;
а в place.Type:
Relationship Places As place.One [ Cardinality = many, Inverse = Type ];
Компилируем.
Для того, чтобы организовать ввод поля "Тип площадки" на интерфейсе, воспользуемся новым zen-контролом (ищите dataCombo после полей ввода):
<text label="Название" dataBinding="Name" />
<text label="Описание" dataBinding="Description" />
<text label="Подробности" dataBinding="Details" />
<dataCombo dataBinding="Type"
sql="select ID,Description from place.Type"
sqlLookup="select Description from place.Type where ID = ?"
/>
В параметре sql мы указали контролу, как предлагать выбор пользователю, а в sqlLookup — как загружать данные из контроллера (например, при выборе новой строки в таблице).
Для отображения в таблице воспользуемся очень мною любимой возможностью неявного JOIN'а посредством "стрелочек":
<tablePane id="placesTable"
tableName="place.One"
onselectrow="zenPage.onSelectPlace()"
valueColumn="ID"
>
<column colName="ID" hidden="true" />
<column header="Название" colName="Name" width="20%"/>
<column header="Описание" colName="Description" width="30%"/>
<column header="Детали" colName="Details" width="30%" />
<column header="Тип" colName="Type" colExpression="Type->Description" />
</tablePane>
Таким же способом можно быстренько создать классы событий и их типов:
Исходники проекта: circus1.xml
Получившийся у меня интерфейс выглядит так:
Наступил момент, когда или нужно честно остановиться и подумать о следующей части или отложить — объем получился неожиданно большим.
Что я хотел сказать о Cache':
Мы получили мощное средство проектирования объектов предметной области, их связей и поведения. Не использовать паттерн "Модель предметной области" при работе с Cache' как минимум нерационально.
ZEN позволяет очень быстро переходить от проектирования БД к реализации GUI, что дает возможность выполнять сотни набросков и прототипов до появления продукта, удовлетворяющего заказчика.
Вчерашний студент воспринимает технологию за несколько дней. Через две недели написанный им код может запросто оказаться в продакшене.
Внесение изменений часто может не ждать очередного релиза — требования пользователя могут быть выполнены в пределах телефонного разговора. Часто пользователю для работы с измененным кодом не приходится использовать даже "F5".
О чем я не успеваю рассказать:
Наследование на уровне хранения — великолепный инструмент, предлагающий различные интерфейсы доступа к одним и тем же данным.
Неявный JOIN. Пример в тексте (и исходниках) есть, но мощь инструмента конечно не раскрыта.
И еще от автора:
Я не просто убежденный лентяй, я проповедник лени. Лениво сделанный код видно сразу — он краток, понятен, и очень эффективно делает именно и только то, для чего предназначен. Последний фактор немаловажен — часто программист обдумывает и пишет универсальный код, участь которого — до конца жизненного цикла системы не получать ровно ничего в запроектированной массе параметров и возвращать только два значения вместо нафантазированных программистом (хуже если аналитиком) сотен. Ленивого программиста также легко отличить — он жизнелюбив и эффективен. Он в курсе светских сплетен и NoSQL-холиваров. Он посещает театры и занимается детьми. Если он программирует, то лишь когда без этого никак не обойтись.
Некоторые утверждают, что заслуга Интерсистемз невелика — главное М-язык, глобалы и прочие радости бэ-деревянного зодчества (в первом варианте я тут опечатался по-фрейду, набрав раБости). Многие из наших программистов работают с Cache' не первый год и вовсе не знают команд работы с глобалами, о ужас!
Заслуга Интерсистемз для меня в том, что они дали возможность забыть о "повседневном М" — предложили использовать его лишь как специю, украшающую вкус совершенно иного блюда, с рецептами которого я и попробовал начать Вас знакомить.
Важная сноска: все вышесказанное неприменимо к Российским стандартам бухгалтерского учета — пресловутому РСБУ, отвратительному примеру того, как не нужно организовывать учет. Никогда не буду писать бухгалтерский софт. Сказал я себе 20 лет назад. Придерживаюсь. Нет в ларьке объекта "проводка"! Есть витрина, продавец, касса. До 22-х часов есть объект "спиртное". Но объекта "проводка" там нет. Разве что электропроводка.
Спасибо за внимание.
Автор: kolesov