Wednesday, April 22, 2009

Unit testing makes manually managed memory simple

I recently started working on a project that does test-first development in C++. I have mostly done TDD in Java, but I've done a lot of C++ before that so neither the language nor methodology is new to me. However, after two-three years of unit testing in Java and a few scripting languages, I have (luckily) learned a few things. So this time around I hope to avoid one of the problems I had earlier with C++: the problem with ownership of newed objects, that is, which object owns another dynamically allocated object?.

When I was rewriting some classes to be testable I, as you usually do, introduced interfaces, used factories, injected dependencies, etc. In one case I rewrote the class under test (CUT) to use a factory instead of calling new directly. This made it easy to test that the CUT allocated an object correctly. But how to test that the CUT deletes that allocated object?

Well, it was quite simple: simply add a method to the factory called destroy that takes one argument which is the object to be destroyed. The method destroy is used to tell the factory I'm done with this object, do what ever you like with it... delete it it you want to. The destroy method corresponds to the make method, which of course allocates an object.

This is probably not some great new discovery I've made; most of you who have done test-first development in languages with manual memory management have probably already done this kind of thing. This was a new thought for me, though.

I also realized how clear the ownership of the object (created by the factory) had become. It was obvious from reading the production code and/or test-case that it was the factory that owned the object; all it did was to lend the object to some other class until destroy was called. This was an insight for me.

The fact that the factory owns the objects it creates means that it is trivial to replace the memory allocation scheme used by the factory. Only the factory is needed to be changed, e.g., if there is a need for pooling objects. Awesomeness.

I guess there are cases when this approach is not possible to use, but in cases where it is I think its a good pattern to use.

Wednesday, April 8, 2009

Movable proxy: a design pattern for hiding dirty secrets

The Proxy design pattern is a useful pattern. For my style of programming it's quite common, although I seldom actually name the proxy-class SomethingProxy. Instead I try to come up with a name for its actual role or responsibility. An example of this kind of proxy could be the services provided by a package in some Java code. All classes of the package is package private (default visibility) except for one, which is the proxy towards the package (there are of course a bunch of public interfaces).

Traditionally, though, a proxy is an object used to accessing something complex in a easier way. For instance a proxy for sending messages to, or retrieving the state of, a remote process. At work, where I'm working with a distributed Java application, we have a bunch of such proxies for accessing the various distributed subsystems/processes. All these proxies have some protocol for talking to the remote subsystem, e.g., homebrew protocol N, standard protocol M, etc.

This is all good, except for the fact that both the client subsystem and the server subsystem need to share a dirty secret: which protocol that is used to communicate. A sane design will hide this dirty secret inside some class (e.g., a proxy!), such that the bulk of the code doesn't need to know the secret. But still, some part of the client subsystem must know it, otherwise it cannot establish a connection to the server.

Or does it?

Wouldn't it be great if it was possible for the client to ask the server for the proxy instance? That is instead of doing:

final Proxy forTalkingToServer = new ServerProxy();

the client does:

final Proxy forTalkingToServer = server.proxyForTalkingToServer();

Ok, that sound like a nice idea. But wait, how is the proxyForTalkingToServer() method implemented? Doesn't the implementation of that method need to communicate with the server? Well, yes. But this bootstrap problem is easily solved by having a standardized protocol for sending java objects between different Java systems, e.g., RMI.

The sequence is something like this:

Client Server
------ ------
| Proxy request [RMI] |
|-------------------------->|
| |
| Proxy confirm [RMI] |
|<--------------------------|
| |
+------------------+ |

| client has proxy | |
+------------------+ |
| |
| Whatever request [?] |
|-------------------------->|
| |
| Whatever confirm [?] |
|<--------------------------|

Where Proxy request is what happens when the proxyForTalkingToServer() method is called, and Proxy confirm is the methods' return value, that is, the proxy the client should use for talking with the server. The Whatever request and Whatever confirm messages are messages sent using some protocol (symbolized by [?]) that the server decided to use.

In addition to having the client completely unaware of the actual protocol used for communicating with the server, the proxy can be pass around (using, e.g., RMI) the entire distributed system and it will still be possible to access the server using the proxy. It is also possible to update the protocol without updating the clients, or to let the proxy instance implement multiple interfaces (one new-and-improved and one legacy for backwards compatibility). It is also great for testability/debugging: you can easily replace a troublesome protocol with a simpler variant.

Neat.

Wednesday, April 1, 2009

Happy new year!

One year ago I wrote my first post for this blog! I've been writing about Java and testing, published a few small programming project, and screamed in frustration.

There have also been some (slightly) philosophical posts, seemingly trivial ideas, my old sweatheart Lisp, and my views on OO. I have also faced one of my many fears and helped you making your faviourite IDE a bit better.

At late, I've even had some insights and publishing one of my coolest ideas (with a crappy implementation) :)