Наверное все уже так или иначе слышали о таких концепциях как 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 года я использую его для статей и мне кажется он «окупил» себя полностью.
Оставить комментарий