in detail in section 4.
Executing the above described iterative process al-
lows the reverse engineer to pull more and more fea-
tures of the software system onto the model level. As
more and more generated code replaces manual code,
each new revision of S
i
simplifies the maintainability
of the software system, and eases the generation of
new code variants.
As with any kind of code refactoring, it is im-
portant to support the reverse engineering process to-
wards MDSD by continuous unit testing. The reason
for this is that generated method implementations can
vary from the original code, as long as the methods
provide the same functionality. See section 4 for fur-
ther information.
It should have become obvious that the generated
code will almost by definition be incomplete. To be
able to adequately deal with this incompleteness in
the merging step, we assume that for a given method
in S
i
, the generator either (i) does not generate the
method at all, or (ii) generates only the declaration of
the method using its method header
1
, or (iii) gener-
ates the complete method definition, i.e. both header
and body. There is no generation of partial method
bodies. This assumption is, however, not a serious
restriction, because each method that could be gen-
erated partly can be refactored and decomposed in a
preparatory step. For fields, either only the declara-
tion or the declaration together with an initializer is
generated. Finally, inner classes are generated recur-
sively within their containing classes.
3 SEPARATING GENERATED
AND MANUAL CODE
When forward engineering a software system with
MDSD, the partly generated code needs to be com-
pleted with hand-crafted code. One approach is to
manually add code directly into the generated source
code. However, this technique is widely consid-
ered problematic, mainly for two reasons: (1) The
hand-crafted regions of the source file must not be
overwritten when the artifact is regenerated, and (2)
putting generated code under version control is gen-
erally avoided. Therefore, most authors (e.g., (V
¨
olter,
2009)) recommend the strict separation of hand-
crafted and generated code into different source files.
In the following, we briefly discuss the two separa-
tion techniques that are commonly propagated, and
1
The method header consists of modifiers, generic type
parameters, result type, method identifier, parameters and
the thrown exceptions.(Gosling et al., 2005, Page 210)
evaluate their applicability for model-driven reverse
engineering.
1. Inheritance is probably the most widely-used
technique to separate generated and manual code.
The idea is to generate a base class which can be
extended by a concrete subclass implementation
that contains the manual code. For reverse engi-
neering, this would mean to decompose an exist-
ing legacy class A into a generated base class, A
0
,
and a hand-crafted subclass A
00
. This decomposi-
tion, however, leads to a variety of technical prob-
lems, one of which has to do with access rights:
Assume a private field in a legacy class A that
after reverse engineering can be generated into
the new base class A
0
. To give subclass A
00
ac-
cess to this field, its access right must be modified
from private to protected. This modification,
however, might have undesired side-effects some-
where downstreams the potentially complex pre-
existing type hierarchy.
2. Composition and delegation is another approach
where a composed object uses an associated del-
egate object to delegate its tasks to. With model
driven engineering, the composed object contains
the generated code, whereas the delegate object
contains the hand-crafted code. In (Walter and
Haase, 2008), this technique is used to transform
existing legacy code into a model-driven struc-
ture. This approach, however, leads to even more
serious problems with access rights than inheri-
tance, owing to the fact that object identity gets
lost with composition and delegation, because
each object in the legacy system gets split across
two separate objects. As a consequence, each for-
merly private field must be made not only pro-
tected but at least package-private if the other ob-
ject needs access to it, too.
In summary, these separation techniques are not
adequate for reverse engineering, because decompos-
ing existing legacy classes into new classes, be it by
subclassing or by composition, is a very disruptive
technique that can have unexpected and undesired ef-
fects on the correctness of the overall system. In
addition, on a semantic level, both approaches are
meant for other purposes than separating generated
from manual code which makes their application for
code separation questionable: (1) Inheritance is meant
to model is-a relationships; however, there is no such
relationship between the generated and the manual
code portion of a class. (2) Composition is meant to
model part-of relationships, which is also not the ap-
propriate relationship between the two code portions.
In contrast, manual and generated code are two equal
parts that together form the functionality of a class.
ACodeMergertoSupportReverseEngineeringTowardsModel-drivenSoftwareDevelopment
85