3.2 The Modeling Language
The single most important asset of a DSM environment is the
domain-specific modeling language. To substantiate this claim, let us consider
the payback promised by the DSM approach. The labor of the domain experts who
create the DSM environment is the original investment on the DSM. The return on
investment, then, is a result of the increased productivity of the developers
working with the DSM environment. While the code generator and the domain
framework are important parts of the DSM environment, they still remain
reasonably invisible for the developer, whereas the role of the modeling
language is emphasized as the main instrument of the DSM. Thus, the better
modeling language we have the more we benefit from the DSM.
The first rule of thumb for creating a domain-specific
modeling language is to keep the language as independent as possible from the
target code. We know that it often originally appears easier to try to build the
modeling language as an extension on top of the existing code base or platform,
but this kind of visualization of the code world very seldom lead to a
significant rise in the level of abstraction and it definitely does not free the
developer to think according to the domain instead of the code. Thus, to achieve
the best possible level of abstraction for our modeling language, we need to
base it on the domain itself.
First, ask yourself what you want to do with the
domain-specific modeling language. When you have set this mission statement for
yourself, you can proceed by asking how you can do what you want and what is
needed to do that. This analysis leads to the discovering of the first domain
concepts that are to be incorporated into the modeling language. For example,
our mission statement for the watch modeling language set the following goal: we
want to be able to model those static and behavioral elements that constitute a
digital wristwatch. Based on this statement, the further analysis soon
identified a watch model, display, logical watch and a watch application as the
elementary concepts of the watch architecture.
At this early stage of the modeling language definition,
one should focus on identification and definition of domain concepts. There are
several ways to do this and it is important to understand that usually none of
them alone can provide complete coverage. Good results typically require
concurrent use of a number of different strategies. In any case, the key success
factor in finding the domain concepts is the domain knowledge possessed by the
domain experts.
A good way to identify the domain concepts is to study the
aggregation structures within the domain and product. The aforementioned
elementary watch concepts were discovered in this way. Another method is to try
to find the commonality and variability among the products. For example, it is
easy to see that the different watch models still share the common concept of
button that would suggest button as a probable domain concept for the modeling
language. Similarly, we can see that the watch models differ from each other by
the number of buttons and features they include, which says something about the
configuration space requirement for the watch models.
It is also worthwhile to examine the existing
specifications to see if there are any repeating patterns that could be refined
further as a domain concept. And don’t forget common wisdom or experience
as a source for ideas – our decision to use the state machine as the
computational foundation for watch applications and logical watches was based on
the fact that it is a widely used solution in the area of embedded systems in
general.
The next step after the identification of domain concepts
is to assemble them into a modeling language. The language is defined with
MetaEdit+ as a metamodel that applies the domain concepts as the semantic
structures for the language. The detailed description of the metamodeling
process is out of the scope of this tutorial, so for more comprehensive
information about the metamodeling please refer to the Family Tree example in
the Evaluation tutorial and the ‘MetaEdit+ Workbench User’s
Guide’.
Two important aspects should be considered during the
creation of the modeling language: layering and reuse. Modeling language
development efforts typically start with a flat model structure that has all
concepts arranged on the same level without any serious attempts to reuse them.
However, as the complexity of the model increases while the number of elements
increases, the flat models very seldom are suitable for presenting hierarchical
and modularized software products. Thus, we need to be able to present our
models in layered fashion.

Figure 3-2. Watch model hierarchy
A partial illustration of
the watch model hierarchy is presented in
Figure 3-2. The watch model hierarchy
consists of three layers. For the top-layer models we use a proprietary
WatchFamily diagram type to present the static high-level configuration of each
watch model. On the two subsequent layers we employ the WatchApplication diagram
type to present the dynamic variability within the logical watches and watch
applications. As each additional diagram type increases the complexity of the
modeling language, it is normally good practice to design diagram types so that
they can be applied recursively on more than one layer. On the other hand, if
the semantics of two consequent layers are different, two different diagram
types are the recommended solution.
Another aspect that influences the layer structure is
reuse. The idea of reuse-based layering is to treat each model as a reusable
component for the models on the higher level. In this kind of solution, the
reusable element has a canonical definition that is stored somewhere and
referenced from where it is needed. In the watch example, the whole layering is
actually based on this principle. Each watch application is a true model
component that can be referenced from any logical watch. Similarly, each logical
watch can be attached to any concrete watch model.
Reuse can also happen regardless of or in addition to the
layering. Typically we also want to reuse concepts within or between the models.
The concept of a display function is an example of reuse within a model. Defined
once in a WatchApplication diagram, each display function can be referenced by
any state within the same diagram. Reuse between the models is needed when the
same concept appears on several models. Examples of this kind of concept within
the watch example are the buttons. While it is possible to create a new button
concept for each state transition, it is much better idea to reuse an existing
one. It is not only faster to use buttons in this way, but it also makes it
easier to propagate possible future changes (like changing the name of the
button). This kind of reuse differs from those described above in the sense that
there is no canonical definition for the reusable element. It can be considered
as a floating concept that exists as long as it is instantiated
somewhere.
The last step during the initial development of a
domain-specific modeling language is the finalization of the language. Typically
this means the extension of the language with concepts that are required for
code generation, component interfaces, consistency checking and documentation.
In the watch example, the inclusion of the watch domain framework code as
included components in WatchFamily diagram is an example of this kind of late
addition. With this solution we wanted to ensure that the framework code is
always available for the code generation. Otherwise, and probably a bit
surprisingly, no other code or documentation generation related additions or
modifications to the original modeling language were
needed.