03 January 2010

BDD podcast for ANUGCast

I was recently interviewed for ANUGCast by Søren Skovsbøll about Behavior-Driven Development. If you want to listen to it you can find it here.

Labels: ,


24 December 2009

Working in a foreign country

I'm thinking about finding my next job in Australia or Canada. For several years I have thought about doing so, but I've never come around to actually exploring the possibilities.

At this point I'm just collecting information. Reading articles and blogs written by people who's lived and worked abroad as well as reading up on official migration documentation on government websites.

If you have any experience doing something like this, I would like to hear from you. How did you go about contacting possible employers? How did you figure out the legal stuff that needs to be in place? And how did it go?

If you could recommend companies in one of those two countries that would be interesting for a developer like me, please drop a post!

Labels: ,


18 December 2009

Testing Software Ontology: Why spend time and money on testing software?

I want to talk more about testing software.

Through my professional career and my work in Aalborg .NET User Group, through my participation at conferences and by reading blogs, articles and books, it has become evident to me, that the importance of testing software is lost on a large percentage of developers and businesses.

If not lost, then at least not well understood and therefore not prioritized on the basis of entirely misconstrued economical reasons. It is a fallacy that by not spending money on testing, you save money. The exact opposite is the case.

In this post and several others, I will try to sum up, what I think, I know about testing software in a broad and generalized sense. To the professional software test engineer, everything in this post and the next ones is old news, but to many developers the content will be new ground and it will show that testing software is more complicated and nuanced than they thought.

Why spend time and money on testing software?

In today's world, software is the glue that binds almost everything. There is software in our watches, phones, cars, laptops, music systems, airplanes, trains, televisions - places we take it for granted. But software is quickly making its way into less obvious places such as kitchen appliances: microwaves, freezers, coolers, coffee makers and food processors to name a few. We monitor our sleeping babies with wireless network devices that are stuffed with software. In hospitals almost everything has embedded software and you can be pretty sure that your country's infrastructure and airspace is monitored by software programs. The list just goes on and on. And we haven't even mentioned the vast majority of businesses, that are completely dependent upon their ERP systems, data analysis programs and office packages.

We are all almost entirely dependent upon software that works. Not all software works. Why? Well, as this series of articles will reveal, the reasons are many, but mainly because those involved with its creation are fallible creatures - humans.

This is unfortunate for us. Why? Because untested software will kill you! Or at the very least make your life miserable...

Untested software will kill you slowly by increasing your daily stress level. We all know the irritation of waiting for unresponsive programs. We all know the anger felt when our word processing program crashes and we loose our work. We all know the increasing pressure in our chest and the throbbing in our temples when we spend an inordinate time trying to use bug ridden, monolithic governmental software systems that are supposed to make it all so easy for us. Over time it adds up.

Untested software will kill you quickly as when the airplane you are in drops out of the sky. Or when the paramedics cannot be called due to overloaded telephone systems. Or when early warning systems fail to detect the mega wave that just passed the software embedded buoy. And so on and so on.

Untested software will kill your business because dissatisfied (or dead) customers won't ask for your services again.

Untested software is expensive. We all know this. Here in Denmark we have many government software projects that have failed miserably, not solely due to lacking software testing, but certainly as a big part of it. Trying to repair such systems will only increase the magnitude of its failure.

Fixing bugs in an untested software system of any moderate or high complexity is a daunting and difficult task. Fixing bugs in an untested software system of any moderate or high complexity that was not written with testability in mind is an impossible task. Well, maybe not for the very best senior elite developers, but the rest of us are screwed. So we start looking for jobs elsewhere...

To sum it up. We want to spend time and money on testing software because:

Labels: ,


11 December 2009

Personal leadership is about being a better person

I'm half way through the personal leadership module on Diploma of Leadership. It is based on the premise, that one cannot successfully lead others, if one cannot lead one self.

It is about theories, that hypothesize how information cannot be transferred from one person to the next. You cannot choose to teach another person anything. You can provide exformation, but it is entirely up to the other person, which parts of the exformation, if any at all, become actual information. In other words, reality is constructed by each and everyone of us as we choose what to take in and how to interpret it (constructivism, Jean Piaget). We are closed, self referencing systems (autopoietic systems).

Another theory explains that reality is created in the context of interpersonal relations and by the language and words we choose to express ourselves by (construcsionism, Seymour Papert).

We learn communications theory and how leadership has evolved and changed meaning through history.

The module does not try to teach us what personal leadership is, for this is indeed a difficult, perhaps impossible task. It is up to each student to explore, how he or she will fill the role of leadership in an effective and trustworthy way.

It aims to teach us how to become deeply reflective about what we do, how we do it, and why we do, as we do. I have come to the conclusion, that it is really about becoming a better person through a cyclic process of studying and self exploration which, if wholeheartedly embraced, can be very rewarding on a personal- as well on a professional level.

I think that true leadership is rooted in:

Labels:


29 November 2009

Why do you read this blog?

I'd like to hear what you find interesting enough to come and visit my blog.

I have close to 50 visits per day in average by unique visitors. This is not many, but please leave a comment on what you find interesting and what you would like to read more about.

16 November 2009

Writing an EventBroker

On a project I'm working on with my friend Michael, we need a web page to be build from independent modules - independent in the sense that they have no direct dependency on any other module and that they may operate autonomously. A lose coupling strategy for the various UI elements you could call it.

We need this kind of flexibility because the users of the system must be able to pick and choose any module, or any number of modules, for any given page, dynamically - that is, without the need for a developer to wire everything up in the code behind. They should be able to select the modules they want and the modules should function autonomous. The modules should also be able to send messages to other modules when needed, without knowledge of each other.

The way I went about achieving this was by writing an EventBroker. An EventBroker can be considered an implementation of the Publisher/Subscriber pattern or a sub-pattern or derivative thereof.

It is obvious, that to achieve loosely coupled modules that knows nothing of the other modules, yet are able to send messages to each other, we must move the coupling or change its direction to an intermediate component. This is the role of the EventBroker.

An example is in place. I have two modules. When the UpdateContent method in the first module is executed, I want the second module to be notified and do something about it.

I use well named interfaces to express the type of message send.

public interface UpdateContentEvent {}

The SubscriberModule subscribe to messages of type UpdateContentEvent and assigns a messagehandler, UpdateContentHandler, to handle the message when or if it occur.

public class SubscriberModule
{
    public SubscriberModule()
    {
        EventBroker.Subscribe<UpdateContentEvent>(UpdateContentHandler);
    }
 
    private void UpdateContentHandler(object sender, EventArgs e)
    {
        var args = e as UpdateContentEventArgs;
        if(args != null)
        {
            string content = args.Content;
            // perform some update with content
        }
    }
}

The PublisherModule first builds some event arguments, then publishes the event, UpdateContentEvent, and supplies a reference to itself as well as the arguments.

public class PublisherModule
{
    public void DoUpdateContent()
    {
        EventArgs args = new UpdateContentEventArgs {Content = "Some content to be updated"};
        EventBroker.Publish<UpdateContentEvent>(this, args);
    }
}

That is basically it. The two modules know nothing of each other, but are able to send and receive messages from and to each other through the EventBroker.

Some considerations:

This EventBroker implementation is static and as such represent the strongest coupling one can have between components. In this case I find it acceptable and consider it part of the infrastructure of the system we are building. It is possible to change the implementation slightly and inject the EventBroker into the classes that use it, or hide it behind a factory, but at this point I'm satisfied with the coupling it represents.

The implementation only allow modules to send and receive messages in a synchronous manner. This is all I need at the moment, but at some point it may need to support asynchronous messaging. If this need emerge, I'll consider a true message bus instead.

The implementation allow for any number of publishers and subscribers. I've wrapped the event handling Action delegate in a WeakReference so that the EventBroker does not become a greedy memory-clutching hub.

In truth the EventBroker mediates messages, not events in the sense of .NET events. In this implementation I switch between the terms event and message. This can be cause for misunderstandings. In the next version I'll remedy that...

Lastly, the EventBroker is thread safe.

And here is the EventBroker code:

public static class EventBroker
{
    static readonly IList<KeyValuePair<Type, WeakReference>> eventsSubscribedTo = new List<KeyValuePair<Type, WeakReference>>();
 
    public static void Subscribe<TEventType>(Action<object, EventArgs> eventHandler)
    {
        lock (eventsSubscribedTo)
            eventsSubscribedTo.Add(new KeyValuePair<Type, WeakReference>(typeof(TEventType), new WeakReference(eventHandler)));
    }
 
    public static void Publish<TEventType>(object sender, EventArgs e)
    {
        lock (eventsSubscribedTo)
        {
            RemoveGarbageCollectedEventHandlers();
 
            for (int i = 0; i < eventsSubscribedTo.Count; i++)
            {
                if (eventsSubscribedTo[i].Key == typeof(TEventType))
                {
                    var eventHandler = eventsSubscribedTo[i].Value.Target as Action<object, EventArgs>;
 
                    if(eventHandler != null)
                        eventHandler(sender, e);
                }
            }
        }
    }
 
    private static void RemoveGarbageCollectedEventHandlers()
    {
        for (int i = 0; i < eventsSubscribedTo.Count; i++)
        {
            KeyValuePair<Type, WeakReference> pair = eventsSubscribedTo[i];
            WeakReference value = pair.Value;
            var eventHandler = value.Target as Action<object, EventArgs>;
 
            if (eventHandler == null)
                eventsSubscribedTo.Remove(pair);
        }
    }
 
    public static void Unsubscribe<TEventType>(Action<object, EventArgs> eventHandler)
    {
        lock (eventsSubscribedTo)
            for (int i = 0; i < eventsSubscribedTo.Count; i++)
            {
                KeyValuePair<Type, WeakReference> pair = eventsSubscribedTo[i];
                Type eventType = pair.Key;
                WeakReference weakReference = pair.Value;
                var handler = weakReference.Target as Action<object, EventArgs>;
 
                if (eventType == typeof(TEventType) && handler == eventHandler)
                    eventsSubscribedTo.Remove(pair);
            }
    }
 
    public static void Clear()
    {
        lock (eventsSubscribedTo)
            eventsSubscribedTo.Clear();
    }
}

Please feel free to suggest improvement or errors I have not detected.

Labels: ,


24 October 2009

When you forget to prune your logging data


The last 8 months I have worked on and off on a municipal IT project, which have had many different subcontractors before me. The system pretty much does what it has to do, but the code is pretty smelly and could use a good deal of refactoring.

It's a learning experience to read such code. Once in a while you find little gold nuggets and intelligent solutions to problems, that you can really learn from. You also learn from the code smells and the truly "criminal" stuff that you find. It has made me think more on what constitutes a production ready system. More on that in a coming post.

What I want to share, was a pending bug that I found, after one of the servers the system runs on started to act strange and finally went dead. I found the following code:
static void Main(string[] args)
{
try
{
Application app = new Application();
app.Start();
}
catch(Exception ex)
{
Logger.Log(ex);
}
}
At first glance this looks fine (if you approve of a global exception handler like this), but once you've made the decision to log data of any kind, you must remember to prune your log, so that it does not grow out of proportion - which would be, when it takes up all hard disk space.

Once this happens, the OS will throw an IOException every time a write to disk is attempted. You see the trouble now?
  1. An exception occur somewhere in the system
  2. The exception is caught by the catch statement
  3. The logger tries to write the details of the exception to a log
  4. The hard disk is full and the OS throws an IOException
  5. Repeat from 2
This loop crashed the server due to a full hard disk and the consumption of all RAM.

I guess the programmer who wrote the Logger class did not ever consider, that his implementation would have the potential to crash an entire server, because it lacked pruning of the logs. I'll not lie. Only a few years back I would not have thought of it either.

So here's a rule of thumb you might try to remember:

If your code adds bytes to any persistent media, it is almost certain, that it should also remove bytes with some regularity.

Labels: ,


23 October 2009

Use AutoHotKey to enable easy BDD naming style

When writing BDD specifications I prefer to use StoryQ. But on smaller projects I often revert to using more traditional TDD with a dash of BDD naming style:

8 public class MessageBusTests

9 {

10 public void Should_send_message_when_event_occur()

11 {

12 // SUT code

13 }

14 }


But typing the underscores soon become tiresome so I use AutoHotKey and a script by JP Boodhoo to auto-insert an underscore every time I hit space.

If you would like to try this out, do the following:
  1. Install AutoHotKey
  2. Copy the file "BDD naming mode.ahk" to your start menu folder along with the two icon files from the zip file.
  3. Double click the .ahk file to enable the script or restart your computer.
Now you can turn on/off the BDD naming style using Ctrl+Shift+U. The BDD icon in your tray should change to indicate activation.

Download BDD naming mode script and icons: AutoHotKeyBDDNamingMode.zip

Labels: ,


22 October 2009

Extract list of installed programs on Windows XP

I'm moving to Windows 7 and as every time I change OS, I need a list of the programs, I have installed. It turns out, that it is pretty easy to get this list in Windows XP.

Here's how:
  1. Start > Run, type msinfo32.exe and press enter
  2. System information window opens
  3. Expand node Software environment and click Program groups
  4. The right pane of the window now display all your installed programs
  5. Select all using Ctrl+A and copy to clipboard using Ctrl+C
Now you can paste the list into excel or another file and save it to a network drive or an USB drive.

Labels:


19 October 2009

When your tests rot

The last 15 months I have worked as project manager, system architect and competency trainer at Transsoft A/S.

When I was hired, my task was to implement transparent project management, which would allow the board to know what development was doing and how the project was progressing. I also had to implement practices, which would empower the team to deliver software of a verifiable quality level.

ERP software is supposed to last many years, often 10-15 years. This means, that it must be built to be maintainable, and it must have a very extensible and flexible application architecture, which allow for easy implementation of customer specific busines rules and views.

In order to deliver a system with the kind of progress transparency and quality of architecture demanded by the board, I had the following agenda:

Concretely:
All these elements are needed in some form or shape, to deliver the kind of software we write. But the test-suite, that is the result of test-first development, is to me, the most important element, to ensure a steady progress and a certain level of quality to the code. A Lot of Good Things emerge when you do Test-Driven Development/BDD that I will not reiterate here,

The last few months I have spent a lot of my time developing a course department in Transsoft. This has had the consequence, that I haven't had the same focus on our practices and quality of the code, that I had before. My lack of focus on our practices have resulted in a rotting test-suite.

After a major refactoring (that I gave the greenlights on), our tests were not kept in synch, and we could no longer rely on them. This has reduced the confidence of the team, as we can no longer run all our tests and know, that adding a new feature or removing a bug, has not changed the expected behavior of the system. In addition, the test-suite is now technical debt and does the exact opposite of its intention - it reduces confidence instead of reinforcing it.

We have changed our sprint plan to give the developers time to refactor the tests to get in synch with the codebase. We also did a brush up on our DONE DONE DONE definition as well on why we use the practices we do. But this work takes time, velocity is reduced and refactoring 500+ tests is a pain.

So my advice to any team practicing TDD or unit-testing is to NEVER, EVER ALLOW YOUR TESTS TO ROT!

Labels: , , ,


This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]