Свой собственный domain workbench?

Наверное все уже так или иначе слышали о таких концепциях как DSL, domain workbench, language-oriented programming, и так далее. Мартин Фаулер даже готовит книгу на тему DSLей и как их «готовить». В этом посте я хочу рассказать про свой проблемы DSLей и domain workbench’ей (уж извините что на английском) а также начать рассказ про свое решение данной задачи.

Вступление

Для начала – немного терминологии. Домен – это область применения знаний. Математика, юриспруденция, строительство – это все домены знаний. Соответственно, люди которые обладают соответствующими профессиями (к пр. преподаватель математики) являются доменными экспертами. Доменные эксперты используют свои языки – например, математики используют формулы. А мы, разработчики, берем знания доменных экспертов и превращаем их в код. То есть если математик напишет

то разработчик должен представить эту формулу как

p = rho*R*T + (B_0*R*T-A_0-((C_0) / (T*T))+((E_0) / (Math.Pow(T, 4))))*rho*rho +
    (b*R*T-a-((d) / (T)))*Math.Pow(rho, 3) +
    alpha*(a+((d) / (t)))*Math.Pow(rho, 6) +
    ((c*Math.Pow(rho, 3)) / (T*T))*(1+gamma*rho*rho)*Math.Exp(-gamma*rho*rho);

Задача конверсии математики в код автоматизируется. Но это возможно не всегда – иногда, доменные знания записаны в такой форме, которая не позволяет автоматическую конверсию. А это наводит на мысль создания отдельного редактора, который позволил бы доменным экспертам записывать свои знания в форме, которая могла бы быть сконвертированна в код.

Такой редактор называется domain workbench. Точнее не совсем так – domain workbench используется для создания таких редакторов. На самом деле может быть и то и другое, и вопрос касательно того, что является domain workbench не имеет одного правильного ответа.

Разновидности

Вообще, если обобщить, то реализация доменно-специфичных языков имеет три основных типа:

  • Текстовые DSL, т.е. например нечто, что является текстом на английском (сорри!) языке, но де факто уже является программой. Примером может служить, например, использование F# для DSLей или использование Ruby для BDD (см. Cucumber).
  • Структурированные DSL тоже являются текстовыми, но имеют жестко определенную структуру. Иначе говоря, создание структурированного DSL это создание описания синтаксиса некого нового языка, который потом может использовать доменный эксперт. Примером реализации такого подхода может служить JetBrains MPS.
  • Графические DSL подразумевают создание визуальных редакторов для описания DSLей – при этом, код генерируется из текствого представления визуальной модели. Например, пользователь может визуально определить последовательность операций, и сгенерировать из этой модели код на основе Pulse & Wait (пример). Типичным приложением для создания графических DSL является Microsoft DSL Tools.

Все эти подходы оперируют простой идеей: доменный эксперт так или иначе начнет пользоваться таким, разработанным под него/неё приложением, передавать результаты разработчикам, и на основе этих результатов будет генерироваться работающий код программы. Да, и документация тоже будет генерироваться! Казалось бы, все выигрывают, не так ли?

На самом деле, мне кажется что использование доменными экспертами специализированного ПО в принципе невозможно. То есть, большинство экспертов не будут напрягаться с тем чтобы описывать свои знания в удобной нам форме – они будут продолжать использовать Word, Excel, Visio или какой там их излюбленный продукт. Что же остается нам в таком случае? Нам остается несколько вариантов, а именно:

  • Отказаться от идеи DSL и продолжать работать «как всегда»
  • Сконцентрироваться на автоматической конверсии из моделей экспертов в наши. Как показыват практика, это вполне возможно – например математические формулы из Word или блок-схемы из Visio вполне реально перевести в тот же C#.
  • Использовать DSLи и language workbenches только для наших, разработческих, целей, не привлекая к их использованию доменных экспертов

Может со мной кто-то захочет поспорить (а я люблю споры!), но мне больше всего импонирует последняя опция. Мы – разработчики, мы сами родили идею DSLей как «моста» между нами и определенной областью знаний, так почему мы должны зависеть от доменных экспертов? Ведь на практике, доменно-специфичные языки дают приемущества именно нам – разработчикам. Какие приемущества? Ну вот несколько

  • Более высокий уровень абстракции позволяет инкапсулировать те фичи, для которых иначе требовалось бы метапрограммирование, АОП, статическая кодогенерация или неудобное использование ООП/динамических прокси/шаманства
  • Модель является более полезной документацией чем CHM-файлик. Если модель и код находятся где-то рядом, любой участник проекта может быстро разобраться, как она сопоставляется с кодом.
  • Модель является неплохим артефактом при requirements elaboration. Ее можно показать заказчику в уже готовом виде и попросить откомментировать. Конечно, это получится не со всеми типами моделей.

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

Своя реализация

Я люблю графы. И как мне кажется, графовый движок (к пр. Microsoft Advanced Graph Layout) можно приспособить к реализации доменно-специфичного редактора. Ведь если посмотреть, например, на редактор Workflow Foundation, там тоже все из графов сделано – другое дело что там все не однородно, есть всякие сложные activity которые по-особенному выглядят, но это не важно – ведь графические движки расширяемы, и в тот же MSAGL вполне реально вклиниться со своим редактором.

Но давайте не будем забегать вперед. Для начала, вот небольшой пример применения графов в принципе:

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

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

Вот например, во что превращается прямоугольник с b*b? Это может быть инлайновое вычисление:

double SomeBigMethod()
{
  ...
  double temp_1234 = b * b;
  ...
}

Это может быть отдельный метод:

double bTimesB(double b)
{
  return b * b;
}

Или это может быть например просто функция:

Func<double,double> bTimesB = b => b * b;

Теперь то же самое насчет связок между компонентами – это синхронные вызовы? Асинхронные? У них есть триггеры? Ну и естественно такие вещи как политики исключений и обработки ошибок, проверка входных значений и т.п. тоже сюда привлекаются.

Заключение

Писать код в нодах никто не предлагает. Но с другой стороны, неплохо иметь ту же возможность что есть в некоторых UML-пакетах, а именно возможность делать double-click по ноду и получать пустое тело метода (это если нод мэпится на метод, конечно). Ну или аналогичный редактор.

Естественно, что не все концепты будут мэпиться напрямую на код – ведь иногда хочется иметь редактор который на 100% замещает код (у нас такое UI-дизайнерах повсюду). Для этого нужна всего лишь вменяемая модель расширений, т.к. например некий контрол, который мог бы «замещать» обычный текстовый нод в графе.

Вообщем, вот такая у меня концепция – это все еще пока вилами по воде писано, но если кто-то захочет внедрить подобное, я могу поделиться идеями реализации. Как и любой другое проект, этот будет казаться туманным и нереализуемым пока не начнешь им пользоваться. Именно таким мне казался TypograFix, но вот уже 2 года я использую его для статей и мне кажется он «окупил» себя полностью.

13 responses to “Свой собственный domain workbench?”

  1. Вот это “возможность определять алгоритм, например, как некую последовательность шагов” и концепт глобально – очень напоминает WWF. Чем ты занимаешься, что приходится решать такие непростые задачи?

    1. Ну например при построении TypograFix алгоритм типографирования текста – это жуткое месиво с maintainability index == 0 :) А вообще сложных задач много, и хочется как-то систематизировать подход к их описанию.

      1. На счёт TypofraFix – ну я думаю можно попытаться это отрефакторить, понаделать синтаксических примочек и уже всё будет не так печально. Думаешь стоит для такой задачи строить DSL?

      2. Конкретно для этой – да, т.к. уровень сложности просто зашкаливает. Если не веришь, глянь сам метод Transform() в файле Generator.cs.

  2. Дмитрий, в коде TypograFix часто встречается строки вида

    text = “|{0} link|”.ƒ(text);

    Что это за магический extension ƒ()?
    Откуда такой странный символ? И студия его не понимает.

    1. Привет, есть такое зло. Попробую объяснить в чем проблема. ƒ – это необычный символ т.к. его выдает IntelliSense даже если вы печатаете f. Я использую метод ƒ() для fluent-аналога string.Format(). Проблема в том, что некоторые файлы не сохранены в UTF-8, и в результате вы на вашем конце получаете ошибки в этих файлах. Если вы скажете мне, что это за файлы, я пофиксю и залью их на сервер.

      На самом деле, использование магических символов в VS это еще та тема, она наверное на отдельный пост тянет :)

      1. Generator.cs
        MainWindow.xaml.cs

      2. Хмм, оба из них уже UTF-8. А это означает что это баг Mercurial. Или же BitBucket тупит.

  3. Я что-то недопонимаю. “Использовать DSLи и language workbenches только для наших, разработческих, целей, не привлекая к их использованию доменных экспертов” Зачем вообще использовать DSL и language workbenches, если мы не привлекаем доменных экспертов?
    DSL как раз должны использоваться доменными экстпертами как конечными пользователями. Разве не так?

    1. Совершенно не обязательно, DSL нужен в первую очередь для более удобного описания домена, чем язык на котором Вы программируете. Доменных экспертов можно использовать, чтобы выработать этот язык, не обязательно потом заставлять использовать.

      1. Наверное, для разработчика описание домена будет ближе на языке разработчика, а не доменного. Я думаю, что DSL нужен именно доменным экспертам. А полученный программный продукт они используют в своих целях с использованием своего языка.
        Также тут есть такой аспект. Сможет ли разработчик без доменного эксперта корректно трансформировать DSL в алгоритм? Скорее всего такая конверсия должна контролироваться со стороны доменного эксперта.

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

    2. Воооот. Я именно про это. Забиваем на доменных экспертов ибо с ними все равно не скооперироваться. Думаем о себе любимых. Ведь нам несмотря на всю мощь языков и платформ порой не хватает именно генеративных решений. Поэтому я и предлагаю DSLстроительство для наших, кодерских целей.

Оставить комментарий