Implementing a DomainDomain-Specific Modeling Environment

Download Report

Transcript Implementing a DomainDomain-Specific Modeling Environment

Implementing a Domain-Specific Modeling Environment For a Family of Thick-Client GUI Components

Milosz Muszynski Tanner AG

[email protected]

Generators For the GUI Components

In theory, generators should be as simple as possible. The following guidelines, when followed, lead to simple generators: • Variation is moved to the specification (DSL) language.

• Low-level implementation issues are pushed into the platform.

• We generate only the glue code.

We strive to minimize the generator and the manually written code by pushing complexity to the platform and DSL.

Higher Abstraction Level DSL Generator Manually Written Code Platform Lower Abstaction Level

Following the guidelines is not always feasible. Problems arise when trying to simplify generators by extending platforms: • Moving implementation details into a platform is time consuming and requires resources.

• Platforms imply programmatic approach - not feasible for textual specifications (such as GUI design).

• Platforms may easily become too generic - not feasible if we need an exactly tailored solution.

• Complexity in platforms is usually less comprehensible for people not familiar with the DSM process.

Small, tailored GUI components require precise, rich generators.

• Precise, rich generators don’t need to be complex, but they produce relatively large amounts of code.

• Some applications such as interface-driven GUI components require voluminous code generated by conceptually simple generators.

Variability space of the generated components.

• Static (non-behavioral) variability allows for significant simplifications in both the model and the generator: – Model walking algorithms become straightforward.

– Number of required generator operations is limited.

Example - small set of operations used be the generator for interface-driven GUI components.

• Setting an output file name or part of name using a value of a model class attribute.

• Substituting text with a value of a model class attribute at a file or a file fragment scope.

• Conditional inclusion of text depending on a value of a model class attribute.

Code that is a basis of generation.

• Usually developed outside of the generator in a form of a reference implementation.

• Should be functional and well tested before we insert it into a generator.

Insertion of a reference implementation code into a generator (code migration) can lead to the following problems: • It is time consuming, difficult to automate, amounts to 20-25% of the entire reference implementation development effort.

• It results in code duplication. Constant evolution of the reference implementation is not easily reflected in the generator.

• It results in a mix of concerns in the generation input script.

Why don’t we scrap the reference implementation after we are able to re-generate it?

• Reference implementation ought to be developed and evolved in a non-impeded way.

• Evolution by pushing changes through the generator limits the developer.

• Reference implementation is intended to be a top quality exemplar for other code artifacts, there should be no obstacles in achieving the top quality.

Agility of the reference implementation development process.

• In an agile process, we tend to make changes in short cycles consisting of debugging, testing, and applying changes.

• Forcing all changes through the generator would hinder the agility of the process.

Reference implementation code in generator.

• Is less readable because of the generator-specific syntactical embellishments.

• There is a mismatch of concerns: – Model walking and access code is mixed with: – Application specific code.

– Generator input script often does not satisfy the conceptual esthetics requirement (Dijkstra).

An Inverse Approach.

Reference Implementation Metamodel Generator • Rather than migrating code into the generator, we add generating instructions directly in the reference implementation in a form of annotations.

Conventional Domain-Specific Modeling Process.

• Design, implement, debug and test the reference implementation.

• Develop a domain-specific metamodel (or any other form of specification of a domain-specific language).

• Write the generation input script, migrate code from the reference implementation into the script.

• Create models in terms of the metamodel (or write specifications in the domain-specific language).

• Run the generator to obtain a working product.

Reference Implementation Driven Modeling Process Perform the variability analysis. Assign files and file fragments to metaclasses. Decide which names, modules, features, interfaces, etc. you want to have exposed in the model.

Using the visual language defined by the metamodel.

Generic generator walks the model tree and the corresponding reference implementation files.

Design, Implement and Test the Reference Implementation Annotate the Reference Implementation Parse Reference Implementation into the Metamodel Create Models Generate

Latest changes in the reference implementation will be automatically included in the generated code.

Mixed approach is also possible.

• Some code better fits in the generator.

– Code that changes infrequently.

– Code that is very short, like the glue code.

• Some code better fits in the reference implementation.

– Code whose evolution is ongoing.

– Voluminous code.

– Code that is easier to understand in the context of the reference implementation than in the context of the generator.

– Code that conforms to some company standards and/or has to be comprehended by people not trained in the DSM process.

Simple model example.

title interface listener factory app name TabbedGuiApp GeneratedApp IGeneratedGui IGeneratedGuiListener GeneratedGuiFactory GeneratedGUI target dir source dir test dir GuiGenEnvironment c:\vc7proj\GeneratedGui c:\vc7proj\TabGuiGenSource c:\vc7proj\GenTest TabPanel GuiModuleName GeneratedTab4 T Id 3004 TabPanel GuiModuleName GeneratedTab1 F Id 3001 TabPanel GuiModuleName GeneratedTab2 T Id 3002 TabPanel GuiModuleName GeneratedTab3 F Id 3003 • Metamodel is extracted from an annotated reference implementation and fed into a metamodeling tool.

Code in the generator vs. code in the reference implementation.

• Code in the generator (MetaCase MetaEdit+): foreach .TabPanel

{ ' #include "'; :GuiModuleName; '.h"'; newline; } (Mixed concerns - model walking and the target application logic).

• Equivalent code in the reference implementation: /*@@fragment PrototypePanelX = $TabPanel.GuiModuleName */ #include "PrototypePanelX.h" /*@@endfragment */ (Single concern, no code migration necessary).

Three major possible approaches when performing the “inverted” model walking:  Generic walking - starting from the root and following a designated relationship between the model elements.

 Walking with information embedded in reference implementation annotations – this approach is similar to the generic walking, only here the reference implementation annotations may cause the walker to skip the current flow and jump to a given model class.

 Custom walking – the user writes her or his own generator script and accesses the reference implementation files via “processReferenceImplFile(…)” kind of calls. This kind of walking allows for hybrid solutions – both reference implementation and generator-driven.

Three types of reference implementation annotations: • Annotations that influence the metamodel.

• Annotations that influence the output produced by the generator.

• Annotations that influence the model walking performed by the generator.

Additional advantages of the elimination of the migration step.

• In environments where investment in legacy systems is significant, existing code base or its subset can be treated as a reference implementation.

• In environments where there is a substantial production of code without the required modeling awareness and support, the modeling infrastructure can be introduced at low cost.

• As a consequence, model abundance in non-modeling environments.

Conclusion.

• Standard DSM requirement to generate glue code only is not always realizable. • For static variability the metamodel is simple enough to be represented by an annotated reference implementation.

• Necessary generation of large amounts of code is practical and agile with an inverted approach.

• Inverted approach improves the separation of concerns in the generator script.

• Minimal modeling overhead makes it possible to make models abundant in the context of legacy applications.