суббота, 7 сентября 2013 г.

Куда может завести "свой DSL". Часть 1. Контекст.

С некоторым удивлением обнаружил, что тема «своего собственного» DSL довольно популярна в блогах, да и в интернете вообще.
Из последних публикаций, которые обратили на себя моё внимание могу назвать эту и эту.
Но поиск в Google, понятно, выдаст настоящую картину.

Здесь, думаю, следует оговорится, что я имею ввиду, когда говорю «свой собственный» DSL.
Нет, речь идёт не о текучих интерфейсах и не о всепроникшем XML.
Речь идёт о настоящем языке, для которого реализован собственный интерпретатор, или построенного на базе приспособленных для этой цели Forth/Lisp.

Читая восторженные реляции по поводу такого подхода, не могу отделаться от мысли, что где-то я это уже слышал. В году эдак 1992-м...
Нетрудно вспомнить даже, от кого. От себя самого :-)

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

…О! Я помню времена, когда отчёты создавались с использованием Pascal.
Тогда это был Turbo Pascal, ребрендинг на Borland ещё не случился. У нас в городе, по крайней мере. Это сейчас можно зайти в интернет и скачать (в идеале — купить) новую версию. Тогда имел место заметный временной лаг... Но я не буду отклоняться от темы.

Итак, был 1990 год, ещё был СССР, пребывавший в терминальной стадии «Перстройки».
Новые правила требовали «новой бухгалтерии», а чуть ли не главным артефактом бухгалтерии тогда (м.б. и сейчас - я далёк от этой темы) были отчёты.
У нас были данные в БД проприетарного, не совместимого ни с чем формата, были формы ввода, описанные в коде, мы работали со структурами данных (бинарными деревьями) напрямую, разумеется, у нас был набор модулей, позволявших генерировать тексты, которые затем можно было распечатать на матричном принтере, который стоил пол-«Запорожца».

Я помню, как отдавались задачи на реализацию.
Ко мне подходил коллега (который весьма далеко пошёл, к слову), брал у меня исходные тексты (сети уже были, IOLA – если кто помнит, и Novell, но нашей организации они были не по карману) и шёл писать код.
Через пару дней (иногда — больше, поскольку отчёты были разной сложности), он выдавал готовый отчёт, который я подключал к проекту, собирал его, и в проекте появлялась новая функциональность.

Так продолжалось достаточно долго, по нынешним меркам — год или два. Сейчас уже трудно точно сказать — сколько времени прошло.
Кстати, я тоже тогда был весьма молодым человеком, просто специализация у меня была другая. Зачем я это пишу? - Для того, чтобы обозначить контекст тех событий, которые случились позже.

В какой-то момент на семинарах (в нашей организации были семинары) стали появляться темы, связанные с генератором отчётов. Слушал я «вполуха», поскольку своих проблем было предостаточно. Но кое-что вспомнить (восстановить) могу.

К тому моменту мы уже использовали реляционную СУБД без SQL. Да, так бывает :-)
В качестве СУБД использовалась отечественная разработка - HyTech, которая жива и сегодня. К слову - неплохая вещь была, особенно, по тем временам. По скорости выполнения проекций она и сегодня даст фору любому Oracle, правда на тех объёмах которые она поддерживала - 16 млн. записей. Инвертированные файлы - это серьёзно. Для тех задач, где их можно применить ;-) Не для СУБД... :-)

Одной из неприятных проблем, с которыми приходилось сталкиваться при разработке отчётов было то, что Pascal, вообще-то, не очень подходит для генерации и обработки текста.
Все такие задачи, сводящиеся к «жонглированию» строчками, в реализации оказывались непростыми, особенно, если вспомнить, что предоставлял из себя Pascal тогда.
К вашим услугам была конкатенация строк, вставка, удаление символов и «гениальная» функция Pos, которая могла искать только с начального символа строки, длина которой была ограничена 255 символами.
Негусто. Никаких вам параграфов «бесконечного размера». Форматирование? - Реализуйте сами. Ну, мы и реализовали. Много чего нареализовывали.
Я это к тому, что задачи форматирования текста и его разбиения на страницы, с колонтитулами, с итогами по странице, вкупе с ограничениями на количество оперативной памяти 640 KB «реального» режима, при немалом размере оверлейного приложения и постоянной «паранойи» относительно количества используемой алгоритмами памяти, оказывались весьма непростыми в реализации.

В какой-то момент возник совершенно справедливый вопрос. Как так получается, что задачи, которые описываются сравнительно ограниченным набором понятий:
  • Абзац
  • Шаблон (некий аналог макета — того, что можно за пять минут сделать в любом интерактивном дизайнере отчётов)
  • Страница (с нумерацией, колонтитулами и итогами)
приводит к таким (существенным) затратам труда при реализации?

Чтобы стали понятны некоторые детали "той логики", мне нужно кое-что пояснить.
Как я сказал уже выше, разнообразие функциональности по работе со строками в Pascal было не очень большим, с PChar работать было вообще неудобно, если не сказать - опасно, ввиду чего работа с абзацами (тогда мы не использовали этот термин, вообще, система понятий была несколько иной, я вынужден подбирать нечто похожее из современного, чтобы не утомлять читателя) "заворачивалась" в классы-обёртки, но всё равно, возни с форматированием было намного больше, чем бы хотелось.
И мы были вынуждены экономить память. Жёстко, брутально.
Когда памяти мало, она начинает фрагментироваться (понятно, что связь - непрямая) и становится совсем худо.
Постоянные мысли о необходимости экономить приводили к тому, что для нас дикостью выглядело формирование абзаца целиком в куче, после чего его можно было бы подставить, скажем, в ячейку таблицы. - Нет, это привело бы к необходимости перераспределения этой кучи при достижении границы текущего отведённого под хранение абзаца блока, фрагментации и... Ну понятно, в общем.
Поэтому мы видели формирование отчёта исключительно по строкам. Сверху-вниз. Строка за строкой. И так до конца страницы, когда управление должно было быть передано коду, занимающемуся формированием нижних колонтитулов, в которых должны были отображаться пресловутые итоги по странице.
Разумеется, при появлении новой страницы, сначала "печатались" верхние колонтитулы. Когда появлялась новая страница? - А когда производилась попытка вывода в неё первой строки.
Ну понятно, что строка таблицы и строка отчёта - разные вещи. Приходилось "крутиться". В частности, с итогами по странице, которые уверенно "пили кровь". Но они встречались нечасто, что и спасало.
DPMI же стало возможным использовать только через год или два, когда до нас дошла техника, где стало возможным его применение. Это - существенно.
Ну и, кроме всего прочего, бытовала уверенность, что формирование отчёта по строчкам текстового файла - это адекватный подход к генерации отчётов.
Эх... Было бы возможным вернуться в то время, я бы смог убедить себя самого, что лучше уж было применить буферизацию и хранить формируемые абзацы во временных файлах (если они становились бы слишком большими), поддержать таблицы в явном виде, т.е. в виде соответствующих классов: таблица, колонки, строки, в которые можно было бы вставлять абзацы... Но... Время анизотропно... :-)
Ладно, на суть того, что я хочу донести, это не влияет ни в малейшей степени. Даже лучше, что получилось так, как получилось.
Итак, я надеюсь, что дал некое объяснение тому, почему решено было формировать отчёт по строкам текстового файла, который и был результатом выполнения отчёта.

Но удобным форматированием вкупе с построчной генерацией отчётов наши пожелания не исчерпывались.

Неудобным было пересобирать приложение при подключении/или изменении реализации отчёта. В рамках реализации их с помощью модулей на Pascal проблема не решалась.
Экзотические пути с реализацией отчётов в виде отдельных исполняемых файлов мы отбросили и, я считаю, что правильно сделали.

Наконец, была вожделенная мечта. Дать возможность конечному пользователю самостоятельно составлять отчёты, в которых он испытывал потребность.
Квалифицированные пользователи (как правило, это были администраторы) были всегда. Ну, по крайней мере, в среде наших клиентов. Иногда были даже целые отделы программистов.
Но если отчёты - равноправная часть программы, то пользователю придётся отдавать её исходный код, что по ряду причин - совсем не comme il faut. И дело даже не в наших "секретах". Создавать отчёты - одно, а вмешиваться в логику приложения, к чему пользователь, по факту, получал бы доступ в таком случае - это виделось неприемлемым как тогда, так и сейчас.

Итак, как виделась задача тогда.
Проблемы, которые следовало решить в контексте "нового" генератора отчётов:
  1. Удобное форматирование текста, основанное на шаблонах. Так, чтобы не приходилось возиться со строками.
  2. "Прозрачное" разделение на страницы с поддержкой колонтитулов и итогов.
  3. Отделение реализаций отчётов от основного приложения
  4. Обеспечение возможности пользователю создавать свои отчёты и, при необходимости, вносить изменения в отчёты, реализованные нами (компанией-разработчиком)
Вся совокупность означенных требований хорошо ложилась в концепцию собственного специализированного и очень простого языка программирования, который посредством использования естественных понятий предметной области (генерация отчётов по реляционной БД) позволит с минимальными затратами труда создавать прекрасные отчёты, в некоторых случаях освобождая наших сотрудников от этой рутины, путём привлечения к созданию отчётов самого клиента.
Такой язык был создан.

Продолжение следует...

35 комментариев :

  1. "Я это к тому, что задачи форматирования текста и его разбиения на страницы, колонтитулами, итогами по странице, вкупе с ограничениями на количество оперативной памяти 640 KB «реального» режима при немалом размере оверлейного приложения и постоянной «паранойи» относительно количества используемой алгоритмами памяти, оказывались весьма непростыми в реализации."

    Примерно в то же время, и в тех же 640 К был написан текстовый редактор, который редактировал мегабайты текста :-) вполне успешно.

    ОтветитьУдалить
    Ответы
    1. Да, это Multi-Edit, мы его использовали для редактирования исходных текстов.
      Насколько мне известно, там использовался тот самый принцип буферизации с временными файлами, о котором я упомянул в контексте альтернативного подхода, основанного на абзацах и таблицах...

      Удалить
    2. «И не только Multi-Edit :-)»
      -- Другие мне просто неизвестны.
      Multi-Edit был идеален в частности, потому, что там был встроенный язык, позволявший создавать макросы.
      Кстати, г-н Гурин, популяризовавший DeCAL стал мне известен по выпускам SoftPanorama, как раз, по своей фантастической библиотеке макросов для Multi-Edit...

      Удалить
  2. Но HyTech это ведь не 92-й год? И тем более не 90-й? Ближе к 94-95-му мне кажется. Да?

    ОтветитьУдалить
    Ответы
    1. HyTech v1.6, боюсь соврать конечно, был доступен уже в 1993 году.
      Там ещё был резидентный модуль, который хорошо объедал память, в конечном итоге компания "СКАЗ-М" от него отказалась.
      В HTW32.PAS содержится текст: "HyTech 2.51 Copyright (c) 1993, 99 by SKAZ_M Ltd".

      Удалить
    2. Ну вот я и думаю, что речь о событиях никак не раньше 93-го года.

      Удалить
    3. Точнее, именно 1993-й :-)

      Удалить
    4. "HyTech v1.6, боюсь соврать конечно, был доступен уже в 1993 году."

      В виде obj? Или как?

      У нас уже была dll, но позже.

      Но по-моему в 93-м dll не было? Или были уже?

      Удалить
    5. «Это ведь Windows уже?»
      -- Конечно :-)

      Удалить
  3. https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B1%D0%B0%D0%B7%D0%B0%D0%BC%D0%B8_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85

    "Занятное" там обсуждение :-(

    ОтветитьУдалить
    Ответы
    1. Да, занятное. Я бегло проглядел.
      Чтож, каждая точка зрения имеет право на существование.
      Но всё же в Википедию я бы HyTech пропустил.
      Там не только "интересный формат хранения", но и очень хорошие показатели производительности при минимуме потребляемых ресурсов.
      К сожалению, адекватным образом поддержать SQL разработчики так и не сподобились, что негативно сказалось на популярности СУБД.

      Удалить
    2. "Но всё же в Википедию я бы HyTech пропустил."

      -- я бы - тоже.

      "К сожалению, адекватным образом поддержать SQL разработчики так и не сподобились"

      -- ИМХО не SQL'ем единым... HyTech и без SQL вполне себе хорош.

      Удалить
    3. «"К сожалению, адекватным образом поддержать SQL разработчики так и не сподобились"
      -- ИМХО не SQL'ем единым... HyTech и без SQL вполне себе хорош.»
      -- Да что в нём хорошего...
      * API такой, что шаг влево, шаг вправо - AV.
      * Операцию соединения они поддержали так, что я одно время был единственным в фирме, кто имел представление о том, как она работает...
      * При интенсивном изменении данных требовалась подкачка данных из журналов в постоянную часть чаще, чем раз в день.
      * Для корректной работы транзакций требовалось синхронизация времени на всех компьютерах, работающих на одну БД. Если это не достигалось - вплоть до потери данных доходило.
      Сколько возни с этим было...
      * Для того, чтобы добавить большое количество записей приходилось использовать отдельное API - пакетные операции.
      * "Магические" значения в полях таблиц, что приводило к ошибочной идентификации записей как удалённых.
      * Отсутствие регистронезависимых индексов по строкам.

      И это ещё не всё...
      Самое неприятное - то, что используя HyTech мы опасно отдалились от мэйнстрима.
      Настолько отдалились, что не было возможности использовать существующие наработки в мире Delphi.
      Чтобы "разрушить Карфаген" пришлось поддержать DataSet/Connection для HyTech, а там было столько "прелестей"...

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

      Удалить
    4. "Для корректной работы транзакций требовалось синхронизация времени на всех компьютерах, работающих на одну БД."

      ;-)

      Удалить
    5. "существующие наработки в мире Delphi"

      ах как мы классно "развлекались" с OWL до Delphi... до сих пор с содроганием вспоминаю...

      Правда там было "светлое пятно" - Data Entry Workshop. От Turbo Power. Но и тот - не без вопросов.

      Удалить
    6. "DataSet/Connection для HyTech, а там было столько "прелестей"..."

      Знакомо :-) Но "в серию" это пускать не стали.

      Удалить
    7. «ах как мы классно "развлекались" с OWL до Delphi... до сих пор с содроганием вспоминаю...»
      -- Нет, до OWL мы, к счастью, не дошли.
      Остановились на доработанном Turbo Vision.
      Кстати, у нас был его графический вариант, который мы "в серию" не пустили, поскольку не увидели в нём смысла. Смысл в конце 2000-х нашли в Embarcadero...
      Я про FireMonkey с идеей самостоятельно всё нарисовать :-)

      Удалить
    8. "Кстати, у нас был его графический вариант, который мы "в серию" не пустили"
      -- вы про свои разработки или про Super Vision?

      Удалить
    9. «"Кстати, у нас был его графический вариант, который мы "в серию" не пустили"
      -- вы про свои разработки или про Super Vision?»
      -- Про свои конечно. Super Vision тогда ещё не было, как и интернета, по которому его можно было скачать.

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

    Это мы сделали, но уже в 95-м году :-)

    ОтветитьУдалить
    Ответы
    1. Не.. В 94-м. В 95-м у нас уже эра Windows началась и я туда наработки портировал.

      Удалить
    2. Да мы тоже сделали. Точнее - я. Но в контексте совсем иной задачи, не генератора отчётов.
      Ну и думаю, что то, что мы (я и Вы) делали - суть очень разные вещи, поскольку цели были разными, хотя и набор понятий - похожий...

      Удалить
    3. «Не.. В 94-м. В 95-м у нас уже эра Windows началась и я туда наработки портировал.»
      -- Эра Windows в нашей предметной области началась несколько позже.
      Году эдак в 1996-97-м. Проблема была в том, что у заказчиков было очень много старой техники, на которой либо был DOS, либо Windows2, но на грани минимальных требований к оборудованию.

      Удалить
    4. "Ну и думаю, что то, что мы (я и Вы) делали - суть очень разные вещи"

      Ну я "по жизни" делаю "текстовые редакторы". Во основном. :-) Всё остальное - "вокруг" них.

      Удалить
    5. "либо Windows2"

      Именно Windows 2, а не 3? ;-)

      Занятно. Я Windows 2 видел на "экспериментальной" буржуйской технике. Для управления ферментёрами. Больше - не видел.

      Я тогда был - "несколько" шокирован.

      Удалить
    6. «"либо Windows2"
      Именно Windows 2, а не 3? ;-)»
      -- Просто Windows :-) У меня на русский переключается комбинацией Ctrl+2. Нет-нет, да "паразитическая" двойка в текстах появляется...
      В то время "в ходу" был Windows 3.11 и Windows 95 OSR2. Причём последний ставили даже в условиях, для которых он точно не был приспособлен...

      Удалить
  5. "при немалом размере оверлейного приложения"

    Я что-то путаю, или оверлеи к тому моменту были "отменены"? После TP 4.0.

    Просто я сам пытаюсь вспомнить - у нас вроде тоже были оверлеи. А википедия говорит - уже "отменили".

    ОтветитьУдалить
    Ответы
    1. «Я что-то путаю, или оверлеи к тому моменту были "отменены"? После TP 4.0.»
      -- И да и нет :-)
      Насколько я помню, Turbo Pascal v4.0 не поддерживал оверлеи.
      Turbo Pascal v5.0 и выше - снова поддерживали.
      С оверлеев мы перешли на DPMI, это было, по-моему, уже после 1994 года.

      Удалить
    2. "Turbo Pascal v5.0 и выше - снова поддерживали"

      Ах вот оно что! Точно! Значит - не путаю.

      На DPMI мы тоже перешли :-) И удивились количеству AV в коде :-) До тех пор мы же не знали про AV ;-)

      Удалить
    3. «На DPMI мы тоже перешли :-) И удивились количеству AV в коде :-) До тех пор мы же не знали про AV ;-)»
      -- А так у всех :-)

      Удалить