Trunk Based Development is a style of software development where all developers commit their changes to a single branch (trunk) in source control. The advantage of trunk based development is that there are no long-living feature branches. The idea is to hide the unfinished functionalities with feature toggles. But how are we going to make these toggles manageable?

How can we manage to limit the number of toggles? How to manage that there are no long-living toggles?

To achieve these goals, we are going to write an annotation processor (in a form of a lib in pure Java) to get build-time information about the feature toggles. (This was inspired by ButterKnife)

ToggleProc

Let’s call this library ToggleProc, it will be a pure Java implementation, which can be used in Android and Java applications, and it will be bundled as a library. Source Code

This library has two annotation interfaces, FeatureToggleConfiguration and FeatureToggleBind. The first one is a class annotation, which defines a configuration file (class) that contains all toggles and the FeatureToggleBind is used to annotate a toggle.

FeatureToggleConfiguration has 2 parameters:

strictnessPolicy , an enumeration of {COOL, MODERATE, HARSH}:

- COOL: no build error, only warnings

- MODERATE: build error when the toggle is expired, in other cases build warning

- HARSH: build error when toggle is expired, the number of toggles exceed the maxNumberOfToggles and when the toggles are too futuristic (a period of 8 weeks)

, an enumeration of {COOL, MODERATE, HARSH}: - COOL: no build error, only warnings - MODERATE: build error when the toggle is expired, in other cases build warning - HARSH: build error when toggle is expired, the number of toggles exceed the maxNumberOfToggles and when the toggles are too futuristic (a period of 8 weeks) maxNumberOfToggles: max number of toggles allowed in this configuration file.

The RetentionPolicy is SOURCE, which means that the annotation will be discarded by compiler. And the Target is TYPE, which means that this annotation will be used by Class, interface (including annotation type), or enum declaration.

The toggles are defined using the FeatureToggleBind annotation. This annotation also expects two parameters:

expirationDate: yyyy-MM-dd, e.g. 2017–12–30

toggleName: a name

The RetentionPolicy is set to RUNTIME, which means that annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively. It is set to RUNTIME because we might want to list all toggles and their values at runtime using reflection.

field.getAnnotation(FeatureToggleBind.class);

The Target is set to FIELD, which means that the annotation can be used in combination with a field declaration (includes enum constants).

An example of a configuration file will look like:

Validation

The validation rules are:

Check if the number of toggles doesn’t exceed the specified maximum number of toggles.

Check if the expiration date of a toggle is not expired.

Check if the expiration date of a toggle is not too futuristic

If these checks don’t pass then we throw an error and break the build or just show a warning (depends on the strictnessPolicy)

Annotation Processor

What is the Annotation Processing and how does it work in java?

Annotation processing is a tool build in javac for scanning and processing annotations at compile time. All the source files specified on the command line are read, parsed into syntax trees, and then all externally visible definitions are entered into the compiler’s symbol tables. All appropriate annotation processors are called. If any annotation processors generate any new source or class files, the compilation is restarted, until no new files are created. Finally, the syntax trees created by the parser are analyzed and translated into class files. During the course of the analysis, references to additional classes may be found. The compiler will check the source and class path for these classes; if they are found on the source path, those files will be compiled as well, although they will not be subject to annotation processing.

Let’s create an annotation processor, this processor is responsible for the validation of the toggles and creating a Java class (using the JavaPoet lib), which is responsible for binding of the toggles with their values. Our Processor extends the AbstractProcessor and it will implement the public boolean process(…) method. We will also tell the compiler that we are interested in FeatureToggleConfiguration and FeatureToggleBind annotations.

Before implementing our processor, we have to define our data-model for some bookkeeping. The data model contains 4 classes:

ToggleBinding : contains toggle information (attributes in FeatureToggleBind annotation) such as the expirationDate and toggleName of a toggle, e.g test1 with expirationDate of “2018–01–01”.

: contains toggle information (attributes in FeatureToggleBind annotation) such as the expirationDate and toggleName of a toggle, e.g test1 with expirationDate of “2018–01–01”. ClassBinding : contains all toggles (ToggleBinding) declared in a given class annotated with FeatureToggleConfiguration, e.g. class Config with toggles test1, test2 and test3.

: contains all toggles (ToggleBinding) declared in a given class annotated with FeatureToggleConfiguration, e.g. class Config with toggles test1, test2 and test3. PackageBinding : contains all ClassBinding in a given package.

: contains all ClassBinding in a given package. BindingSet: contains all PackageBinding.

During the Annotation Processing phase, for each supported annotation types (FeatureToggleConfiguration and FeatureToggleBind), the Annotation Processor will fire the process method. First we will start recording all the information we need, using our data-model. Once our data-model is filled with the data, we start checking the expiration date and number of toggles. Based on strictnessPolicy, either we break the build by throwing an error or just give a warning. After this validation process, we generate a java class that binds the toggle with the toggle logic, which tells if the toggle is enabled or disabled. Because we don’t have the implementation of this logic, we use the interface FeatureToggler. The user has to provide its implementation.

The FeatureToggleProcessor generates a Java class, called FeatureToggleBinder. It contains one static public method bind(FeatureToggler toggler, Config target). This method is generated in generateBindMethod function. The generated class will look something like this:

If we are using FireBase remoteConfig to set the value of the toggles then the implementation of FeatureToggler might look like this:

Registration

We have to make Java compiler aware of our annotation processor. There are several ways to that. The easiest way is to specify it in the META-INF/services/javax.annotation.processing.Processor file as a fully qualified class name of it.

com.abnamro.nl.toggle.processor.FeatureToggleProcessor

Now the compiler knows about our Processor and it will trigger it during the Annotation Processing phase.

Conclusion

Trunk based development is a source-control branching style, in which developers collaborate on code in a single branch, resist any pressure to create other long-lived development branches by employing documented techniques. They therefore avoid merge hell, do not break the build, and live happily ever after.

The idea is to hide unfinished functionalities with feature toggles, also known as feature flags. In this blog we have used the power of Annotation Processing in Java to make these flags manageable, which will give us feedback during the build-time. This way, the developers are forced to keep the number of toggles limited and respect their expiration dates.

The ToggleProc library is OpenSource, feel free to contribute to it and make better. Source Code