Code generation

From cdd
Jump to: navigation, search

CDD is a "proof of concept" to see if object orientation can be improved by splitting up classes/objects into smaller pieces with well defined roles. This is done by using parsing and code generation. Another possible solution would have been to create a compiler. The compiler alternative is a cleaner solution but results in much more work. Code generation also has the advantage that the generated code is clean and accessible and therefore easy to read and debug.

Many developers have had bad experience with code generation. CDD tries to change that by not getting in the way of the developer. CDD generates the code needed to assemble the different building blocks, which is the type of code that is often both tedious and difficult to maintain. The code that remains to be written is focused on defining state and adding behavior suitable for different contexts. The hope is that CDD will make you a better developer and the work easier and more fun!

The code generation is performed by the combined code and parser generator Laja. The target language is Java. There are no technical barriers to implement CDD in other languages such as C++, C#, Ruby or Scala, but at the moment only Java is supported. If you are lucky to work in a functional language, like Clojure, you have no need for CDD!

If we take a look at the Quick-start guide, it has the following structure in the IDE:

Project-directory-structure.png

Let's explain some of the basic concepts of CDD by looking at the classes from the Quick-start guide example (package statement, imports and generated code has been removed):

State

public class PersonState implements ImmutableState {
    public final int age;
    public final String givenName;
    public final String surname;
 
    // ===== Generated code =====
    ...
}

Creator

public class PersonCreator implements PersonCreatorMaker {
    private final PersonMutableState state;
 
    public Person asPerson() {
        return new Person(state.asImmutable());
    }
 
    // ===== Generated code =====
    ...
}

Behaviour

public class Person extends PersonBehaviour {
 
    public Person(PersonState state) {
        super(state);
    }
 
    public boolean isTeenager() {
        return state.age >= 13 && state.age <= 19;
    }
}

Main

package com.myproject;
 
import static com.myproject.PersonCreator.createPerson;
 
public class Main {
 
    public static void main(String[] args) {
        Person person = createPerson().age(18).givenName("Ingmar").surname("Bergman").asPerson();
 
        System.out.println("Is teenager: " + person.isTeenager());
        System.out.println(person);
    }
}

output

Is teenager: true
Person{age=18, givenName="Ingmar", surname="Bergman"}


If we take a closer look at the statement that creates an instance of Person:

Person person = createPerson().age(18).givenName("Ingmar").surname("Bergman").asPerson();

...we can see that CDD starts by building state and ends with encapsulation by choosing a behaviour representation that can be used in a specific context.

All generated code is inserted at the end of the state and creator classes, after the comment // ===== Generated code =====. All code before that comment is preserved, including the imports which is never touched by CDD if the "Generated code" comment exists. If CDD can't find the "Generated code" comment, the imports will be updated and the // ===== Generated code ===== comment will be inserted at the end of the class, followed by the generated code.

Because CDD doesn't touch the imports, the only way to let CDD refresh them is to remove all the generated code including the "Generated code" comment and regenerate. The other alternative is to add them manually.


< Back          Next >