воскресенье, 6 апреля 2014 г.

Singleton Registry and constructor categorisation

It's been a while science I did something on jet framework but today I'm going to wrap up with Singleton Registry. One problem that I encountered is that Singleton can't impose restriction on managed class constructor signature. The simplest case of a class with just default constructor is what I'm trying to solve, but any other "requirements" for construction interface are not less restrictive.
Ideally a user should be given option to define some "conventional" constructor or if it's not possible the user should provide constructor argument adaptor and Singleton Registry should prefer this adaptor to any other ways of managed object creation.
The reason I don't want to fallback to usual "factory" approach when user provides "create/destroy" pair of functions is that logically an object lifecycle should be managed by Singleton Registry and not by its client.

I came to the thought that I need a way to categorise constructors of class managed by Singleton. Here is my list of Singleton construction cases:
1. Default constructor;
2. Constructor that accepts Application Context;
3. Constructor that accepts single parameter and an adaptor provided by user which accepts Application Context and returns object of type that can be used to invoke this constructor;
4. Constructor that accepts multiple parameters and an adaptor provided by user which accepts Application Context and returns std::tuple with elements that can be used to invoke this constructor;

These categories are presented in order of preference which means that if some class has default constructor and constructor with the single Application Context parameter then App Context will be preferred for construction of the Singleton instance (because it gives more information for the class).

In my previous post I mentioned that I'm going to implement Singleton Registry but didn't give any details of what I meant by that. Another missing point is what Application Context is. I will give detailed description of Singleton Registry design later but from the name it's already obvious that it's an object that is used to register singletons.
The idea is to separate a Singleton creation and usage. In "Classical Singleton" both creation and usage is combined together which causes much trouble for a user if he wants some special parameterisation or be more specific with the moment when Singleton has to be actually created. This is mostly solved with boost::singularity but it also takes away most of the Singleton attraction. In the ideal world where a developer controls all parts of an application boost::singularity works fine but in practice the requirement to manage Singleton lifecycle explicitly is too inconvenient. I'm talking about usual workflow when all Singletons are initialised at the beginning of function main().
One of the problems with this approach is dependency tracking - only Singleton object knows what other Singletons it depends on and this information is required for correct order of initialisation. If Singleton initialisation is done manually then there is a big chance that some dependency will be missed.
Another problem is that a Singleton parameterisation should be done by library that uses it and not by the function main(). There are other reasons not to allow a developer to manage Singleton lifecycle manually.
The solution for these problems is Singleton Registry that manages Singletons lifecycle, dependencies and parameterisation. So basically a Singleton registers itself in the Singleton Registry and then everything is done by Singleton Registry which initialises Singletons at the beginning of the function main() (or any other place).
Here comes Application Context. Let's assume that in general the only "genuine" Singleton for an Application is the Application itself (this is viable assumption although I'm not ready to prove it). In this case all other Singletons created by specific application should depend on the Application Singleton. Another assumption is - whatever information is required for creating Application Singleton should be enough for creating any other Singletons (this is Application Context definition).
As an example - possible Application Context of a simple console application consists of environment variables and command line parameters. For more complex cases it can be configuration files, database tables, Windows registry records, etc...
This view on Application means that a Singleton is just an Application property so in fact it can be implemented as a data member of Application class (I saw such implementations). The reason why you may not like this implementation is lack of flexibility. Consider the case when an application consists of several libraries and each library contains some singletons - every time a library adds a singleton we need to update the Application class.
These two assumptions greatly simplifies all answers on Singleton related questions, for instance:
1. When a Singleton has to be created?
The answer: A Singleton lifecycle is bound to the Application (and other Singletons that it depends on) thus logically it has to be created after all its dependencies and destroyed before them;
2. Can a Singleton be recreated?
The answer: No, a Singleton can not be recreated because it will break its possible dependencies. But if you wish you can recreate the whole tree of Singleton objects starting from the Application;
3. How Singleton can be used with unit tests?
The answer: Every unit tests that require new state for particular Singleton has to recreate the Application Singleton and all other Singletons. If some unit test can share Application Singleton state and others Singletons' states then all Singletons have to be initialised only once before execution of these unit tests;
4. What about lazy initialisation of Singleton - is it allowed?
The answer: Yes, it is. But you should consider overhead of thread synchronisation which prevents data races in multi-threaded environment. Singletons that are initialised at the beginning of an application execution don't need this synchronisation.
5. What if a Singleton requires some initialisation parameters that are not in Application Context (for instance user input)?
The answer: Since a Singleton is a property of the Application then any information available during the Application construction should be enough for construction of the Singleton. If it's not the case then this object is not a Singleton.
This is the weakest point but I don't like the idea of mutable Application Context. This problem can be solved with  hierarchies of components. For instance, the Application is top level component of a program. Any Singleton attributed to the Application uses its Application Context (constant during initialisation of the Application). There could be plugins loaded later during execution of a program. Any Singleton attributed to the plugin will use that plugin Context for initialisation (which can be different from the Application Context). Lifecycle of those Singletons depends on the plugin's lifecycle.

The problem with Application Context is that it has to be general enough for any kind of applications. Initially I thought that it can't be achieved but then a help came from boost::application library. It implemented boost::application::context type which is actually an aspect_map. I'm leaving explanation of application::context and aspect_map to boost::application documentation
In fact I was really lucky to find boost::application - otherwise I had to write something similar.

After this long side-story I can return to initial problem of constructor classification. Implementation is a bit tricky with a lot of obscure templates but this is normal for SFINAE way of programming. In general classification method is simple - the code associates some number with each category:
1. Default constructor: 4;
2. Application contest constructor: 8;
3. One argument constructor with suitable adaptor: 16;
4. Multiple arguments constructor with suitable adaptor: 32;
Then algorithm tests whether a type can be constructed in particular way (this is SFINAE part). If a test fails then result values for the category is 1, if it succeeds then category result equals to this category number.
After that all 4 results are summarised and this value is used by Singleton Registry to chose suitable constructor.
For instance:
A class with just default constructor will have classification result value = 4 + 1 + 1 + 1 = 7
A class with default constructor and multiple arguments constructor will have result = 4 + 1 + 1 + 32 = 40.
For any possible combination:
If the result value falls into the range of (4:8] then Singleton Registry uses default constructor;
If the result is in the range of (8:16] then Application Context constructor is used;
If the result is in the range of (16:32] then single argument constructor with adaptor is used;
If the result is in greater then 32 then multiple arguments constructor with adaptor is used;

пятница, 21 февраля 2014 г.

Initial contents of jet framework

I have many candidates for inclusion into "foundation framework" but I need to round up initial stage of development and start using the library. So the most necessary facilities are:
1. Configuration;
2. Exceptions;
3. Logging;
4. Application initalization;
5. Singleton registry;

Whenever it's possible I will use existing solutions/libraries.
I couldn't find suitable configuraton library, so I implemented it by myself. In fact boost::property_tree is almost ideal for this purpose but it has some issues so I wrapped it in jet::config library.
Chained exceptions are not popular in C++ but I think they are esential for simple error diagnostics so I created jet::exception with chaining. I will also implement backtrace taken at the point where the first jet::exception in a chain was raised.
In the above list the logger is the most complex component. I compared several available log libraries and I found that it's very hard to choose despite the fact that logger is required in many applications and it should be very well developed area. One thing that I know for sure - it's impossible to use one logger for all cases. So maybe I have to split this task into two and use "general purpose logger" and "high performance tracer".
By "application initialisation" I mean that there are many questions that are not decided by traditional function main(), e.g. how to integrate application with its environment, that is command line, environment variables, configuration, etc... How to start application; how to properly destroy it. Of course all this tasks can be done without any framework but doing this tedios coding again and again is just boring. There is promising boost::application library in stage of approval by boost community. I'm going to use it with integration with other facilities.
Pattern Singleton is considered to be broken by many. In fact Singleton is very useful in some cases and it's hard to replace it with something else. But "classical definition" of Singleton has to be reviewed and there is good attempt to do it in Singularity library. I like this library but it's not complete solution. I will implement "Singleton registry" on top of Singularity.


понедельник, 17 февраля 2014 г.

Convenient exceptions

C++11 introduced new language features that enable implementation of chained exceptions in general. In C++98 it was possible to implement exception chaining but only for your own exception hierarchy - for example, POCO exception class - and this solution was incomplete and cumbersome.
One of the main requirements for jet::exception is exception chaining. My full list of "ideal" exception features:
1. Exception chaining;
2. Stream-like interface for error message construction;
3. Ability to create hierarchy of exceptions;
4. Exception should hold information about location in source code where it was raised;
5. Convenient way to throw exception;
6. (Optionally) Stacktrace attached to exception;

I implemented exception chaining using std::current_exception. Implementation itself is not difficult but chaining changes the way how I use exceptions. Previously I used the code similar to the following when I wanted to implement exception translation:

try
{
    //...
}
catch(const std::exception& ex)
{
    throw my_error(std::string("Couldn't do stuff. Reason: ") + ex.what());
}

This "surrogate chaining" is not necessary anymore. But after I fixed all such places I found my test cases are broken because I expected "flatten" exception message. With this change I had to change my test cases. For better handling exception cases I introduced "exception validator" which checks one or more exceptions in the chain.
Consider the following code:

TEST(config_source, error_instance_shortcut_config_source)
{
    EXPECT_CONFIG_ERROR(
        config_source::from_string{"<config><app.. attr='value'/></config>"}.name("s1.xml").create(),
        equal
            ("Couldn't parse config 's1.xml'")
            ("Invalid '..' in element 'app..' in config source 's1.xml'. Expected format 'app_name..instance_name'"));
    EXPECT_CONFIG_ERROR(
        config_source::from_string{"<config><..i1 attr='value'/></config>"}.name("s1.xml").create(),
        start_with
            ("Couldn't parse")
            ("Invalid '..' in element '..i1'"));
}

Here you can see two forms of error validators - "equal" and "start_with".
The former requires that exception has specified number of messages and all messages are equal to expected messages. "Equal" is useful when exact error message match is required.
"Start_with" validator is used when user wants to avoid unnecessary typing. This check is successful if number of expected messages is less or equal to actual error messages and each expected message is started from string passed to validator.
I was also considering "regex" validator but then gave up this idea as overly complex.

воскресенье, 16 февраля 2014 г.

Test in the middle

I am passionate advocate of unit testing and I will make it one of the principles of jet framework. Whatever code is written developer have to prove that it works as expected. Normally I do not follow extreme TDD activity – it’s possible but non-practical to write unit test before implementation of some functionality. Instead I follow approach when final product looks like it was implemented using TDD (but it wasn’t).

In argument around pro- and against-TDD people usually miss one important point – the purpose of testing. Imagine if somebody has unlimited analytic capabilities – does he need to test his code? Not really. He can trace possible execution paths of the program without writing a single piece of helper code (which is unit tests by definition). Indeed unit tests are not for genius – but for software developers who understand limits of their abilities.

TDD as a development process helps people to organize their coding activity but this is not the only way to do it. Moreover this stable and repeatable process contradicts to initial development stage of any project. Consider “flash of insight” when programmer needs urgently to write down his thoughts. Unit test is not the best way to start implementation in this case – it’s too “organized”.

Anyway testing is required. So I prefer opportunistic testing which can be described as “test-in-the-middle” as opposition to “test-first” concept.

пятница, 14 февраля 2014 г.

C++11 transition

I've started jet framework as c++98 compliant project but I've decided to change it. From now on jet will be written in c++11. In general breaking compatibility is not a good idea. In this case it's justifiable - I don't have neither energy nor intention to support as much clients as possible - the only user of jet is me.
C++98 served me well but it's time to start using new tricks.

вторник, 11 февраля 2014 г.

Few words about compatibility


I’m C++ software developer and I love C++.
In modern world this confession may be considered as laziness of mind but I will argue – I do a big dive into other languages from time to time. It gives me new way of thinking, new ideas and new pleasure. Nevertheless I’m still with C++.
C++ is commonly acknowledged as multi-paradigm language and one of the reasons of its popularity is compatibility with C. To be more specific – many languages are in fact compatible with C. And some of them heavily rely on this compatibility, for instance you can write your library in C and then use it in Erlang. C++ is different; C is a part of core language. If we follow Liskov substitution principle – C++ is not compatible with C; it is in fact C.
I always felt that compatibility is weak argument. Moreover it sounds like cheap marketing trick. When Stroustrup after 30 years of the language history tells about compatibility this is very similar to interview with action movie star who tells that he was interested to dig into cultural background of the script. Hm... maybe.
I like unambiguous clarity of C and when I write something in C it feels like I really control a program. But when I see C code in C++ environment it’s terrible: lack of encapsulation, global variables, potential memory leaks, broken invariants and uninitialized variables – all kind of bad smell.
My verdict – C and C++ are not compatible; they just share common syntax.

четверг, 6 февраля 2014 г.

Move semantics - optimisation or syntax fix?

Recently I joined army of C++11 explorers (better late than never). Of course move semantics is one of the most interesting new features of the language but does it really useful? It increases complexity of source code in exchange for potential performance gain. For example this article shows a case when move semantics can be beneficial with the only catch that initial example was purposefully pessimized.
Those who care about performance will carefully use pointers, references, inline, etc ... and profile there code. With move semantics you get your code as fast as before but not that ugly – so the real gain that I see is syntax improvement under the sauce of optimal code generation.