Release of a DSL for the Gamma et al. Design Patterns


Hi folks,

I have written a DSL for the Gang of Four design patterns.

If any of you are interested in taking it for a spin, you
can get the source and doc from:

   http://www.clipcode.biz/workshops/dsl.html

Enjoy,

Eamon O'Tuathail
Clipcode Knowledge Services
mailto:eamon.otuathail@clipcode.biz
http://www.clipcode.biz



Answer this question

Release of a DSL for the Gamma et al. Design Patterns

  • Grwilhelm

    Interesting - I just tried it and


    <p>Built: <#=BuildSomeStuff()#></p>

     

    also works for me.
    I wonder what's different about your environment


  • turbofreddan

    Eamon - great examples and interesting points about text templating engine.  We're looking into enriching th editing experience for a future release.

    Allowing boilerplate text inside functions would be very nice - we're not sure whether we'll have time for it as it complicates one or two other things.

    However, you can emit strings in functions without returning them by using this.Write, this.WriteLine which have a few overloads.  Have a look at the interface to the class

    Microsoft.VisualStudio.TextTemplating.TextTransformation
     
    -There are also some error and warning methods for your convenience

    You should be able to call functions from within <#= blocks #>
    I just tried the following successfully:

    <#+
    private string BuildSomeStuff()
    {
       return "a" + "b";
    }
    #>
    <p>Built: <#=this.BuildSomeStuff()#></p>


     



    We're looking into revamping the way you execute T4 across a set of model files and template files to make your scenario simpler for end-users of a tool you build.



  • Dan DeLaf

    Wow! Amazing...

  • PCM2

    Nice work Eamon!
    I wrote some comments here.
    Claudio

  • Albatetra

    Hi,

    I have read the Software Factories book and am trying to get the feel of this very exciting and promising initiative through the samples/walkthroughs. I found your work when I signed in the forum.

    From the looks of it, it is a nice work Eamon. However, I am encountering errors using the Feb2006 release of the tools that are integrated with VS SDK already. It can't seem to recognize the "ProvideItemTemplate" attribute in the ClipcodeGoFDSLPackage.cs file.

    Would you happen to know if this was moved to another namespace Or was the name changed

    Thanks for any help,

    Emil Valdez


  • Cristiano Leite

    Microsoft has released the March 2006 CTP for Visual Studio SDK (which now incorporates the DSL Tools bits):

    http://msdn.microsoft.com/vstudio/extend/default.aspx

    and I have updated my GoF design pattern DSL to use it:

    http://www.clipcode.biz/workshops/dsl.html

    Enjoy,

    Eamon


  • Brachole

    Here are some general points regarding DSL construction. 

    < xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 

    When building your domain model (.dsldm), make sure you understand the meaning of the Accepts property for elements that will provide parenting for others.

     

    At the moment, there is no graphical tool to build the domain designer (.dsldd). You  should spend the time to learn the internal schema of the DSLdd. Even when graphical tools arrive in future, the more you know about the underlying technology, the better.

     

    Writing the templated code is a bit of a pain. Once the Microsoft folks are finished writing the dsldd design tool, I suggest they look at improving the developer experience for writing the templated code.

     

    Through the template generator can be used to generate any kind of textual artefact, mostly it will be used for C# and XML files. Hence specific richer support for these is needed. I reckon the templating constructs (“,< #”, “<#=” etc.) should be made part of the C# spec, and Intellisense could be improved to work directly with it (colour-coded template files would be nice). Also, the debugger should be improved to directly debug templated code. One the size of the template code goes beyond a couple of pages, this issue moves from “nice to have” to “very important”.

     

    I maybe wrong here, but there does not seem to be any way to inject text into the generated file from template functions. For example, for Clipcode-GoF-DSL, I need to output the class preamble which is slightly different depending on whether the class inherits or not. What would be nice is to create a function GenerateClassPreamble that takes in relevant parameters, has its own internal logic, and outputs what is needed. Unfortunately, “<#= … #> blocks do not seem to work within functions – is this correct This means functions must return strings (etc.) and the main code must output the text.

     

    Another important problem is that we are not able to call functions from within <#=… #> blocks. So we must call the function from within <# … #> blocks and store results in local strings, and use these local strings from within <#= … #> blocks.

     

    All this leads to cut-and-pasting of lots of code and minor modifications, and the resulting template code is not pretty.

     

    At the moment we need one template controller file per model instance. Using the “<@ include file” construct means this can be minimised, with the common template code put externally, shared by all model instances. I wonder can we go one step further, and eliminate the “ReportTemplate” file altogether. For a particular domain model, the ReportTemplate file will be the same for each model instance, except for the different model instance filename. I wonder should there be a way in future to associate a ReportTemplate file with the model, and let it take in the model instance filename as a parameter.

     

    There does not seem to be any way to have multiple toolbox compartments.  If you end up with lots of toolbox icons, this becomes an issue.

     

    Eamon


  • Tim Landgrave

    Hi Eamon,

    This is a great piece of work. I had some issues with the Designer project, buut soon found out that it can be fixed very easily. I am sure you fixed it for March CTP, but I installed the latest April CTP. But, the solution to the problem is easy, as stated in the VSIP docs.

    Migrating Domain-Specific Language Tools Projects Generated with the November 2005 CTP

    To migrate any projects that you generated using the November CTP of Domain-Specific Language Tools, follow these instructions:

    1. On the File menu of Visual Studio 2005, click Open, and then click File.
    2. Browse to the Designer folder in your DSL Tools solution.
    3. Click Designer.csproj, and then click Open.
      The XML editor opens with the contents of your Designer.csproj file.
    4. Locate the line that contains the following text:
      <Import Project="$(ProgramFiles)\Visual Studio 2005 SDK\2005.10\VisualStudioIntegration\Tools\Build\Microsoft.VsSDK.targets" />
    5. Replace it with the following text (change is highlighted in bold text):
      <Import Project="$(ProgramFiles)\Visual Studio 2005 SDK\2006.02\VisualStudioIntegration\Tools\Build\Microsoft.VsSDK.targets" />
    6. On the File menu, click Save Designer.csproj, and close the XML editor.
    7. Load your DSL Tools solution as usual.

    NOTE: In the point 5., make sure you put the correct folder. 2006.02 is FEB CTP, 2006.03 is March CTP and 2006.04 is April CTP and so on.

    NOTE: Also, I found out that if you installed VSIP SDK on any other drive than C:, the variable $(ProgramFiles) in the Import statement in line 5. , is always interpreted as C:\Program Files and hence cannot find the appropriate folder.

    I could not find any solution to this one, so a workaround is to just replace the $(ProgramFiles) variable with a hardcoded path "<your drive>\Program Files".

    Hope this helps everyone that is trying to run this wonderful work from you.

    Thanks,

    Rupak Ganguly

    http://developeshelf.blogspot.com



  • aytas

    Gareth,

    > <p>Built: <#=this.BuildSomeStuff()#></p>

    Excellent - Thanks!

    I was trying without the 'this':
    <p>Built: <#=BuildSomeStuff()#></p>

    Eamon


  • hayate

    Hi Eamon,

    Please, update it for VS2005 final version.

    Thanks,
    Alexnaldo Santos


  • Christian Jacob

    Gareth,

    You are right - that works too.

    When I was trying it in the past I must have been changing a few different things, and when it did not work, for some reason I though the problem was with the function call inside <#= .. #>. I guess the lesson is, when writing templating code, better to try one thing at a time.

    I have updated my Clipcode-GoF-DSL on my website to emit text from functions, which cleans up the templating code.

    Thanks,

    Eamon

  • C2O

    Claudio,

    < xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 

    Interesting comments.

     

    “What is the most appropriate level of abstraction for DSLs ” is a question that will be frequently asked when folks are thinking about creating DSLs. There are a variety of ways of categorising DSLs, but for now if we just look at closeness to code, we can think of DSLs in terms of high-level, medium-level and low-level.

     

    An example of a high-level DSL would be one for web services. I bet there is a team somewhere in < xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Redmond working hard on a DSL for Windows Communication Foundation in Vista (which is why I did not pick that as the basis for my DSL!). We can imagine such a DSL will provide high-level constructs for designing SOAP interactions, and the generator will created many instances of CLR types for each element instance in the model. It is the perfect example of where DSLs can be immensely useful. However, because it will be high-level, an open question is how it will handle significant variability. The further you are from the code, the more important this question becomes. If the DSL user sticks to the common usage, it will work extremely well. I openly wonder, when the DSL user wants greater variability, how the high-level DSL will support that   (in my case, I would be interested in support for something like: http://www.ietf.org/internet-drafts/draft-mrose-rfc3288bis-02.txt).

     

    An example of a  medium-level DSL would be one for custom resource managers using .NET v2’s System.Transactions. There are a couple of important design decisions about how your RM works with the kernel transaction manager and the DTC; and when the model is finished then for each element instance a few CLR types will be instantiated in the generated code.

     

    High-level and medium-level DSLs will be most popular, but I think low-level DSLs can sometimes deliver benefits.

     

    An example of a low-level DSL would be one for fundamental design patterns, such as GoF, POSA or Hohpe. Before looking at how these might be created, we should first ask are they needed at all One viewpoint might be, just don’t bother. Since they are so low-level, code snippets might be a better idea. A while back I wrote GoF in C#  http://www.clipcode.biz/stream/gof/index.html and similar implementations for other patterns/languages are available.

     

    In my opinion, what a low-level DSL for GoF brings to the table is:

    A)    visualisation of the pattern (I am a fan of “UML as a sketch”)

    B)     ability to customise the pattern before code generation and 

    C)    elimination of potential error conditions (the model will prevent these)

    If one is new to GoF, all this helps a lot – if one is already a GoF expert, one would probably be quicker hand-coding. In contrast, for high-level and medium-level DSLs, even if you are an expert, you will likely be more productive using the DSLs.

     

    When creating my GoF DSL, I considered three approaches: one-element-per-pattern, common-elements-among-patterns and one-to-one-mapping.

     

    One-element-per-pattern is along the lines you outline in your blog – one toolbox entry per pattern, this could be dragged onto a design surface and various properties set on it directly, and compartments within it could contains lists of participants (and their properties). For simple patterns (e.g. Singleton) this will work nicely. The problem is with the more complex patterns – such as AbstractFactory. Here we have multiple participants of different types; participants have a variety of relationships (ConcreteFactory creates ConcreteProduct, which inherits from AbstractProduct which is used by Client). If we go beyond the simple case of one of each, to a user-defined number of each with varying per-element relationships, it becomes difficult to represent this all within one element (note: compartments cannot be nested). Furthermore, we are getting no benefit from a graphical design surface (it just shows one element).

     

    The common-elements-among-patterns approach involves sharing elements among different patterns. Many GoF patterns have a Client, an Abstract<something> and a Concrete<something> and we need to ask could we represent them in the toolbox as common elements. The two problems here are that each pattern attaches different semantics to each element and that the connectors would need more intelligence built into them to decide the permissible connections (e.g. in the AbstractFactory pattern, we do not want to allow ConcreteFactory inheriting from AbstractProduct, even if we have a connector that allows Concrete<something> inherit from Abstract<something>). With a bit of work, maybe these problems could be overcome.

     

    Therefore I went with the one-to-one mapping. I am not saying the first two approaches are wrong, it is just that the one I chosen has maximum flexibility.

     

    I agree that the most productivity gains will be had from higher level DSLs - The big question is how to expose significant customisation while maintaining the DSL at a high-level. I reckon in certain circumstances, low-level DSLs will be useful too.

     

    Eamon

     

    P.S. One question to ponder is how best to implement composable DSLs – imagine we want an abstract factory AND a web service element; or a Singleton AND a ResourceManager.

     

    P.S. 2: In my GoF DSL, the icon in the toolbox that represents each element within a pattern is meant to appear in the top-right corner of the element instance box in the design surface. (We obviously need some graphical way of distinguishing model elements). In the current DSL Tools, icons in multiple design surface elements are not supported. (This is in the FAQ – which of course I did not read at first - So read the FAQ before coding).

     

    P.S 3: A library of prebuilt GoF models would be useful. I could imagine opening a directory, accessing a prebuilt model, and then customising. The same applies to other DSLs.


  • Alfred Myers - MVP

    Emil,

    That attribute was removed for the November release of the DSL toolkit. It's functionality (ability to register a project item template with Visual Studio) was replaced with a combination of MSBuild rules at design time and generated WiX at deployment time.

    Thanks,

    Grayson


  • PWStevens

    Awsome! This is excellent, Eamon. Gave me also new thoughts of finding my way through the template engine.

    Thanks,
    Alex

  • Release of a DSL for the Gamma et al. Design Patterns