Языки предметной области Domain-Specific Languages (DSL)

Что это?

Это некоторая форма компьютерных языков, разрабатываемых для специфичной предметной области. Это то, что позволяет вам (разработчикам ПО) лучше взаимодействовать с носителями “доменных знаний”. А так же позволяет более лаконично оформлять бизнес-логику. Это то, что представляет собой, к примеру, SQL, Linq, многое из синтаксиса Ruby On Rails.

Зачем мне это?

Если вы согласны с утверждением: “Языки общего назначения порой слишком красноречивы”, вы разрабатываете на .NET, либо сильно интересуетесь программированием, то наш доклад будет вам интересен.

Что я узнаю?

Ответы на следующие вопросы:

  • Что такое DSL?
  • Откуда это понятие пришло к нам?
  • Какие бывают DSL?
  • Какие “языки общего употребления (GPL)”  предоставляют возможности построения DSL? Какие из них есть на .NET?
  • Почему я должен использовать DSL? Какие плюсы от этого?
  • Какие шаблоны используются при построении DSL?
  • А можно увидеть примеры?

Материалы нашего выступления

Слайды презентации

Building DSLs on CLR and DLR (.NET)

Видео:

http://video.yandex.ru/users/thecoffee/collection/1/

Видео в более пригодном к рассматриванию надписей на доске качестве можно слить по ссылкам ниже:

http://narod.ru/disk/9278634000/01.wmv.html

http://narod.ru/disk/9279885000/02.wmv.html

Все рассмотренные примеры доступны здесь:

http://spbalt.net/Content/Baum_Moiseev_DSL.zip


Пример практики BDD при работе со Specter Framework

specter-log Specter – инфраструктура для составления объектно-поведенческих спецификаций для .NET. Он предоставляет возможности для обеспечения разработки, руководствуясь поведением системы (BDD), требуя от разработчиков написания исполняемой спецификации для объектов перед написанием самих объектов. Технически это ни чем не отличается от разработки по средствам тестирования (TDD), хотя различия в форме написания снимают психологический барьер для написания “тестов” для кода, которого ещё не существует. Есть множество проектов для различных платформ, реализующих данную идею (К примеру RSpec для Ruby, NSpec для .NET. Подробнее о средах здесь).

Specter использует возможности мета-программирования языка Boo (CLR .NET) для написания неплохо читаемых спецификаций.

Пример практики BDD при работе со Specter

Для нашего примера рассмотрим спецификацию мини-бара Бендера, она будет выглядеть следующим образом:

import Specter.Framework

import Bender

context "At Bender's bar":

   _bar as duck #our subject is defined in the setup block below

   setup:

     subject _bar = Bender.MiniBar()

   #one-liner shorthand

   specify { _bar.DrinkOneBeer() }.Must.Not.Throw()

   specify "If I drink 5 beers then I owe 5 bucks":

     for i in range(5):

       _bar.DrinkOneBeer()

     _bar.Balance.Must.Equal(-5)

   specify "If I drink more than ten beers then I get drunk":

     for i in range(10):

       _bar.DrinkOneBeer()

     { _bar.DrinkOneBeer() }.Must.Throw()

* This source code was highlighted with Source Code Highlighter.

Хотелось бы отдельно отметить возможность читаемости данного кода сторонними от программирования людьми.

Что же мы такое написали?

Всё очень просто, мы создали привычный нам по NUnit TextFixture Class и описали Test методы. Сейчас расскажу, как это получилось. Обратим внимание на следующую строчку:

context "At Bender's bar":

* This source code was highlighted with Source Code Highlighter.

Мы определяем некий context. Что же он из себя представляет? На самом деле, если полезть рефлектором в сборку, которую мы полчим, при компиляции спецификации, мы обнаружим, что данный контекст являет собой сам TextFixture Class:

[NUnit.Framework.TestFixture]

class EmptyStack:

* This source code was highlighted with Source Code Highlighter.

Далее посмотрим на:

setup:

  subject _bar = Bender.MiniBar()

* This source code was highlighted with Source Code Highlighter.

Это являет собой привычный нам SetUp:

[NUnit.Framework.SetUp]

 public void SetUp()

{

   subject _bar = Bender.MiniBar();

}

* This source code was highlighted with Source Code Highlighter.

Следующая интересная нам строчка:

specify { _bar.DrinkOneBeer() }.Must.Not.Throw()

* This source code was highlighted with Source Code Highlighter.

Является уже тестом:

[NUnit.Framework.Test]

public void BarDrinkOneBeerMustNotThrow()

{  

    Assert.DoesNotThrow(_bar.DrinkOneBeer());

}

* This source code was highlighted with Source Code Highlighter.

Аналогично следующие строки соответствуют:

specify "If I drink 5 beers then I owe 5 bucks":  

for i in range(5):

     _bar.DrinkOneBeer()

   _bar.Balance.Must.Equal(-5)

* This source code was highlighted with Source Code Highlighter.

Так же тестам:

[NUnit.Framework.Test]

public void IfIDrink5BeersThenIOwe5Bucks()

{

   for (int i = 0; i == 5; i++)

     _bar.DrinkOneBeer();

   Int32MustModule.Must(_bar.Balance, “Bar balance must equal -5").Equal(-5);

}

* This source code was highlighted with Source Code Highlighter.

И ещё одна строчка:

specify "If I drink more than ten beers then I get drunk":

   for i in range(10):

     _bar.DrinkOneBeer()

   { _bar.DrinkOneBeer() }.Must.Throw()

* This source code was highlighted with Source Code Highlighter.

Соответствует:

[NUnit.Framework.Test]

 public void IfiDrinkMoreThanTenBeersThenIGetDrunk()

{

   for (int i = 0; i == 10; i++)

   {

     _bar.DrinkOneBeer();

   }

   Assert.Throws((typeof(InvalidOperationException), _bar.DrinkOneBeer()); }

* This source code was highlighted with Source Code Highlighter.

Со спецификацией покончено, далее нам необходимо написать КОД нашего приложения, т.к. specter выругался о том, что спецификация не реализована:

minibar-result1[1]

Что же, реализуем наш мини-бар:

namespace Bender     

class MiniBar:

   pass

* This source code was highlighted with Source Code Highlighter.

И добавляем необходимый метод:

namespace Bender

class MiniBar:

    def DrinkOneBeer():

        pass

    [getter(Balance)]

    _balance = 0

* This source code was highlighted with Source Code Highlighter.

Но тем не менее specter не доволен, так как наш метод не реализует работу с балансом, описанную в спецификации:

minibar-result2[1]

Придётся добавить реализацию:

namespace Bender

class MiniBar:

    def DrinkOneBeer():

        _balance--
	if _balance < -10:
		raise System.Exception("i'm drunk")

    [getter(Balance)]

    _balance = 0

* This source code was highlighted with Source Code Highlighter.

По-моему specter’у всё понравилось:

minibar-result3[1]

Отлично, вот мы и попрактиковали BDD.

Итак, мы получаем привычные нам unit-тесты, однако мотивация написания немного измениться, а так же нами будет приобретена такая возможность, как предоставление specter-спецификации тестов в качестве документации. Мне кажется это отличная идея!

Ресурсы

О BDD почитать можно здесь:

http://habrahabr.ru/blogs/testing/52929/ (про BDD на русском на примере RSpec, в конце статьи есть ссылки)

Знакомство с Behavior Driven Development (BDD) (рус.)

Скачать Specter можно здесь:

http://specter.sourceforge.net/


Boo Programming Language

Slides from first meeting of spbalt.net group 25 Feb’09

View this document on Scribd


Boo 0.9 уже здесь!

Введение

 

Вчера Bamboo в своем блоге сообщил о релизе Boo 0.9. Стоит обратить внимание на то, что данный релиз заметно преображает язык, делая его более удобным.

Ключевые обновления

 

Основными “фишками” новой версии являются:

  • Генератор макросов [BOO-1077], который больше не ограничивает макросы возвращением единственного значения, либо блока, а позволяет возвращать неограниченное количество веток с помощью yield:
    macro printLines:
        for arg in printLines.Arguments:
            yield [| System.Console.WriteLine($arg) |]
        
    printLines "silly", "silly", "silly"
  • Nestable-макросы [BOO-1120] – описания макросов теперь могут быть вложенными, и поддерживают зависимости от контекста:
    macro given:
        macro when:
            yield [| print "given.when" |]
        yield 

    macro alert:
        macro when:
            yield [| print "alert.when" |]
        yield 
   
    given:
        when // given.when
    
    alert:
        when // alert.when
  • Макросы – как члены типа [BOO-415] – макрос может быть использован в описании тела типа:
    macro ThreadStatic:
        case [| ThreadStatic $name as $type |]:
            yield [|
                [System.ThreadStatic] static $name as $type
            |]
    
    class Environments:
        private ThreadStatic _current as Environment
  • Шаблон соответствия [BOO-1106] – простой, но мощный шаблон соответствия объекта с макросами match/case/otherwise:
   import Boo.Lang.PatternMatching
    
    def Eval(e as Expression) as int:
        match e:
            case Const(Value):
                return Value

            case InfixExpression(Operator: "+", Left, Right):
                return Eval(Left) + Eval(Right)
                
            case InfixExpression(Operator: "-", Left, Right):
                return Eval(Left) - Eval(Right)
  • Поддержка универсальный расширений методов (generic extension methods знакомых нам по C#) [BOO-937] – подобные LINQ расширения:
    import System.Linq.Enumerable from System.Core
    
    [Extension]
    def MakeString[of T](source as T*):
        return join(source, ", ")
    
    evenDoubles = range(10).Where({ i as int | i % 2 == 0 }).Select({ i as int | i * 2 })
    print evenDoubles.MakeString()
  • Общий параметр ограничений [BOO-935] и общий параметр вывода типа [BOO-1102]:
def Using[of T(System.IDisposable)](value as T, block as System.Action[of T]):
        try:
            block(value)
        ensure:
            value.Dispose()
    
    Using(System.IO.File.OpenText("TFM.TXT"), { reader | print reader.ReadLine() })
  • Строгий режим [BOO-1115] – строгий режим меняет некоторые правила компилятора: по-умолчанию все типы становятся private, параметры метода и возвращаемые значения должны быть обязательно объявлены
  • Ассиметричные свойства видимости доступа [BOO-1094]
    class Song:
        Name as string:
            public get:
                return _name
            internal set:
                _name = value
        ...
    def ToHex(n as int):
        return "0x${n:x4}"
    
    print ToHex(42)
  • Поддержка SilverLight [BOO-1117] – пример Владимира Лазунина с его Тетрисом, рабочий проект которого нуждается только в Boo.Lang.dll весит ~46 KB, а аналог, исполненный на IronPython подцепляет библиотеки DLR и весит в целом ~1.15 MB.

Материалы

 

Статья подготовленная по

http://blogs.codehaus.org/people/bamboo/archives/boo.html


Codeplex: Очередной Add-In для Reflector’а

Сегодня на Codeplex нашёл плагин, который позволяет рефлектору интерпритировать сборки в IronPython. Довольно таки интересно.

image

На рисунке интерпретирована сборка Boo в IronPython.

Ссылка на релиз http://www.codeplex.com/ipreflector.


Что такое ALT.NET?

Введение

По многочисленным WTF от коллег, хотел бы вкратце прояснить, а что же это такое. А дальше решайте сами, интересно Вам это или нет.

Содержание

 

ALT.NET — Альтернативные инструменты и подходы к разработке на .NET.

Инструменты и подходы перечислены ниже в табличке HOTorNOT.

Hot Not
Castle, ActiveRecord,
NHibernate
DataSets, Dataset Designer, Entity Framework, MS Application Blocks
MVC,NUnit,MonoRail Web Forms, SCSF, VSTS, MSTest
XP, TDD, Scrum MSF Agile, MSF For CMMI
Evolutionary Design and Development Big Design Up Front
Ruby + IronRuby, Python + IronPyton, DLR, Silverlight(?) ?
OR\M (NHibernate, LLBLGen  etc..) DLinq, Data Access Block, DataSets, Plain ADO. NET
Open Source (Mono, SourceForge) Application Blocks, CodePlex
MVC and MVP (RoR, MonoRail..) Web Forms, CAB, Smart Client Factory
CVS, SVN VSS, VSTS Source Control
Build Automation and CI
(CI Factory, NAnt, FinalBuilder, CruiseControl..)
Team Build
TDD and Unit Testing
NUnit, MbUnit, RhinoMocks, NMock, TypeMock
MSTest for unit testing, VSTS
Subtext, DasBlog, WordPress, TypePad, Blogger, FeedBurner Microsoft MSN Spaces, Community Server(?)
Simplicity in Design P&P
Working at Google Working at MS
Google Gears Smart Client, MS Ajax
.NET 3.X (WF, WPF. Silverlight) .NET 2.0
DI, IoC, Spring for .NET Object Builder
Conferences:
OSCon, RubyCon, Code Camps, DevTeach..
VSLive, TechEd, DevConnections..

Считаю, что необходимо как минимум ознакомиться со всеми перечисленными понятиями как в правой, так и в левой колонках, следуя принципу анализ-синтез-best practices.

Материалы по теме

 

  1. Табличка любезно позаимствована здесь http://weblogs.asp.net/rosherove/archive/2007/06/04/alt-net-alternative-tools-and-approaches-to-mainstream-net.aspx
  2. Страница сообщества ALT.NET http://altdotnet.org/
  3. Статья в журнале MSDN “Что такое ALT .NET?” by Джереми Д. Миллер (Jeremy D. Miller) http://msdn.microsoft.com/ru-ru/magazine/cc337902.aspx
  4. Активно развивающаяся группа ALT.NET на Yahoo Groups http://tech.groups.yahoo.com/group/altdotnet/

Обзор языка Boo! – как средства организации DSL Вашего приложения

boo-logo-128_med

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

В последнее время меня так и тянет насесть на какой-нибудь новенький язык программирования, особенно что-нибудь на типа Ruby или Python, но в связи с моей привязанностью среде разработки (Visual Studio, неверно это не очень хорошо – зависеть от IDE ;)) и затруднительной ситуацией с разработкой на ней на динамических языках (надеюсь это временное затруднение) от них пока пришлось отказаться. В то же время меня интересуют такие области как метапрограммирование и реализация DSL (Domain-Specific Language == проблемно-ориентированный язык приложения), и в этой связи видится мне, что Boo является весьма интересным языком. К тому же Boo — язык CLR, что очень даже не плохо для изучения.

Поэтому я решил, что когда я узнаю Boo и когда почувствую уверенность в Boo, я попробую реализовать DSL и реализовать именно на Boo для своего ближайшего проекта.

Что такое Boo?

Boo представляет собой open-source объектно-ориентированный статически типизированный язык программирования для CLR с Python’о-подобным синтаксисом, язык увидел свет в 2004 году из-под рук Rodrigo B. de Oliveira. В настоящее время последняя версия 0.8.2, но даже если нет еще версии 1.0, это действительно очень стабильной и зрелый язык, который можно использовать на производстве.

Основные концепции в Boo:

  1. Дать компилятору сделать большую часть работы, для того чтобы помочь языку выглядеть более динамическим с автоматическим объявлением переменных, выводом и приведением типов.
  2. В то же время он предоставляет возможности для выполнения статической компиляции, проверку ошибок во время компиляции.
  3. Boo также предоставляет функциональную составляющую в том, что функции могут использоваться в качестве возвращаемого значения, как аргументы, хранимые в переменных, а так же как объекты.
  4. Boo имеет первоклассные генераторы, это конструкций, способные производить более одного значения при использовании итерации цикла (“return a for a in apples if a.IsRipe”).
  5. Boo также поддерживает утиную типизацию (Duck Typing), которая позволяет отказаться от обеспечения безопасности статических типов и принимать любой объект, который просто имеет соответствующие методы и свойства, определяемые во время выполнения.
  6. Boo также имеет расширения методов и свойств (extension methods and extension properties).

Одним из наиболее интересных функций Boo является расширяемость процесса компиляции, которая позволяет управлять компиляцией и изменять или добавлять функции. Можно добавить подпрограмм для проверки конвенции кода, генерирования отчётов или преобразовывания кода. То, что Вы сможете сделать в C# с помощью тулзы посткомпиляции такой, как PostSharp и только ограниченный набор действий. В Boo Вы могли бы например автоматически преобразовать класс в одноэкземплярный (pattern Singleton), просто добавив атрибут следующим образом:

[singleton]
class MySingleton: pass

PostSharp просто не смог бы сделать этого, свойство экземпляра было бы обработано поздно. Это действительно открывает множество возможностей и Вы ограничиваетесь только Вашим пониманием внутренней функциональности компилятора и набора его возможностей.

В Boo пробелы имеют важное значение как в python, но есть возможность включить режим “Whitespace Agnostic”, позволяющий оканчивать выражение с помощью “end”, который избавит Вас от возможных проблем с пробелами.

Что нужно для начала работы с Boo?

Главным образом если Вы хотите узнать Boo, достаточно иметь последнюю версию Boo . В папке bin, Вы найдете файл “Booish.exe”, являющийся интерпретатором командной строки Boo, которая позволяет проиграться с синтаксисом языка.image

Для разработки нам необходима IDE, и следовательно у нас два варианта.

Большинство Boo разработчиков работают с SharpDevelop , и если Вы скачаете последнюю версию, в ней будет Boo полностью готовый к использованию. Эта IDE имеет преимущество, с точки зрения создания DSL, так как в ней легче добавить функции автозавершения кода и подсветки синтаксиса, в Visual Studio же потребуются написать лексер и парсер; в SharpDevelop можно сделать это с помощью XML-файла.

Но с другой стороны Visual Studio является зрелой IDE, и с BooLangStudio вы получите Boo интегрированный в Visual Studio. Люди жалуются, что проект является нестабильным и это лишь альфа выпуск, так же я встретился в нём с проблемами уникода (UTF8), которые пока не смог разрешить, но у меня пока нет весомых замечаний.

В настоящее время я буду пользоваться Visual Studio в силу привычки, но я могу изменить свой взгляд при продолжении этой статьи.

При написании данного поста я руководствовался данной работой, можно даже сказать переводил, но перевод очень личный и свободный.

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