View Excerpts
  View Full Text

Why Round-Trip Engineering does not work

Where Is Here The State Machine

One of the most frequently-raised topics in model-based engineering is that of “Round-Trip Engineering“. Well, there is a good reason why there is no workable solution for round-trip engineering on the market. This is because of two reasons.

First – is the difference between the languages. Both tasks – forward engineering (code generation from the model) as well as the reverse engineering (parsing the source code and creating model elements based on the results) are nothing else than translation from one language into another and as we know some things get lost in translation. Whereas, on the one hand the structural UML features like classes or interfaces have comparable features in most of the high level programming languages and can be translated from UML to the programming language and vice versa, the behavioral part of UML is different. Features like state machine have no equivalents in programming languages and will be translated during code generation to standard programming statements (like if, else, switch, function calls etc.). These statements have to follow exact pre-defined schema (or with other words pattern). Once the schema has been broken by accident while editing source code this code can not be reverse engineered any more to the same model as it has been generated from.

Second – since in most cases models contain source code snippets, the generated code consists of two parts: the part that defines pattern implementation, and the part that defines user-specific logic. While these parts are separated in the model by concept, in the generated source code one can impossible hardly be discerned from the other since they are essentially interwoven. So again, this is where mistakes are bound to be made while programming the source code… and once this mistake has been made and  both parts have been mixed up, not even the world’s most advanced parser can re-assemble this code into a clean model. All in one that means the round-trip-engineering is restricted to very basic part of UML simply due to conceptual differences between the modeling and programming languages.

Nevertheless, even if model-based engineering provides many advantages, some parts can be developed much more quickly in the source code editor and not using very basic code editor features provided by modeling tools and clicking through hundreds of dialogs. The User Code Sync feature integrated into LieberLieber Embedded Engineer offers a workable alternative to round-trip engineering by clearly marking the areas in the source code that can safely be edited by the developer at any time. Typically, users add some hand-written source code either as the implementation of an operation or an opaque action. The description how it works please find here

Syncing Model with Code

Round-Trip Engineering is one of the most requested features for our code generation solution. While people agree that it’s hard to get right and consequently are disappointed by many implementations thereof, it’s nonetheless a feature which can improve – when done correctly – your workflow.

Unfortunately, round-trip engineering is quite hard a challenge even for structural code generation, but for behavioral code generation usually all bets are off. Existing products often resort to kludges and hacks to implement this feature, sometimes making it downright dangerous. While sometimes useful, it’s not a feature you’d like to use from day to day.

We at LieberLieber believe that we can improve the modeling workflow now, without the need for full round-trip and its drawbacks.

That’s why we’ve created Code Sync for Embedded Engineer.

LieberLieberEmbeddedEngineer

 

 

The premises are simple:

  • The model is the one-and-only source for generated code – no exceptions
  • Structural changes are done in the model

This ensures that your model is always up-to-date, and there’s no way around that. This in turn improves the utility of your model as documentation – because what good is a documentation if it only remotely documents the thing you’re shipping?

Now these premises would restrict you to model-only engineering, basically. But that can be tedious when you start to do behavioral modeling, where you also include source code in the model.

That’s where Code Sync comes into play.

Before gCodeChangeReport_thumbenerating code, Code Sync looks for existing code blocks – that is, code which can safely be changed by the user – and detects the following changes:

  • The model changed, but the code didn’t. It’s safe to overwrite the code.
  • The code changed, but the model didn’t. It’s safe to sync the model with the code.
  • Both sources changed. Apparently there have been changes in the model as well as the code, so Code Sync let’s you decide how to merge the code.

This way you can efficiently modify the generated code, and as soon as you sync/regenerate it, your changes are incorporated in the model.

You also get a report documenting the changes (pictured above), be it changes in the model, the code, or conflicting changes which may require your attention.

Coming in Embedded Engineer 2.0

 

Embedded Engineer and Python with Enterprise Architect

See our first shot at Python script generation with the Embedded Engineer and Enterprise Architect from Sparx Systems

LL_Embedded_Engineer_20141105.indd

 

For our example we used a Raspberry Pi B+ with the Adafruit LCD Pi plate.

Since the Embedded Engineer has the abillity to be extended with your own “CodeBuilder” we created an implementation for Python.

This first implementation is targeted on simply showing the Raspberries IP, a crude file navigation and functions to exit the programm as well as rebooting and shutting down the raspberry.

Besides a small python script for starting the programm every line of code was generated with the LieberLieber Embedded Engineer.

 

Here some examples of the CodeBuilder, the generated code and the model used to generate the code.

 

1.) The CodeBuilder:

Here you see a simple piece of code to generate a if/then/else statement.
image

2.) The domain model:

All used classes are modeled here
Domain Objects

 

3.) The state machine:

This is the main state machine which controls the LCD and its buttons.
The LCD is used to show text and the buttons are used to scroll inside the “root menu” and navigate the “output” (in this case the IP or a file listing)

StateMachine

 

4.) Example activity:

This “RunDirCommand” activity sends commands to the shell and writes the output to the “self.cmdOutput” list.
With a simple “ls –a –p” we get a list that can be used for navigation across directories.
RunDirCommand

If the selected output entry ends with a “/” we know it’s a folder and therefore change the workingdirectory and refresh the filelist.
If the selected output entry endw with “.py” we know it’s a python script and can be executed with a “sudo python [output entry]”
Everything else will leads to no action.

 

5.) Generated code:

generated python code

 

6.) The starting script

This simple script is all you need to start the generated state machine.

from LCDMenu import *
lcd = LCDMenu()
lcd.runStateMachines()

 

At last,… the generated code in action:

LieberLieber@ESE Congress 2013

A very successful participation had LieberLieber last week at the “ESE-Kongress 2013” in Sindelfingen, Germany. The congress, including workshops, presentations, tutorials and an exhibition around the topic embedded software engineering, was visited by 500 participants.

LieberLieber presented his solution for embedded C-Code generation enar uml2code together with Sparx Systems on an exhibition booth. Furthermore the know-how was transferred to the participants in a tutorial, a presentation and a workshop held by the LieberLieber employees R. Bretz, W. Nesensohn and O. Alt.

For the topic of embedded code generation from UML models we had a very big response and we think it might be the mega-trend for embedded systems for the next years. Also other LieberLieber Model Engineering topics like model validation, Systems Engineering and variant management were from big interest for the congress participants.

We look forward to next embedded events, the Embedded World exhibition and conference in Nuremberg 2014 and of course the next ESE Kongress in 2014.

Here are some impressions from our exhibition booth…

ese2013_1 ese2013_2

… and sometimes as a software company you have to deal with hardware as well ;-)

ese2013_3

uml2code Extension for Enterprise Architect

Extending EA’s code generation capabilities with the uml2code plugin form LieberLieber. It provides you 100% control of the generated code and an easy to adapt interface.

When you generate code, probably you know how to write code. Hence, the approach of the uml2code generator is an implemented code generator in C#. It consists of 2 steps and 4 packages.

This article gives you an overview of the general architecture of the uml2code generator. The mentioned packages actually represent VS projects and provide the following functionality:

uml2code Package Dependencies

 

MDE.Apps.enar.uml2code: This package represents the EA-PlugIn. The purpose of the project is to start the code generation from within EA. However, the code generation can also be triggered from outside.

MDE.AnyModel2UML.SourceCode.Uml2Code: This packageis responsible for reading EA’s UML model, parses it and generates an abstract representation of  the UML model in programming language semantics, the abstract code tree (ACT). Hence, it uses the package MDE.DataModel.AbstractCode.

MDE.DataModel.AbstractCode: This package contains interfaces which represent an Abstract Code Tree (ACT). It is used by Uml2Code, which implements the interfaces of it and by Uml2Code.Uml2C, which writes the source code based on the ACT.

MDE.AnyModel2UML.SourceCode.Uml2Code.Uml2C: This package uses the interfaces from AbstractCode and generates the source code. This is the main place where the source code is written and influenced.

The two steps of code generation are the following:

  1. Parse the UML model and create an Abstract Code Tree (ACT).
  2. Use the ACT to write the source code.

How to Influence the Code Generation

Each of the above steps can be influenced. To influence the code which is written, you can adapt the content of the package Uml2C.
The Uml2Code plugin also provides implementations for C#, C++ (Uml2CSharp, Uml2Cpp, respectively).

The generator generates ANSI C89 code which can be used out of the box. However, if you have another idea how the model should be translated into code, you simply select the method which generates the code you want to influence.

public void GetCode(IMethodCall<IMyNamedElement> methodCall){…}

public void GetCode(ILoop<IMyNamedElement> loop){…}

public void GetCode(IIfThenElse<IMyNamedElement> ifThenElse){…}

The method GetCode(…) provides access to the part of the ACT which is currently translated into concrete source code. If the ACT doesn’t contain the information you are looking for to generate source code (e.g. tags, stereotypes, status, phase, version, etc.), you can simply access the corresponding EA model element, get the information and use it to write the code you would like to see. For instance, if you would like to generate different code for methods with stereotype “ComponentX” , query the corresponding model element and get its stereotype.

if(methodCall.ModelElement != null

&& methodCall.ModelElement.Stereotype == “ComponentX”)

The ACT tells you if the model contains a method, attribute, loop, etc. How the method, attribute, loop is modeled in UML is transparent within the package Uml2C. The package Uml2C only relies on ACT element. If necessary, you can dig deeper and get the corresponding model element for the ACT, as explained above. However, depending on the corresponding model, it may be that there is no single model element, e.g. a loop modeled with Decision and Merge in UML::Activities. Hence, you have to check for null first.

If your are not happy with the way your model is mapped into the ACT, go to the place where the ACT is generated (the package SourceCode.Uml2Code) and influence it.

Use a DSL Model to Generate Code

Because the package SourceCode.Uml2Code is responsible for the mapping between UML and code and provides an out of the box mapping of UML semantics and programming language concepts, this is the place to influence the generation of the Abstract Code Tree (ACT) if you are not happy how the UML mode is mapped into code.

This is for instance necessary if you have created your own DSL. If this is the case, you merely have to adapt uml2code and create the ACT you would like to see. Uml2C will take the new ACT and create the code without any further necessary changes.