As an ArgoUML contributor I'm going to blog my activities here, so that they may draw interest by other developers or help other developers when doing tasks similar to what I've done. AND(!) the grand vision that makes an Argonaut what he is, TO THRIVE IN THE BIG DANGEROUS WORLD, TAKING THE Argo TO A GOOD SHORE ;-))

Monday, November 12, 2007

Refactoring org.argouml.uml.profile

As stated in issue #4885 and in the dev mailing list thread "org.argouml.uml.profile - success in working from models and improvement proposals", I'm working in refactoring the profile sub-subsystem of ArgoUML so that it is possible for modules to define their own profiles. The main problem to get rid of is that there are singletons in it, such as the ProfileManagerImpl. This class is a singleton and besides some very few exceptions singletons are an abused design pattern. More so in Java projects, since Java doesn't support global variables and, guess what, a singleton is a replacement of the humble global variable, even if it is very clumsy and pernicious.

Before proceeding with my rambling about singletons being bad, let me say that I'm very happy with the work contributed by Marcos Aurélio, one of the developers that joined in the Google Summer of Code 2007. The package org.argouml.uml.profile is congruent, being absent of monster classes and methods, with a nice balance between abstractness and implementation classes and with a very pleasant distribution of responsibilities amongst the classes. Furthermore, so far I haven't found a single defect!

The refactoring will be much more easy than what I will have to do to improve the GeneratorCpp – which is a singleton :-( ... and that bring us back to my rambling...

Singletons are clumsy, because instead of one line of code declaring a variable at global scope1, one line initializing it in some appropriate place of your code and a direct reference from where you want to access it, you now have to define a private constructor, a static accessor method and then, call this method from wherever you need to access it from. It is pernicious because if you wanted to abstract the implementation of the global variable, it won't be possible – every single user object will now refer to the singleton class directly, even if they don't need to, because one of their owners or more closely related objects could have provided it themselves. Another bad effect is that when eventually the application evolves and you would like to have more than one of those objects, or to have a fresh one for another piece of work or for unit testing, you'll have the singleton and the singleton accessing code stopping you from doing it.

Today I found yet another pernicious effect – loss of control of initialization order. In my checked out copy I have made a spike to check if the plan of having the C++ module providing the UML profile for C++ would work based on the recently contributed support provided by Marcos AurĂ©lio. So, in C++ module I have defined a new ModuleInterface implementation that registers a ProfileCpp object in the ProfileManagerImpl instance. Now, guess who is now instantiating indirectly both ProjectManager and ProfileManagerImpl? Yeah, the humble C++ module or better indirectly the ModuleLoader2 is doing it! Worst, while at it, I noticed that the order of initialization of modules by ModuleLoader2 seams to be arbitrary. Because SettingsCpp is also loaded as a module, and it accesses the GUI instance, this will also be initialized not by the Main.main in an explicit way, but, indirectly by the SettingsCpp module.

Isn't this bad?!?

The way to solve this is via explicit initialization of subsystems and subsystems which keep the details for themselves. The best example is the org.argouml.model subsystem. It provides means for explicit initialization and access to it is via static functions of the Model class.

Alas, the Profile subsystem may not need to have several implementations as required from the Model subsystem, so, I won't restrict its implementation so much, such as having only interfaces available for clients, but, I think it will be easier to use and maintain if it looses some of its singletonitis. Check the ideas in issue #4885 and please send some feedback if you have ideas on how to deal with this differently.

1 In modern programming languages, "global variables" aren't normally global anymore, since normally they are contained in a specific package or namespace. A pair of good examples is the java.lang.System in Java and std::cout in C++. These "globals" aren't frown at and the libraries were design by developers above the average for sure, so, why is an accessible variable so bad?!?

No comments:

Reader Shared items