Applying Code Generation Approach in Fabrique

Usage from hand-written code

Usage of business objects is very simple. Inside Fabrique Model you can be sure that there's always a visible variable for each manager object. You don't care how it's initialized, you just write something like:

   Collection fabriquePeople = developerManager.findDevelopersByProject(“Fabrique”);

Coding assistance

Complete coding assistance is provided by Visual Fabrique:

Code completion:

figure 6

Find usages:

figure 7

The cool thing here is that you work with interfaces that have nothing to do with the target persistence platform. You don't have to write redundant casts when working with business objects and you don't see any unrelated methods there since their interfaces are completely generated.

Refactoring it all together

One of the reasons people are conservative about applying code generation is the fact that generated code is not easy to maintain. What happens, if I want to change something, say – to rename a business object?

Fabrique was designed with the idea that you should never have to hack generated code. If you want to rename something, Visual Fabrique will take care of renaming all references in your model and then regenerate the affected code.

figure 8

On-the-fly generation

Visual Fabrique doesn't have to run the compiler to provide assistance such as code completion. To tell the truth, it does run it, but only to generate platform-independent code, which is a pretty quick thing. You don't sit around waiting for Visual Fabrique to regenerate all the code on every change. Full code generation happens only when it's time to deploy. Even then, Visual Fabrique tries to make it as incremental and time-efficient as possible

Managing transactions

In Fabrique, there is something more than just making development abstract from concrete persistence platform. Fabrique provides a platform-independent implementation for transaction management specifically designed for web applications. This simply means that some typical work that web developers do has already been done for them.

For example, each web page instance always lives inside a transaction. Any changes to business objects will be local to the transaction until the transaction gets closed. Here is how it's done:

figure 9

Logic inside the web page always works with copies of business objects. Managers of business objects are accessible as we described above, and we can be sure that each time we use, say, the "developerManager" variable, it points to a local copy of the DeveloperManager object, and all objects the manager creates are local for the transaction.

As the page gets closed, all local objects are either dropped or saved to the database. It's managed by a simple API that the logic inside the page can use:

In addition, it's possible to create nested transactions and either commit or roll them back as a whole.

So, lots of typical work is already done, but if we want something specific like the creation of nested transactions – a Fabrique transaction API is open to us. This is very simple. In Fabrique, almost in every place where you write FabScript, there is appropriate set of context variables. In a web page, among others (like "developerManager", see above), there's one called "transaction".

The cool thing about Fabrique transactions is that they're platform independent like the things we considered before. The rules are the same – we don't have to decide on a platform, and we let the complier generate all the implementation for us.

Kirill's photo

Kirill Kalishev

Kirill is Senior Software Developer at JetBrains. He was instrumental in the creation of the company's award-winning IntelliJ IDEA IDE. He now works on core parts of the Fabrique project.

Contact Kirill via email: kirill(.)kalishev