Model Driven Development: Code Generation or Model Interpretation?
During the Code Generation 2010 conference I was part of a Birds of a Feather (BoF) session about Code Generation versus Model Interpretation. It was an interesting, informal discussion with Walter Almeida, Peter Bell, Angelo Hulshout and Pedro Molina. We discussed the advantages of Code Generation over Model Interpretation and the other way around.
I want to give you a short overview of the points made during the discussion. We didn’t come up with a final comparison or overview of all issues. Hence, you should see this article as a starting point for a discussion. Join the discussion by adding your own views in the comments!
Introducing Code Generation and Model Interpretation
In Model-Driven Development code generation is used to generate code from a higher level model to create a working application. Let’s consider the next example domain model specified in a Domain-Specific Language:
If we want to generate Java code for this little model we can use a template engine. A template contains the Java code with some tokens which will be ‘filled’ based on the model. We can for example use a template for each entity in the domain model. The template represents a Java class with the name of the entity as name (e.g. Customer). For each attribute a private field will be generated. For a detailed overview / tutorial about creating a DSL and its associated code generator see "Getting started with Code Generation with Xpand".
In case of model interpretation we do not generate code to create a working software application from a model. In case of model interpretation a generic engine is implemented in (for example) Java and the model is directly interpreted by this engine. This generic Java program for example contains a class Entity with a property "name" and a hashmap containing the attributes of that entity (name – value pairs). A Customer entity is in this case not represented by a Java class, but by an Entity object with the property name containing the value "Customer". These Entity objects are created based on the information in the model.
Both code generation and model interpretation are used in practice. Let’s look at the advantages of these approaches compared to each other. Read 15 reasons to start using Model-Driven Development for an overview of the advantages of a Model-Driven approach in general.
Advantages of Code Generation
Code generation has the following advantages in comparison to model interpretation:
- It protects your intellectual property: with code generation you can generate an application for a specific client. When using model interpretation you have to give your client the runtime engine which allows him to implement a whole class of applications. For example, if you can generate websites, you can give a client the code needed to run their website. With an interpreter, you have to give them the entire system for interpreting any kind of web application that can be described using your DSLs. This point is especially relevant when you have a software product line for a number of different clients.
- It can target your customers architecture: when using model interpretation you have to implement an interpreter following your own architecture of choice. In case of code generation you can generate code precisely following the guidelines of your client(s).
- The generated implementation is easier to understand: you can look at the generated code an directly understand the behavior of an application. In case of model interpretation you have to understand the generic implementation of the interpreter and the semantics of the model.
- Easier to start with: if you already have build an application by hand you can start using code generation by turning existing code into templates and replacing parts of the code with tokens which will be replaced by model information. If you have build multiple applications for the same domain (e.g. for different customers) you can start analyzing these applications. Static code (i.e. code being the same for all applications) can be put in a domain framework, variable code needs to be generated (i.e. you need to create a Domain-Specific Language to model the variability).
- It is more iterative: as explained in the previous point you can start using code generation by turning existing code into code generation templates. You can of course do this in an iterative way. First you only generate parts of the code and other parts will be implemented manually, later on you can extend your code generator to generate more parts of the code. The same holds for your DSL. At first it can be low level to reflect the code which will be generated. Later on you can tailor it more and more to domain experts by raising the level of abstraction.
- It provides an additional check by the compiler: when you generate code, that code need to be compiled. This compilation step is an additional check as compilers will check the generated code for errors. In case of an interpreter you will need to do these checks yourself during the interpretation of the model or you need to create a tight coupling between the modeling environment and its interpreter.
- Debugging the generator itself is easier than debugging an interpreter: if you need to debug an interpreter you need conditional breakpoints all the time because the interpreter code is generic.
- Changes in templates are easier to track: code generation templates are just text files, hence changes can be easy to track (e.g. by using a version control system). The same holds for changes in the code of the interpreter, however, this code is generic and its less clear what exactly has changed.
Advantages of Model Interpretation
Model interpretation has the following advantages in comparison to code generation:
- It enables faster changes: changes in the model don’t require an explicit regeneration, rebuild, retest, and redeploy step. This will lead to a significant shortening of the turnaround time.
- It enables changes at runtime: because the model is available at runtime it is even possible to change the model without stopping the running application. See Why Model Driven Software Development isn’t fast enough and how to fix it to read more about this interesting subject.
- Easier to change for portability: an interpreter in principle creates a platform independent target to execute the model. It’s easy to create an interpreter which runs on multiple platforms (e.g. multiple OS, multiple cloud platforms). In case of code generation you need to make sure you generate code compliant to the platform. In case of model interpretation, the interpreter is a black box, it doesn’t matter how it is implemented as long as it can run on the target platform.
- Easier to deploy: when code generation is used you often see that you need to open the generated code in Eclipse or Visual Studio and build it to create the final application. In case of model interpretation you just have to start the interpreter and put the model into it. Code isn’t necessary anymore. Hence, it is much easier for domain experts to deploy and run an application instead of only modeling it.
- Easier to update and scale: it is easier to change the interpreter and restart it with the same model. You do not have to generate the code again using an updated generator. The same can hold for scaling: scaling an application means initializing more instances of the interpreter, executing the same model. Especially in cloud environments this can give you advantages.
- It’s more secure: for example on a cloud platform you only need to upload your model, there is no need to access the file system or other system resources. Only the code in the interpreter can access system libraries. The interpreter provides an additional layer on top of the infrastructure, everything underneath is abstracted away. This is essentially the idea of a Platform-as-a-Service (PaaS).
- It’s more flexible than code generation: there are limits to template based code generation. In these case you will get the need for helper files to extend the possibilities of template based code generation. An interpreter can be less complex in these cases, and often less code is needed to accomplish the same result.
- Debug models at runtime: while the model is available at runtime, it is possible to debug your models by stepping through them at runtime (e.g. you can add breakpoints at model level). This only holds for action languages, not for declarative languages (there you’ll need static analysis). When debugging at model level is possible, domain experts can debug their own models and adapt the functional behavior of an application based on this debugging. This can be very helpful when for example complex process or state models are used.
If we look at the advantages of both approaches we can conclude that in the end it all depends on the domain, the use case, and the skill-set (or comfortability) of the people building and/or using the Model-Driven Software Factory.
When we discussed the differences between code generation and model interpretation, soon the question came up: what’s the difference between code generation and model interpretation? What is the boundary between these two approaches? What if we have an in-memory file system were we generate the code? What if we optimize our interpreter by compiling parts of the model? What if an interpreter generates a database structure and web content for browsers?
Do you think there’s a relevant distinction between code generation and model interpretation?
What do you see as the main advantages of both approaches?