Reflective Architectures and Code Generation.
ã Moisés D.
Díaz. www.moisesdaniel.com
1.- Let’s start with an example: AnotherAmazon.com .
2.- Source Code generation (or manual development).
3.- What a reflective architecture is.
4.- When do we have to develop a reflective architecture.
1.- Let’s start with an example: AnotherAmazon.com.
Imagine we have to build up a commercial site focused on web sales of
products like books, films, DVDs, CDs, printers, mouses, cameras, mp3 players,
TVs and all kind of electronic products.
Each type of object can be defined by its characteristics. So, we will
have:
To manage all this information, we certainly need to keep it in data bases, in order to be able to manage it in a suitable way and to have all this software guaranties. So we will have a table for each type of object, where fields will coincide with its (particular and common) characteristics. So, the information related to each object will be kept in the table of the type of object it belongs (for instance, books will be kept in the “Books” table).
This is a simplification of reality but it is a good example to
illustrate what we want to explain.
Our duty consists, basically, of managing the web publication of all this information (forget the shopping trolley). Publishing this information consists of giving the user the permission, using a web navigator, to be able to:
There are two technical possibilities to achieve successfully this duty:
|
|
§
We can have an only web component
which works in such a way that is able to show any object of any type by
reading the properties of each type of object (these data are kept in the
MetaInformation table). It is like having an only JSP/ASP to list
(List.jsp?type=DVD), and another one to visualize entries
(ShowElement.jsp?type=DVD&id=83838). The information that describes the
structure of each type of object is called metainformation. Creating it can be
expensive or not, but its maintenance has a very low cost.
|
2.- Code generation (or manual development).
Each type of object has a group of characteristics that are common to
other types, in the same way, each of them has its own ones that are different to
the own characteristics of the others. This implies that we will have some
tables related to each type in the data base, and that the web components which
lists and visualises each type must have a very similar structure, as their
function is basically the same. But, at the same time, that structure or code
must be a little bit different, due to the specific characteristics of each
table (type of object), to which it acts as the latter web interface.
In fact, the code of each component related to a type is absolutely
independent of the structure of the table to which it works as interface. So,
once we have defined the table, we can automatically generate all or part of
the code that is going to list it, visualize it, and so on. The other
possibility is using the well known technique: “copy-paste-modify”. Both
techniques are almost equally successful, but the last one is much more
expensive and can produce more mistakes.
There are many tools to generate code, for instance, CodeCharge, Xcripter, and many wizards from different development
frames.
As using the first mentioned
technique we obtain the same results, but with a very low cost, we could think that
this option is the solution to the problem described at the beginning of this
article (“AnotherAmazon.com” building up). However, generating code has many
points against (less than the copy-paste-modify technique), that is why it is
not the most suitable technique for all projects.
For this reason we are going to focus on source code generation.
Code generation is frequently found when there are interfaces between
different layers, components, and so on. Places where a little amount of information
can be used to generate all the repetitive code required (e.g.: Wsdl à Soap, mapping OO à RDBMS, tables à forms)(in this case, from tables to Html lists and
Html visualisation of their entries).
There are, basically, 3 code generation types [ACG]:
§
Templating. A draft of
non-functional to be edited source code is generated. Doing this way we do not
have to write down the most repetitive part of the code (usually, not very
complex). It is usually a good solution. For instance: If we use Oracle JDeveloper
to build a new Servlet, this software is going to automatically generate a
“Servlet” class with the basic imports and the methods this class has.
§
Partial. Source code that partially implements the
required functionality is generated. The programmer will use it as a base to
modify, integrate or adapt according to his needs. It is not recommended. For
instance: we generate an application to maintain ddbb tables (as web
applications build up using CodeCharge, or BC4J components created with JDeveloper).
If we want to modify it, integrate it with other developments or just adapt it
to other lightly different needs, we have to dive through a huge quantity of
code that we do not understand but that we have to modify a lot.
§
Total. Functionally complete source code is generated, but it is not going to be modified by the
programmer. If it is necessary the code will be regenerated. Usually, it is not
a very complex code. A very recommended option. For instance: a Stub generation
for a WebService in JDeveloper.
We are going to focus on the partial generation (that means automatic
generation + modifications and some developments in it). Usually, there are
some problems with that, as:
§
The generated code is so
complex that it is difficult to modify from the point of view of the
implemented functionality.
§
Its regeneration is usually
very expensive, as we have to modify it again to adapt it to the problem.
§
We have to maintain all the
generated code, which implies the higher cost of a project.
§
It makes the code dependent
on another extra development tool. This is very restrictive, as the maintenance
becomes more complicated (most of the times, it is not the firm that developed
it the firm that maintains it; some times other environments emerge where those generation tools are not useful
(for instance: at first, CodeCharge generated JSPs, now, it generates
Servlets!!)). It is another strong dependence.
§
Functional code generation
usually contains most of the functionality needed, but not all of it. And modifying it is very complicated.
One of the main objectives of software engineering is creating a reusable software, that means
generating a very hard code, with few mistakes.
Then, why do not parametrise all this repetitive but different code
unifying it (that means refactorising)? All depends on the dimension of the
application, as this refactorisation is, usually, a result of reflective
architectures. We do not have to forget that developing an architecture has a
cost. There are only two positive aspects of partial code generation:
-
Usually, it has a better
performance than the r.a.
-
Its developing is quicker
(unless you have the r.a. implemented).
The generation of web components associated to types of object is
categorised as partial code generation. We can generate code to list and
visualise the entries of the tables, but this code is usually part of an
application that has to be integrated in other specific developments, as
security code, the using of specific technologies related to data base access
(for instance, a connexions pool), navigation elements, style and visualisation
patterns, the using of logs, personalisation mechanisms, printing services, and
so on. When we have to face the building up of
big/medium applications, code generation is very problematic.
3.- What a reflective architecture is.
As it says in [POSA], reflective architectures have been used in many
different systems and are specially recommended when flexible and adaptative
applications are needed.
A reflective architecture is characterised by having a number of
elements that contain structural information about part of the system, that
means that it describe the system. The system uses this metainformation as a
basic element that let it interact with those described elements (generally
called base).
One of its main characteristics is that, usually, all base elements that
are described share a number of characteristics, in such a way that they can be
object of certain transformations (operations) uniformly. However, they have
elements that make them different, so these operations depend on each base
element.
Because of these differentiated characteristics we have to generate a
specific code for each of these base elements. Nevertheless, there are some
times when it is more profitable developing a reflective architecture as it
treats all these elements uniformly.
|
Base Elements implement each Operation. The programmer has to develop a lot of specific
code for each Operation of each Base Element. |
All this architecture can be also seen as a typical strategy of
centralisation or as an application of the encapsulator-centraliser
metapattern.
|
Now Operations are encapsulated and centralized in
one Class, that uses the metainformation contained in the Descriptor, in
order to customise each operation
of each Base Element. The Programmer has to develop only Generic
Operations for all the class. |
Pros:
Cons:
Reflective architectures are not always the best option, above all if
there are not many base elements to generate the code.
With regard to their performance, they are architectures that add an
additional layer of indirection, and that, a cause of that, depending of the
specific application can be slow (though they generally do not have to be that
way). Besides, there are some means to increase their performance, like, for
instance, the using of cache.
4.- When do we have to develop a reflective architecture.
Developing an architecture has some costs and it is always not the most
suitable technique, that depends on different aspects.
Generally, implementing a reflective architecture requires developing
complex code elements, it needs some additional classes, it needs that
additional level of indirection that give us the necessary potential and
flexibility.
So, if it is a little application, implementing a reflective
architecture is not recommended, as this will increase the complexity of the
application, its cost and the needed knowledge for its maintenance without
contributing much to it in exchange.
Then, when we should implement it?:
Let’s imagine a site like the one we have described at the beginning of
this article (AnotherAmazon.com). A site that manages several different tables
of different objects to be sold. That means that here we will have many base
elements. This is the ideal scenario to implement a reflective architecture
that let us modify, in a centralised and easy way, the information contained in
these elements, add new elements of information like “DVD Players”, and so on.
Some useful references to look at:
§ [ACG] “Automated Code Generation”: http://c2.com/cgi/wiki?AutomatedCodeGeneration § [CGIDS] “Code Generation is a Design Smell”: http://c2.com/cgi/wiki?CodeGenerationIsaDesignSmell § [OAOO] “Only and Only Once”: http://c2.com/cgi/wiki?OnceAndOnlyOnce § [RCG] “Reflection versus Code Generation”: http://www.javaworld.com/javaworld/jw-11-2001/jw-1102-codegen.html
§ [WIR] “What is Refactoring” http://c2.com/cgi/wiki?WhatIsRefactoring |
ã Moisés D.
Díaz. www.moisesdaniel.com