пятница, 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.

Definition

Hi there! This web log is dedicated to development of Jet framework.
Jet is c++ library and if you are not interested in c++ I guess this would be not the most exciting reading for you.
Initially I was going to implement Jet to satisfy my immediate needs in convenient set of tools for “rapid c++ development” - this sounds a bit controversial because there is common belief that c++ is not for fast-starters. Well, this is true.
In c++ before you start writing something real you need to write several supporting layers that tailor existing language and platform facilities for your application. This is unfortunate because I like the language and I’m comfortable with it but when I initiated my own project I found that I literally could’t start it. I couldn’t take development framework that I’m using on my work. Other options like using ‘naked’ c++ or switch to another language did not attract me much.
Returning to the purpose of this blog - source code is succinct result of programming process. But there are plethora of design decisions in background. From my experience I came to understanding that modern software development processes are missing one of the most important deliverable of the project - a reasoning of why this or that decision was made. You can have design documents and clear architecture (lucky you!) but the reasons that made you come to these decisions usually are lost in time.
Consider this blog as a whiteboard that I used during development of Jet framework.