Sunday, December 13, 2015

On faking QObject-derived classes (part 1)

Introduction

After reading Michael Feathers' book Working Effectively with Legacy Code, I recently got interested in techniques for making code more testable.  One of these techniques is Extract Interface, which can be used to replace objects of a certain class with fake versions. While trying to apply this to some legacy code, I stumbled upon a problem.  This post describes that problem and how I solved it.  However, I do have my doubts concerning the elegance of my solution. So therefore: feel free to comment and share alternative solutions!

Starting point

Our starting point is a class derived from QObject:

Because this is a QObject-derived class, it can use methods like setObjectName and objectName, but it can of course also have its own member functions like doFooStuff. Our purpose now is to extract an interface for the Foo class, so we can create a FakeFoo class as a replacement for Foo.

Extracting the interface

Faking the Foo class seems easy at first sight: following Feathers' advice, all I should do is extract a FooInterface and let my Foo and FakeFoo implement it. My first attempt in doing this, looked as follows:

Unfortunately, this resulted in the following compiler errors using g++ 4.9.2:


failed_attempt.cpp: In function ‘int main()’:
failed_attempt.cpp:29:14: error: ‘class FooInterface’ has no member named ‘setObjectName’
     fakeFoo->setObjectName("fake foo");
              ^
failed_attempt.cpp:30:27: error: ‘class FooInterface’ has no member named ‘objectName’
     std::cout << fakeFoo->objectName().toStdString() << std::endl;
                           ^
failed_attempt.cpp:34:14: error: ‘class FooInterface’ has no member named ‘setObjectName’
     realFoo->setObjectName("real foo");
              ^
failed_attempt.cpp:35:27: error: ‘class FooInterface’ has no member named ‘objectName’
     std::cout << realFoo->objectName().toStdString() << std::endl;

Needless to say I was a bit disappointed in realizing that FooInterface indeed did not have a setObjectName or objectName function. Inspired by the section The Case of the Onion Parameter and The Case of the Aliased Parameter in Feathers' book, my current best attempt so far in solving this issue consists of creating a QObjectInterface with these methods and letting FooInterface derive from that:

This works, as is visible in the output of the program:


fake foo
Foo::doFakeFooStuff()
real foo
Foo::doFooStuff()
But my current solution has several drawbacks:
  1. I need to add every QObject member function that I use, to my QObjectInterface.
  2. If I want QObjectInterface and FooInterface to be real interfaces, that forces me to do the implementations of every QObject member function that I use in both my Foo and FakeFoo class. These implementations are just forwardings of method calls to the QObject class. That is quite mechanical, cumbersome and errorprone. I don't like that.
Is this really the best way to go? Or have I overlooked more elegant solutions that don't require me to do all that mechanical, cumbersome and errorprone work?

Conclusion

I did find a way to fake QObject-derived classes, but my solution requires quite some brain-dead QObject-method implementing in the original class and its fake version. I am open for more elegant designs. Please enlighten me! All code in this blog post is available in a public Gist.

Sunday, November 22, 2015

Testing GitHub gists

Occasionally, i day-dream about sharing some random thoughts about certain aspects of software development. An important practical tool needed for this kind of idea-sharing, is being able to nicely embed code-snippets in my blog posts. Googling around for solutions, I came across GitHub gists. This is my first test to embed small pieces of code into my blog posts. If you see a "Hello world!" program below this paragraph, it means my test succeeded...

If you also see a "Hello people!" program below this second paragraph, then it means I'm able to display several different pieces of code into my blog posts.

If you think you know better solutions for embedding code-snippets into Blogger articles, do not hesitate to post a comment!

Wednesday, August 12, 2015

Show your Google Contacts on a map using Google Fusion Tables

Just for the fun of it, I decided to investigate ways to display my Google contacts on a map.  One solution I use already quite a while is the Contacts on map app on my Android smartphone.  But I also want a desktop solution that doesn't require me to enter my Google credentials on a website.  Finding such a solution turned out to be hard, so in the end, I decided to be creative and construct my own solution.  These are the steps I followed.  Google Fusion Tables to the rescue!

Step 1: export your Google contacts

  1. Surf to http://contacts.google.com
  2. In the left menu-bar, under More, find Export and go to the old Google Contacts (because the new Google Contacts doesn't allow you to export your contacts yet).
  3. In the old Google Contacts, select More followed by Export and export your contacts in Outlook CSV format (the Google CSV format didn't work for me):

Step 2: import your CSV file in Google Fusion tables

  1. Surf to http://drive.google.com
  2. Check if you have Google Fusion Tables available under New / More.  If you don't have it yet, install the Google Fusion Tables app.
  3. Create a new Google Fusion Table using New / More / Google Fusion Tables.
  4. Under Import new table use From this computer and select and upload your contacts.csv file.  Use comma as separator character and select UTF-8 character encoding:

Step 3: select the column to use as a location

  1. First, you can remove some unnecessary columns using the Select Columns menu item from the Rows 1 tab.
  2. Then, pick the column you want to use as your location column (e.g. Home Address), and change its type to Location.
  3. Now go to the tab called Map of Home Address and select Home Address as Location column:

  4. Press Begin geocoding and once that's finished, you should see a nice map of all your contacts.

Step 4: finetune

To change several map feature styles and the content of the info window that appears when you click on a contact from the map, go to the tab of the map and select Change map.  It is even possible to display your contacts in a heat map.  My map finally looks like this:


Conclusion

If you keep all your contacts centralized in Google contacts, then visualizing for example their home and work address on a map is rather easy using Google Fusion Tables.  I use these kind of maps a lot when I go somewhere and want to say hi to friends that I haven't seen in a while.

Comments and suggestions on this article are more than welcome!