Well it’s been nearly a month since I first wrote about project freedom (as in financial) and I thought it might be time give a brief update on where I’m at. Given that we’ve just had Christmas and I’m currently on holidays progress hasn’t been all that dazzling. That said, I’m still pretty happy with what has been done all things considered. So what have I been doing? Well so far I’ve mainly been looking at different approaches to building the application.

The Java Way

Naturally I immediately jumped to looking at a Java based solution – after all it is what I’d call my “home” language. Anyone who’s been around a while and has had the opportunity to program in Java as well as a variety of other programming languages/paradigms would undoubtedly agree that it is a beautiful language. I for one really appreciate the consistency of the syntax, the uncompromising enforcement of the OOP paradigm, and most of all the rich standard library with its accompanying documentation.

Being that I work with this stuff quite a bit my head was filled with all sorts of ideas about how we could achieve our goals using Java as the weapon of choice. The first thing that came to mind was that I could utilize the Eclipse RCP and JFace to get some quick wins getting a basic application framework up and running. This approach has the following distinct advantages:

  1. Eclipse RCP contains an OSGi container built in (Equinox to be exact) which is a very powerful plugin framework in a manner of speaking. Potentially it means that each discrete piece of functionality can be build as a separate plugin (or bundle in OSGi-speak).
  2. SWT/JFace contain a rich component set which would do about 95% of what I require and look/behave just like native components on Mac, Windows and Linux.
  3. RCP comes with a tool that allows to generate an executable and budle a JRE with the application so you can avoid “but my system doesn’t have Java (or version required) installed” type support headaches. It just runs.
  4. It’ll run on Mac, Windows, and Linux with no issues whatsoever.

So why wouldn’t I take that approach?

  1. Personally I’ve found RCP very hard to come to grips with. Documentation is scarce and outdated from what I can determine.
  2. OSGi adds a large amount of overhead in terms of complexity. Now I’m not exactly the smartest guy going round, but I’m not a moron either. I’ve spent hours frigging around with manifests, configurations, interfaces, dodgy docos and classpath hassles getting very little done. It all feels like a tremendous waste of time at this stage.
  3. Need to learn and ORM mapping tool like Hibernate or similar to overcome the OO to Relational mapping mismatch. I’m predominantly a user interface specialist so I usually leave this kinda stuff to someone else. Alternatively I can just battle on through with JDBC (*shudder).

As far as abstractions go Donald Knuth is reputed to have once said:

“There is no complexity problem in programming that cannot be eased by adding a layer of indirection. And there is no performance problem in programming that cannot be eased by removing a layer of indirection.”

Ordinarily I’d agree with this statement. You only have to look as far as something like an ORM to see this principle at work. What could be simpler than just working with your domain objects and letting something else worry about the whole persistence issue? On the contrary though I’m inclined to say that the sheer number of abstractions present in the aforementioned solution actually add to its complexity – not reduce it as promised. As always in Java I seem to be forced to spend a lot of time thinking about the correct way to do something as opposed to just doing it and refactoring later.

So there it is, I’ve spent a whole lot of time without a great deal of success. About the best thing it’s got going for it so far is that I’ve managed to do some modelling of the domain level objects. So where do we go from here?

Back to the Future

Some might consider this a backward step from comfortable walled garden that is Java but I’ve been experimenting a bit lately with C and GTK+. Yes you read right C, not C++, just pure unadulterated structured programming. Why not C++ indeed.

I’ll probably get flamed for saying this, but I just don’t like it. With great power comes great responsibility, and it’s like a wild beast that can take on any form it likes depending on the wild mood swings of your average programmer. Every time I read C++ I get the impression that whoever’s driving the evolution of the language can’t quite decide what they want it to be. If Java is a well manicured, if somewhat anal, golfing green then C++ resembles a hoarders front yard. You know the ones, full of old car bodies and useless junk left over after you take all the useful stuff out. Don’t take my word for it though, ask Linus. That said you can always pick and choose the bits you like and leave out the bits you don’t.

Anyway, so far I’m really impressed. Previously I’d thought that leaving OO behind would just be too painful however I was pleasantly surprised. To demonstrate a few concepts to myself I briefly knocked up this little demo which consists of a simple GTK+ interface sitting atop an SQLite database. As far as I’m concerned this a great “thin line” of technology from top to bottom which could conceivably be employed to write the app.

db_test.c

#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <sqlite3.h>

/* Database file name. */
const gchar *DB_FILENAME = "test.db";

/* A simple SQL query to select all rows from the person table. */
const gchar *DB_QUERY = "SELECT * FROM person;";

/* Index of the name column in the list view */
const gint LIST_COL_NAME = 0;

/* Index of the age column in the list view */
const gint LIST_COL_AGE = 1;

/* The total number of columns in the list view */
const gint LIST_NUM_COLS = 2;

/* Global reference to DB handle. */
static sqlite3 *db;

/* Callback that processes a single row returned from the database. The first
 * parameter is expected to be a pointer to a GtkTreeView. */
static int
process_db_results( gpointer  data,
                    gint      ncols,
                    gchar    *col_values[],
                    gchar    *col_names[] )
{
    GtkTreeView    *view;
    GtkListStore   *store;
    GtkTreeIter     iter;

    /* Get reference to underlying GtkListStore so we can add to it. */
    view = GTK_TREE_VIEW (data);
    store = GTK_LIST_STORE (gtk_tree_view_get_model (view));

    /* Append a row and populate it using the row data provided */
    gtk_list_store_append (store, &iter);
    gtk_list_store_set (store, &iter,
            LIST_COL_NAME, col_values[0],
            LIST_COL_AGE, col_values[1],
            -1);

    /* Auto-adjust columns to fit data. */
    gtk_tree_view_columns_autosize (view);

    /* Return a zero to let SQLite know it's okay to continue processing */
    return 0;
}

/* User clicked the "Load List" button. */
static void
button_load_clicked( gpointer data )
{
    gint rc;
    gchar *err_msg = 0;

    /* Populate the list component with data from the DB. */
    rc = sqlite3_exec (db, DB_QUERY, process_db_results, data, &err_msg);
    if (rc != SQLITE_OK)
      {
        fprintf (stderr, "SQL error: %s\n", err_msg);
        sqlite3_free (err_msg);
      }

    return;
}

/* User clicked the "Clear List" button. */
static void
button_clear_clicked( gpointer data )
{
    GtkTreeModel  *model; 

    /* Get reference to underlying GtkTreeModel so we can clear it. */
    model = gtk_tree_view_get_model (GTK_TREE_VIEW (data));

    /* Clear the list using gtk_list_store_clear. This is much faster than
     * calling gtk_list_store_remove once for each row. */
    gtk_list_store_clear( GTK_LIST_STORE (model));

    return;
}

/* This callback quits the program */
static gboolean
delete_event( GtkWidget *widget,
              GdkEvent  *event,
              gpointer   data )
{
    /* Close the database connection. */
    sqlite3_close (db);

    /* Terminate the main program loop. */
    gtk_main_quit ();

    return FALSE;
}

/* Creates a list view component consisting of two columns. The first column
 * is for a persons name, the second for their age. */
static GtkWidget *
create_list_view( void )
{
    GtkCellRenderer        *renderer;
    GtkTreeViewColumn	 *column;
    GtkListStore             *store;
    GtkTreeView             *view;

    view = GTK_TREE_VIEW (gtk_tree_view_new ());

    /* --- Column #1 --- */
    renderer = gtk_cell_renderer_text_new ();
    column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
            "text", LIST_COL_NAME,
			NULL);
    gtk_tree_view_column_set_resizable (column, TRUE);
    gtk_tree_view_insert_column (view, column, -1);

    /* --- Column #2 --- */
    renderer = gtk_cell_renderer_text_new ();
    column = gtk_tree_view_column_new_with_attributes ("Age", renderer,
            "text", LIST_COL_AGE,
            NULL);
    gtk_tree_view_insert_column (view, column, -1);

    store = gtk_list_store_new (LIST_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
    gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));

    return GTK_WIDGET (view);
}

/* Initialises the application's database connection. */
static void
init_db( void )
{
    gint rc;

    /* Open the database to initialise the connection object. */
    rc = sqlite3_open (DB_FILENAME, &db);
    if (rc)
      {
        fprintf (stderr, "Can't open database: %s\n", sqlite3_errmsg (db));
        sqlite3_close (db);
        exit(1);
      }
}

/* Initialises the application's user interface. */
static void
init_ui( void )
{
    GtkWidget *window;
    GtkWidget *vbox, *hbox;
    GtkWidget *scrolled_window;
    GtkWidget *list_view;
    GtkWidget *button_load, *button_clear;

    /* Create the main application window */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request (GTK_WIDGET (window), 300, 150);
    gtk_window_set_title (GTK_WINDOW (window), "GTK/SQLite DB Example");

    /* Configure app to terminate when closed */
    g_signal_connect (G_OBJECT (window), "delete_event",
			G_CALLBACK (delete_event), NULL);

    vbox = gtk_vbox_new (FALSE, 5);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
    gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_widget_show (vbox);

    /* Create a scrolled window to pack the CList widget into */
    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
    		GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);

    gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
    gtk_widget_show (scrolled_window);

    /* Create the list view which will display the data. */
    list_view = create_list_view ();

    /* Add the list view widget to the vertical box and show it. */
    gtk_container_add (GTK_CONTAINER (scrolled_window), list_view);
    gtk_widget_show (list_view);

    /* Create a horizontal box to hold our buttons */
    hbox = gtk_hbox_new (FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
    gtk_widget_show (hbox);

    /* Create the buttons and add them to the window. */
    button_load = gtk_button_new_with_label ("Load List");
    button_clear = gtk_button_new_with_label ("Clear List");

    gtk_box_pack_start (GTK_BOX (hbox), button_load, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), button_clear, TRUE, TRUE, 0);

    /* Connect our callbacks to the three buttons */
    g_signal_connect_swapped (G_OBJECT (button_load), "clicked",
    		G_CALLBACK (button_load_clicked), list_view);
    g_signal_connect_swapped (G_OBJECT (button_clear), "clicked",
            G_CALLBACK (button_clear_clicked), list_view);

    gtk_widget_show (button_load);
    gtk_widget_show (button_clear);

	/* The interface is completely set up so we show the window. */
    gtk_widget_show (window);

    return;
}

int
main( gint   argc,
      gchar *argv[] )
{
    /* Before we even think about doing anything we must initialise GTK */
    gtk_init (&argc, &argv);

    /* Initialise the database connection */
    init_db ();

    /* Initialise the user interface */
    init_ui ();

    /* Now that everything's ready, start the main program loop. */
    gtk_main ();

    return 0;
}

Not bad for 236 lines of code huh? Feel free to use the code in any way you like. You’ll have to create a new database using the sqlite command-line utility first before running it though:

$ sqlite3 temp.db
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> create table person (name varchar(30), age smallint);
sqlite> insert into person values ("Phillip J. Fry", 33);
sqlite> insert into person values ("Hubert J. Farnsworth", 167);
sqlite> insert into person values ("Zapp Brannigan", 45);
then type CTRL-D to exit

As far as I’m concerned writing this thing in C has a few compelling advantages:

  1. It’s portable. C is arguably the most portable (not to mention widely used) language in the world. If binaries aren’t available for your processor architecture, you can always compile it especially to suit that Z80 you’ve had sitting in your basement – just because you can.
  2. No special libraries or runtimes required here. Just run it baby.
  3. Glib, GTK+ again provide 95% of what I need for the app out of the box. Not to mention that the documentation is awesome and free. They’re cross-platform too!
  4. Working with relational databases is a snack. No OO/RDBMS disparity here, it’s all smooth sailing.
  5. It’s really, really fast. There’s no VM here, just bare-metal machine code.
  6. Like Java, there’s heaps of free libraries and tools out there to take advantage of.

Of course using something as raw as C/GTK+ isn’t without its hangups:

  1. Memory management and pointers frighten the bejesus out of many programmers. I don’t mind them so much, but I do understand that some have a pathological aversion to them.
  2. Cross-compilation isn’t exactly what I’d call straight forward.
  3. If you’ve been spoilt, like I have, working in 4th gen languages with awesome support for strings  NULL terminated character arrays are a rude shock. Don’t get me wrong, it’s not difficult, it’s just one extra thing to keep in mind.
  4. Very little in the way of syntactic sugar.
  5. GTK is still yet to be ported to Mac OSX. This is potentially a dealbreaker.

One thing in particular that I found was very nice was the GTK+ “Object Oriented” style interfaces which allow for a form of inheritance within a standard C program. This is a massive benefit because UI programming can get quite repetitive if you’re unable to extend and modify components simply by subclassing them.

Well that’s about all I’ve got for now. I’d be really interested in hearing what you think on the matter of technology choice, especially if you’re looking to contribute in future.

Project Freedom

December 14, 2008

Over the past few months I’ve been searching high and low for some software that will assist me in managing my personal finances. Ultimately what I want is something that will let me lay out my budget and then proceed to track my expenses against my budget so I can see how I’m doing. This will help me answer some very important questions like:

  1. Is my budget realistic? 
  2. Where am I getting into trouble? 
  3. What are my biggest expenses and can I do anything to reduce them?
  4. How much money have I actually got available (after paying my bills)?
  5. Is there anything on the horizon that I have to put some money aside for?

Knowledge is Power

All of this knowledge is power because it means I can make informed decisions about whether or not to spend depending on my circumstances. Frequently my wife and I have found ourselves saying “No we’d better not, I don’t think we can afford it”, when the reality often is that we can easily afford it. Lucky for us we tend to err on the side of caution and end up with a bit stashed away because of this attitude, however the same principle applies in reverse to those who aren’t so cautious. It all boils down to living within our means which is often quite comfortable – we just don’t know it yet. Most of the time we don’t have to go without, nor do we have to run the risk of getting ourselves into trouble.

We do currently have a system, though it has many moving parts and I’m not really satisfied with the ability to mine more detailed information out of it. What’s more is that I tend to lose a lot of the more fine grained information as it passes through the various stages of being entered into this spreadsheet and that software package. What I’m really after is a solution that is both simple and powerful, without all the accounting-speak. It should have a simple, well designed UI without too much clutter which  belies the underlying power of the application.

Bottom line is that I don’t want have to spend an entire evening every week bringing it up to date, 15-30 mins a week is about all I want to spend on this. I also want to be able to get my vital stats such as cash flow and available funds at a glance. I need something I can look at the start of the day and know exactly where I stand.

Playing the Field

Now being the self-confessed code junkie that I am, my mind immediately jumped to all sorts of fanciful notions of building the damn thing myself. At this point I had to stop and say to myself “Dave, you are not going to build this. There has to be any number of software packages out there that do exactly what you’re looking for and more.”, this was mainly for the benefit of my poor neglected wife however. Deep down I really wanted to write this thing all the same…is there any hope?

Anyway for the record I’ve sampled the following apps so far:

In addition to these I’ve also tried any number of so called budget tracking spreadsheets and access databases.

How Do They Stack Up?

So what did I think? Well, rubbish to be completely honest. I’m sure that all of them fit their niche quite nicely however none of them seem to be able to adequately combine a solid budgeting tool with an expense tracker, let along in an easy to understand, intuitive interface. The ones that came closest in my mind were the online ones,  which leads me to a new dilemma.  I absolutely cannot stand online budgeting tools. In this regard I have to completely agree with Richard Stallman that some things just don’t belong on ‘the cloud’. I don’t really care what the social networking advantages of doing so are (ala Wesabe) I’m just not comfortable in handing over all my financial details to some website (that isn’t a bank an never will be) and hoping that they don’t:

a) Use my information for some nefarious purpose.
b) Accidentally leak my information for others to use for said nefarious purposes.
c) Lose my data when they’re evicted from their hosting provider for not paying their bills.
d) Do any other stupid things that may result in financial loss or general inconvenience on my part. 

That said, being online has the distinct advantage of being available almost anywhere which is a big plus if you’re the kind of person who spends very little time in a fixed location.

Back to Square One

Unfortunately that leaves me back where I started which is I still don’t have an all round tool to help me manage my finances effectively and gives me my vital statistics in a timely fashion. Looks like it’s time to roll up my sleeves and get coding. 

Ideally I want this thing to be a cross-platform desktop app, with a slick user interface and constructed in such a way that we can easily integrate access-anywhere capabilities via the web. You know so you can check before you make that impulse purchase.

Developer Team Assemble!

If you are like me and are frustrated with the current personal money management offerings and you’re interested in contributing then let me know.  If I get enough interest then I think I’ll open source it so I can speed development of the thing up.

There a lots of great ways to improve your desktop experience in Linux. If the default stylings of GNOME or KDE just aren’t your cup of tea, or you really want a Mac but can’t afford one like me, then read on.

Vista, really?

I’m first to admit, and rather shamelessly, that I really like a bit of eye candy in an OS, especially 3D candy. For all it’s underwhelming glory, I do quite enjoy the shinyness of Vista. If I was really going to make the total conversion over to Linux once and for all, I was really going to miss those effects. Unfortunately for Vista, and consequently the reason I’m trying Linux, is that it’s a bit like a photo of a hooker; looks good, but doesn’t do much. But I digress.

Turning on a bit of visual flair in Ubuntu requires that you have a graphics card with some form of graphics acceleration available. My faithful laptop has an absolute clanger of a video card, an ATI Radeon Mobility X1400 to be precise. I can almost hear you stifling a yawn – it really does suck that much – or so I thought…

Driver dramas

Being OSS, Ubuntu doesn’t include proprietary drivers in the distribution due to the license restrictions many of the EULAs impose. This means that by default you’re using an open source equivalent driver for your hardware. This is fine for every day 2D office related tasks. This won’t do with what we’re proposing however as they don’t support many of the advanced features your graphics card offers – we’re gonna need those. Now before you break out in a cold sweat and start fretting about compiling, editing X config files or anything silly like that, take a deep breath. EnvyNG is a great tool that takes care of all the driver updates for you. It detects and installs the correct proprietary video card driver for you in a matter of minutes. Easy huh?

Mac on a mortgage

Mac4Lin Desktop

After a reboot you should now be ready to turn on advanced desktop effects (Compiz-Fusion for those in the know). This will enable all kinds of funky effects on your desktop like wobbly windows, 3D cube desktop selection etc.

Impressive eh? Well this is where it gets really fun. Head on over to SourceForge and grab all the latest files from the Mac4Lin project. This should include everything you need, including instructions on how you tweak your desktop till it’s damn near unrecognisable as Linux. I’m not real sure how Steve Jobs would feel if he saw this.

One thing I’m really impressed with is the speed at which all these effects run. Under Vista one could have been forgiven for thinking that Dell had given me the worst graphics card known to man. In fact I’ve always been slighly disappointed with my laptop’s performance until now. Ubuntu runs like a scalded cat on a hot tin roof, and I’m smiling from ear to ear about it.

Sorry Vista, looks like another nail in your already sealed coffin.

Click here For a more in depth look at more things you can do in Hardy Heron.

Web based IM clients are seem to be the flavour of the month at the moment. Gmail has had one for a little while now and more recently Facebook has added this to their already impressive stable of features. These are really cool, and rip all over the old form based chat rooms, but how do they do it without using any plugins, flash or the dreaded ActiveX componets?

Typically they use a combination of things:

Server

At the heart of the system is a Jabber IM server such as Openfire. The server performs real-time communications with clients via the Extensible Messaging and Presence Protocol (XMPP). XMPP is an open XML based protocol that works on a concept similar to email. That is, anyone with a server open to the internet can create a Jabber IM server and become part of the wider decentralized IM network.

It’s worth noting that XMPP places no restrictions whatsoever on what the client should be. Much of the effort and complexity of developing a Jabber IM network goes into the server itself. Given that there are already a number of perfectly good OSS Jabber servers out there it makes the Web Developers job relatively easy.

Client

Gmail and Facebook use clients written in JavaScript (no plugins!) which communicates can communicate either directly with the server, or via a server-side proxy. There are generally two accepted methods communicating with the server from the browser; HTTP binding (BOSH) or HTTP polling (now deprecated).

Binding universally preferred as it virtually eliminates the number of round trips to the server (the majority of which yield no result) by using keep-alives to hold connections open to the server. What does that all mean? It means that the Jabber server is able to push messages back down to the browser rather than the client checking at set intervals for new messages. Cool huh? The only drawback seems to be that you need to be able to manage a large number of open connections concurrently. The fact that Openfire is built on Jetty helps because of their use of the Continuation Pattern to suspend blocked polling requests and free the worker thread.

Going direct

Communicating with the jabber server directly saves a lot a lot of hassle as opposed to proxying the requests via a servlet or something similar. It also avoids the problem of having to move your existing web server over to something more scalable like Jetty. But how do you do this when JavaScript can only make requests to its own domain? Well if you’re using Apache you’re in luck! Mod_rewrite is your friend here and adding the following to your http.conf file should have to talking to your Jabber servers http-bind service in no time at all:

<VirtualHost *:80>
    Servername yourdomain.com
    DocumentRoot /var/www
    AddDefaultCharset UTF-8
    RewriteEngine On
    RewriteRule ^/http-bind/ http://jabber.yourdomain.com:5280/http-bind/ [P]
</VirtualHost>

Viola! All requests to http://www.yourdomain.com/http-bind/ will be automatically forwarded to your chat server.

Talking XMPP

Okay so we’ve solved the cross-domain request problem, but how to we talk to the server. You’re probably asking yourself “Do I now have to actually parse all those XML messages myself in JavaScript?”. Fortunately no. JSJaC is a freely available, washed in the blood open source GPL JavaScript library, that handles all those icky details for you. It works on an event based model so you can just register your event handler callback functions, and get on with writing your very own IM client.

Speaking of which I’m going to do just that right now!

Follow

Get every new post delivered to your Inbox.