Domain-Specific Development in Visual Studio
The Visual Studio SDK contains tools that make it easy to define and implement graphical Domain-Specific Languages (DSLs) and associated code generators in Visual Studio.The term domain-specific development refers to an approach to software development involving the use of DSLs to drive code generators. The tools contained in the Visual Studio SDK are collectively called the “DSL Tools” and use domain-specific development techniques to create and implement DSLs for use in Visual Studio. This article illustrates the domain-specific development approach through an example, and then shows how you can use the DSL Tools in the Visual Studio SDK to build the DSL used in that example.
The approach the authors call domain-specific development is a pattern of model-driven software development. It’s a very useful way of developing software when you’re building a specific type of solution; that is, when you’re building a solution in a particular domain. A domain could be a vertical one such as insurance underwriting systems, a horizontal one such as three-tier distributed applications, or a combination of the two such as retail shop-floor mobile applications. Figure 1 illustrates the pattern.
Figure 1: Domain-specific development pattern.
The diagram shows the pattern having two main parts: a fixed part, embodied by a framework and a variable part, embodied by a model.
The fact that you’re building software in a specific domain implies that some elements of the solutions you might build in that domain are the same from one system to another. As has been good practice now for many years, to enable you to build systems in the domain more easily, you should capture those common elements in a reusable domain framework.
However, frameworks are often complex. To make using them easier, domain-specific development introduces a model of the part of the solution that is different from one application in the domain to another, for example, the specific UI, business, and data components that you need to create a retail banking three-tier application, as opposed to those components you need for a lending library management three-tier application. The elements that you’ll find in these models encapsulate the right patterns for using the framework. For example, an Entity element in the data tier of the model contains enough information to specify how to derive a class from some EntityBase class in the framework to form part of a data-access layer.
You can see that these models contain information that’s very specific to the domain-the information you’d find in them naturally represents the things you think about when building a solution in that domain. To accomplish this, you create domain-specific languages (DSLs) to represent them rather than using generic modeling languages. Figure 2 presents an example model in a DSL for representing the static structure of a three-tier application.
Figure 2: DSL for three-tier applications.
This DSL has three vertical swimlanes representing the three tiers of the application architecture. The elements in each swimlane represent the types of object you’d expect to find in each tier-each somewhat like a class with attributes and operations, but each distinct with their own specific properties, a page in the UI tier, a service façade in the business tier, and an entity in the data tier.
A key value of DSLs is that because they are specific to a problem, you can encode business and architectural rules about that problem into the modeling tool itself. For example, in the three-tier DSL, dependencies directly from the UI tier to the Data tier will cause the tool to display errors (Figure 3).
Figure 3: Errors displayed in a DSL when architectural guidance is broken.
Going back to the pattern, you’ll see the framework has two inserts: a generated part and a handwritten part. The generated part is the integration between the fixed and variable parts of the solution. Typically a code generator runs across the model and produces code that extends the framework according to well-known patterns. For example, each Page element in the UI tier causes the code generator to generate a page in the solution, derived from an ASP.NET Page object. You might specify the master page to use for the page directly in the DSL or you might choose a more abstract representation and just provide a selection of common page types.
The final piece of the solution in a domain-specific development solution is the handwritten part. This acknowledges that in most cases neither the framework nor the model will capture everything that is needed to produce a 100% complete solution. There will usually be some solution-specific code that you are introducing for the first time in a particular solution. It’s generally accepted that harvesting code for reuse should wait until it’s been used at least a couple of times to prove its utility and this is equally so in the case of being able to establish the model that you need to generate from to parameterize it.
Some things are also simply better expressed in ordinary code than in modeling languages. For example, in this case, the logic and math to calculate the fine for an overdue book would be very clumsy to represent graphically, whereas you can express it clearly in code.