What is the FINA Generator and what is it good for?
The FINA Generator ("FINA Is No Abbreviation" or "Fluent INterface Automation" just what you like better) is a tool for creating custom typesafe fluent interfaces for software components from a rather simple XML description. The fluent character of these interfaces makes it possible to gain some interesting features that conventional "flat" interfaces cannot offer.
The underlying concepts in this approach are:
The interface specification is supplied by the component provider and describes semantic relations between the methods offered - possibly even with regard to the concrete use scenarios of special customers.
The generated interface is primarily represented by a finite state machine, that implicitly allows the user only to specify valid method chains. Furthermore, users can e.g. cut out unused features by themselves, because model and implementation are seperated even in the delivered interfaces.
Main advantages are:
The FINA Interfaces can be delivered side by side with the conventional flat interface.
The declarative usage makes component configuration more flexible as well as easier to survey for not only new users.
If users work with an IDE like Visual Studio, only the valid methods for the "next step" in configuring the component are shown in the IntelliSense window (this makes handling much more intuitive for unexperienced users)
The method chains used are validated at compile-time - if something is wrong this is reported to the programmer at compile-time and not to the user at runtime
All this semantic behavior is part of the component and implicitly given when using the component in development - a great benefit in contrast to descriptions outsourced in seperate files the user must read to understand how to use the component.
Multiple interfaces for one component keep apart different scenarios in which the component can be used - or customers with different use-cases .
Multiple configuration paths can seperate different concerns to be configured in a single use-case.
Interface specifications are language-independent!
Opportunities in lifecycle and versionmanagement are very likely to be achieved, because the interface-code is generated from specifications that are more general than source code. This makes the known advantages of Model Driven Development available to interface design in Component Based Development.
No more trouble with new versions of third-party components! If there are incompatibilities the compiler will tell you. At the same time wrapper-classes for third-party components become unneccessary, because the changing-problem is limitted largely.
Two short examples on how to use those interfaces
The following examples apply to a rather complex interface description for configuring a bar chart using the Google Chart Sharp component. Although the creating processes is structured into separate configuration steps, to illustrate the build-in flexibility of the FINA concept, the examples will show two different ways to construct exactly the same component.
After entering the FINA Interface by calling it's accessor BuildBarChart,there are five methods available in this first configuration step. Obviously the user will recognize the methods Width, Height and Size to depend on each other. So lets invoke Size and see what happens next...
In this example the situation is the same. But instead of Size will will invoke Height and see what happens next...
When invoking a method within a FINA Interface, of course an IDE will show the parameter list as defined in the interface description. For a method like Height this is less interesting, but for Size or more complex methods this becomes necessary. At this time a rollout of method and parameter descriptions into the interface model is still a TODO feature. So for Size you will see something like:
After invoking Size it would not make sense to use Width or Height, because this would define redundant settings. The ability to allow a declarative syntax means that the interface can be specified in a way that it only accepts one value per setting. As you may have guessed already, after invoking the Size method the situation looks like this:
In this example Height was used instead of Size. Accordingly the Width method is left and the Size method disappeared. Setting the width of the bar chart is necessary in order to create a valid BarChart object using this FINA Interface (the specification describes it to be necessary!). So we do this subsequently:
After this there two more methods that can be used: Orientation and ShowStacked. Here we decide to use Orientation first. This is a necessary setting that can complete the first configuration step. Nevertheless the ShowStacked method is still available:
Over here we call the optional method ShowStacked first. But because Orientation is necessary we are forced to specify it now (mention that the SetData method is not available yet, because the current configuration step is not complete):
Now we have completed the first configuration step and only methods of the next step are available:
It's the same in this example. We are only allowed to use SetData now:
This second step consists of only one method. We must decide between specifying one or more sets of data. To make things not too complex we use only one data-row. The next step is an interesting one, because the interface recognizes which overloaded version of SetData was used and now offers an appropriate method to set a single color for the single data-row. If we had specified more than one set of data, we would now have to set multiple colors too! (the SetDatasetColors method would have been available)
The same in this example:
Now we have set almost all necessary values. What is left are chart axes and some optional settings. The AddAxis method is specified to be used minimum once (the "+" symbol in the interface specification). So we must add one axis in order to be able to build the application that contains this method chain:
The same in this example:
Mention that a method chain that does not invoke AddAxis will not compile! This is because the result of the SetDatasetColor method cannot be casted to the BarChart class implicitly!
This is the resulting code for the first example - it builds without raising errors:
The code for the second example returns exactly the same object. It differs from the first example only in the way things are specified: