Finally! Finally we can take a look at some code!
As discussed last time, we start with generating POJOs out of the model, the simplest exercise ever, and this is exactly what our implementation is doing (BTW, to run the code, just type coffee pojo.coffee).
But perhaps first I should make a remark concerning CoffeeScript syntax: If you are a JavaScript developer and don't know this syntax, here is a nice comparison of CoffeeScript and ES6 (and you might also notice, that ES6 will already include support for most of the features we are using). If you are coming from Java, I hope you are familiar with Stream API. If you are a .NET developer, notice similarities with LINQ. Otherwise you can always take a look at this tiny overview of the language features on the CoffeeScript homepage.
So let's come back to the code now.
It's so small, I don't think we need to spend too much time discussing the details, but the general structure is probably worth a look.
As we have seen from the theoretical part last time, our code needs to contain 2 parts: Model-to-model transformation(m2m) and model-to-text-transformation(m2t).
This separation is also clearly seen from the code:
- m2m: We transform the inputModel (our original JSON model) into the outputModel in such a way, so that it contains all the necessary information for our templates to generate code out of it. And this is exactly what we are doing in lines 9-22: Copy everything except the associations from the original model and then process the associations to include information about them in the corresponding class definitions (don’t forget to add default names for association ends: since in our model the name “wrote” is defined only on one end, for the other one we need to generate something meaningful, like “getAuthors”).
- m2t: We define code generation templates in form of functions (lines 25-43) and then apply these templates to every class of our transformed model (lines 45-49).
Ok, this was simple enough. Altogether less than 50 lines of code, not too bad (even if it is probably not the most meaningful metric in this case).
But let's see how well does this approach scale: how about making our associations auto-updateable?
Here is the code.
So what has changed?
The m2m part got a little bit bigger - now every association belonging to a class not only has to know about the class it references, but also about the class it belongs to. Of course, we could just find all this information on the fly from the model, but why bother, when we can spare this effort by just coping the needed parts. At the end of the day, this is why we use transformations at all.
And what about the m2t part? Here we got a lot more templates: separate templates for attributes and associations, initialization of empty lists..
And, of course, all these different cases in handling of the references: Many to many, one to many, one to one. Setting of an item, resetting of an item. Adding an item, removing an item. It is a lot of templating here.
Unfortunately I don't think we can do much about it - we want to generate code and need to specify templates. This way or another, it needs to be done.
But there are several other problems here:
- Our file got quite big, about 100 lines. This is not so good, it's better to split it.
- What about the package name for our classes? Right now it is taken from the model, but what if we have several models (or actually the same model, but just splitted into packages between different files). Do we then need to put it in every file? Or do we define one "main" file, containing such information? Not good. We need to make it more flexible, we need to pass the package name to our code in some other way. Same goes for the input folder, where the model can be found, and output folder, where we want to have our generated code saved.
- And what about the testing? Right now, with all this file reading and writing, it would be impossible to write unit tests for such a module. But we need to write tests. We are pragmatic here, but not stupid.
So let's see what we can do about these issues next time.
No comments:
Post a Comment