Thursday, June 07, 2007

The 5 Laws of Code Generation

A colleague of mine from Magenic has written an blog about code generation which summarizes a conversation we've been having:


I really like this post because it nicely lists all of the aspects of code generation that I have been thinking about but haven't been able to put into words. What's nice is that I've tried to address each of these problems with NBusiness in one way or another. Some of these solutions are somewhat unique, especially in terms of the Template system. The following are descriptions of how NBusines resolves the issues outlined by Jon in his post.

CSLA places most of the "heavy lifting" in a set of common base classes

NBusiness does not use CSLA, instead it comes with a light weight, medium-trust, business object framework. It mirrors most of the core features of CSLA as a business object framework but does so in a very different way (due to the need for medium trust). However there is no reason why NBusiness couldn't be used in conjunction with CSLA (or any other framework) since it is template driven but I wanted the official distribution to be completely self contained for now.

I have some fairly specific "technical requirements" that I think that code generation has to to provide:

To me this list is like the "10 commandments" of code generation. Only there are 5, so let's go with the "5 laws of code generation". I'll summarize his list and try to explain how NBusiness conforms to these laws.

1. Code generation is controlled through modifiable templates.

In NBusiness everything is generated by a template. Rather than using any of the existing template schemes (as far as I know) NBusiness takes a unique, more object oriented, approach. The templates themselves are actual classes that inherit from a Template base class. They contain a single method with the signature "ResourceFile[] Generate(Entity[] entities)". The resource files contain a byte[] and path for the resulting files (you could concievably generate images or other binary resources based on entities this way). Of course what goes on in the Generate method is completely up to the template developer. Furthermore, this scheme allows for inheritance in templates. So, for example, if you decided to use one of the templates that came with NBusiness but you just don't quite like one line of the output, you can create your own template and override an appropriate virtual method and customize the output yourself without destroying the original template. This more object oriented approach brings forth some interesting possiblities.

There is also a notion of template "dependencies", which allows you to selectively generate code if an Entity contains a template that fulfills a dependency. For example if you have a template for generating an EntityBaseCollection object, you'll naturally need an EntityBase object to be generated as well. Therefore the EntityBaseCollectionTemplate is dependent on the EntityBaseTemplate. This problem arises quite a bit and this solution is very helpful for solving these issues. Without it you end up getting to a point where you might as well just make one giant template and apply it to all of your entities rather than selectively implementing only what a particular entity needs.

2. Code generation is done during the build process.

This law is one of NBusiness' best features. Not only is done during the build process the NBusiness engine is actually a compiler. In fact the artifact that NBusiness produces is a class library rather than simply a set of classes to be loaded into a seperate class library project. In v2.0 this is automated fully by means of Visual Studio Integration. You litterally have an E# project that can be referenced by your other projects as intuitively as you would any normal class library.

3. Code generation is done from an intermediate format.

This law is very important to me. NBusiness goes one step further than what Jon is suggesting as the optimal solution however. Jon suggests using XML that is (optionally) generated from a database schema, which I couldn't agree more as the right solution to the problem. However instead of XML NBusiness features an Entity Definition Language known as E#. It is essentially the same thing: a set of meta data that describes your entities. However it is my belief that XML really isn't as developer friendly as what is really needed. Rather than creating all sorts of grahpical development tools that allows a developer to manipulate this XML what is really optimal is to have a model that is the same as what most developers are currently most familiar and productive with, which is code. E# (in v2.0) has visual studio integration which comes complete with syntax hilighting and intellisense and allows a developer to build their entity meta data in a style similar to what they are already familiar with. The only barrier is that you have to learn "yet another language" to do it. E# strives to be extremely simple by having syntax similar to C# and it is also fairly VB-ish in how the keywords flow. Intellisense helps quite a bit as well of course.

4. The intermediate format is under source code control with versioning.

This law is helpful for restricting the definition of what the intermediate format is. I would suggest an ammendment to this law that states the intermediate format must also be such that it is compatible with "merging" features of source code control. This will promote the ideal of having this data as plain text rather than a custom binary format. Of course, since E# is defined in source code files it meets this law fully.

5. The code generation templates are also under source code control.

Again I would ammend this with the mergability rules from #4. In the case of NBusiness the base templates are source code files currently under source control at CodePlex while custom templates would simply be class files somewhere in your project, which is absolutely compatible with source code control.

The next section of Jon's post addresses more of the features required of a business object framework as they relate to code generators. This is an important distinction because, while NBusiness has such a framework, it could certainly be used to target any 3rd party business object framework which may or may not conform to these rules. This is mostly a concern of the templates but there are definitely accommodations for a particular style that need to be taken in the framework itself. NBusiness' default business object framework takes the second style, where partial classes are used to accomodate custom code.

To me the main benefit of this is the cleanliness of the resulting object model. While I'd concede that the base/child style is functionally fine, I would argue that having fewer classes is far superior. The tradeoff, is that you end up having to expose many events in order to provide extensibility points for the other parts but this is ok to me. In fact in NBusiness there is a feature called "actions" that allow you to define the behavior of an entity as a method. These actions can optionally be attached to these extensibility events and even be automatically executed asynchronously. This action method is implemented by the developer in a partial class or even as a static method on another class entirely. So these events would be there anyway.

An example of this might be a "TransferMoney" action on a BankAccount entity. Or a Log method attached to the "persisting" event, etc. You can envision how useful it is to define your entites behaviours in the entity definition itself. The architect can define everything and the code monkey can implement it.

So with Jon's post in mind I propose the 5 laws of code generation:

  1. Code generation is controlled through modifiable templates.
  2. Code generation is done during the build process.
  3. Code generation is done from an intermediate format.
  4. The intermediate format must be versionable and mergeable.
  5. The code generation templates must be versionable and mergeable.


Post a Comment

Links to this post:

Create a Link

<< Home