Code Generation – Blessing or Curse?

There are lot of code generation tools available. Microsoft Visual Studio has had code generation possibilities since I started using it in the mid 90-ties. Code generation can be a blessing for getting something up and running quickly, but also a curse when maintaining code.

Whenever a code generation tool is considered, there are two very important aspects that need to be considered:

  • Is there support for regeneration when the code needs to be updated?
  • Are there possibilities to make adaptions without loosing them on regeneration?

Unfortunately a lot of the tools fail on at least one of these points. The blessing that helped creating something working quickly becomes a curse during further development and maintenance.

Regeneration Support in LINQ to SQL

One splendid example of different approaches to regeneration is in the two LINQ to SQL code generators offered by Visual Studio. The graphical OR designer looks great and it is effective for coming up with a first, working solution. The problems start when there is a change to the underlying database. There is no way to update the model and generated code from the database. In my opinion this actually spoils one of the strengths with LINQ to SQL: The type safety spanning from database to code. If the classes doesn’t match the database we get the problem with code and database schema mismatches back.

I very seldom use the OR designer. I prefer the other tool available, SqlMetal.exe, which can simply be rerun whenever there is a change to the database. With SqlMetal.exe I can be sure that my code is completely up to date with the database schema.

Adaptions in LINQ to SQL

Good code generation tools have support for keeping any adaptions made separate from the generated code. If we change the actual generated code, there is no longer any possibility to regenerate it without loosing our adaptions. LINQ to SQL uses partial classes and partial methods for this. Looking in the generated code, there are partial methods declared:

partial void OnBrandChanging(string value);

These partial methods are called at appropriate places in the generated code:

public string Brand
{
	get
	{
		return this._Brand;
	}
	set
	{
		if ((this._Brand != value))
		{
			this.OnBrandChanging(value);
			this.SendPropertyChanging();
			this._Brand = value;
			this.SendPropertyChanged("Brand");
			this.OnBrandChanged();
		}
	}
}

If we want to make sure that the system only handles specific brands of cars, we can implement the partial method in a separate file. Our adaptions are kept completely separate and will not be lost if the code is regenerated.

public partial class Car
{
    private static readonly string[] validBrands = new string[] { "Volvo", "Saab" };
 
    partial void OnBrandChanging(string value)
    {
        if (!validBrands.Contains(value))
        {
            throw new ArgumentException("Illegal brand specified");
        }
    }

Entity Framework Entity Designer

Using Entity Framework there is a similar designer as for LINQ to SQL where a database table can simply be dragged onto a drawing surface to create a class in the code. For EF there is also a refresh functionality that can update the entity model when the database change. Unfortunately not everything is updated. Internally EF has three layers:

  • Data Source Model
  • Object Model
  • Mapping between the models.

When updating, only the data source model layer is updated. The object layer and the mapping layer have to be updated manually.

Scaffolding vs. DynamicData

Yet another example is the ASP.NET MVC Scaffolding system and the ASP.NET Dynamic data package. Both provide a quick way to setup web forms for editing an Entity Framework based data model, but they use completely different strategies. The scaffolding package is a one-shot code generator that creates the code for us. From that point on the code has to be maintained and updated manually.
Dynamic data on the other hand never creates any code. It creates the necessary web forms dynamically during runtime. The created forms can be controlled by setting attributes on the model classes. With dynamic data it is enough to add a new or changed field in one place – the model. With scaffolding it needs to be added both in the model classes and the forms.

Conclusion

Code generation tools are powerful and can be a blessing to get something up and running quickly. If regeneration and adaption support is poor, they quickly turn into a curse during further development and maintenance. Whenever a code generation tool is considered, pay attention to the whole life cycle of the code. At least try the three key steps:

  • Creating code
  • Making adaptions
  • Updating when the underlying data model has been changed.

During the code’s lifetime adaptions and updating will be done many times while initial creation is done just once.

2 comments

    1. With the LINQ to SQL code generator that is indeed possible, at least in the pre defined extension points that are offered by partial classes and partial methods. I think that they offer quite a lot of hooking points, but there are of course case where adaptions are not possible to place in a separate file. For example it is not possible to add custom attributes to the generated fields without loosing them on the next regeneration.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.