Remote Pair Programming

2637887131_95e7b72a84

Photo by pat ong [licence]

I've recently taken an interest in whether it is possible to run a successful software development project with remote workers. With a crude and bit of Google research it appears that there is a split opinion among our community  especially within the Agile camp. What is obvious is that every one agrees that communication is critical. The pro-remote camp argue that with appropriate tooling it is possible to keep communication channel open and effective. The anti-remote group state that tooling simply masks the subtle interactions that are crucial to a successful team dynamic.

I've recently moved to Perth (WA) and part of my time is spent working on in an internal iMeta project with colleague based in our Southampton (UK) office. This is surely remote working gone mad, we are 9000 miles and 9 hours apart. How can this possibly work?

First off I would like to make the point straight away that I do not believe this to be an optimal working arrangement and is not something I would generally recommend but there are times when we have to accept that we may not have the luxury of having the entire team in the same location. By 'team' I am not only including developers, but all stakeholders.

By working in this extreme environment perhaps there are things we can learn that will help to us build a process that will embrace a level of remote working when the situation arises? Perhaps there aspects to remote working that can be used to help co-located projects?

I intend to keep posting my observations and thoughts on the subject but for this post I want to focus on one aspect of the remote working that has worked really well for us... Pair programming.

Pair programming from 9000 miles away?! Well yes. Communication is key and what better way than through pair programming and I'm not talking about pair programming once every iteration, we need to be doing this on a regular basis. Jason and I try to catch up for two to three hours every day, and through tools such as WebEx we are able to perform some very effective pair programming. Ok, so it is not so easy to grab the keyboard or scribble a sketch but I have been surprised as to how effective our pair programming session have been.

I've put this down to a number of reasons;

Time is Precious

Not more so than when you are 9 hours apart! Obviously we cannot dedicate a full working day to pair programming, but of the time that we are pairing we have to make every minute count. At the beginning of the session we have a clear objective and we run with it, often this changes but the intent to minimise waste is there from the outset. We also share some of the time zone burden, by that I mean that I tend to work into the evenings and Jason gets up early. We both feel a little bit of pain which probably means we both have an incentive to make sure we are productive with the time we have.

Fewer Distractions

Possibly linked in part to the above, but when pairing in a co-located environment, especially in a busy office environment it is easy to become interrupted or distracted. People are less likely to interrupt you when you have a set of headphones on and are talking to your computer. Perhaps they think it might be catching! It is amazing how easy it is to loose your train of thought when the phone keeps ringing or some one asks you 'a really quick question'.

Short Effective Bursts

Effective pair programming can be quite intense and difficult to sustain. We only have a few hours in the day which gives us time when we are not pair programming to reflect and change pace. Often I'll spend some time getting test cases we wrote together to pass or to write candidate tests for the next set of stories which gives us a great head start for the next session. It also gives you time to do the more mundane tasks like writing up the next iteration plan or catching up with your emails. These are not any less important but it forces you to change perspective which is often enough to stimulate ideas even if you are doing something completely unrelated.

 

There is nothing new here but it interesting to see that when forced with a circumstance that would otherwise be considered un-desirable it can make you more productive or at least perhaps a little more lean.

WPF UIElement.Focus()

I recently hit a problem when attempting to focus a control in WPF. Anyone who has looked into the focus model within WPF will know that there are three distinct ways of programmatically setting focus on an IInputElement. If you are interested in learning about how WPF handles element focus take a look at the MSDN. For a quick review here are the three mechanisms for setting focus in code.

Keyboard.Focus()

WPF defines keyboard focus as the element that is currently accepting keyboard input. There can only ever be one element on the entire desktop that has keyboard focus. To manage keyboard focus we use the Keyboard class.

Keyboard.Focus(TextBox1);

 

It makes sense that keyboard focus can only be applied to elements that are visible and that some elements should not be able to receive focus, usually container elements. Therefore Focus() will not succeed if either IsVisible or IsFocusable for the target element is false.

FocusManager.SetFocusedElement()

As user interfaces are become more contextual it is useful to be able to control focus behaviour within the logical regions of a user interface. For example, how can I control the element that will receive focus when a given user interface fragment becomes active? This is what WPF describes as Logical Focus. UI elements, usually container elements, are defined as being a Focus Scope, and within a given focus scope it is possible to specify an element that has logical focus. When the focus scope becomes active the element having logical focus gets keyboard focus. To specify logical focus we use the FocusManager class.

FocusManager.SetFocusedElement(focusScope, TextBox1);

 

UIElement.Focus()

If you are new to WPF and you want to set focus on an element the chances are you will come across this conveniently located method. This method first attempts to set keyboard focus on the target element, failing that will attempt to set logical focus.

TextBox1.Focus();

 

Back to the Problem

I have a UserControl containing a number of UIElements. The user control is dynamically loaded into a ContentControl and I want to  specify which UIElement is to receive focus before the UserControl is loaded. My UserControl may be replaced by other content depending on the actions of the user.

I simply create the UserControl and call UIElement.Focus() on my required element. Of course my control will not get keyboard focus as it is not yet visible so instead it will receive logical focus within the focus scope that is my UserControl.

This all works beautifully until you come across the situation where the logical focus for the UserControl has already been set. For example, what if reuse my UserControl instance and it already contains an element that has logical focus?

Mysteriously, UIElement.Focus() is simply ignored and focus remains with the element that previously had logical focus.

The reason for this is apparent if you look at what UIElement.Focus() is actually doing.

...
DependencyObject focusScope = FocusManager.GetFocusScope(this);
if (FocusManager.GetFocusedElement(focusScope) == null)
{
    FocusManager.SetFocusedElement(focusScope, this);
}
...

 

So UIElement.Focus will only succeed if logical focus has not already been set.

Not only can we see the problem but we are presented with a simple solution. Use FocusManager to set logical scope if you know you want logical scope.

I cannot see any benefit for UIElement.Focus allowing logical focus within a focus scope to be set only once. I would be interested to hear any ideas as to why it should.

Don't 'Do' Agile

Can you relate to the following?...

  • You spend more time discussing Agile than you do delivering on customer requirements.
  • You practice Agile, it seems to work but you cannot say why.
  • You practice Agile, it doesn’t seem to work and you cannot say why.
  • You scour Agile blog posts (like this) and immediately try out everything you read.
  • You do not deviate from what you read about Agile for fear of ‘not being Agile’.

 

Instead....

Use basic iterative principles (plan, do, review, repeat) to incrementally grow a process that enables you to meet the needs of your customer.

  • Identify any impediments which affect your ability to deliver to your customer needs.
  • Quantify the risk/cost of an impediment.
  • Identify any corrective processes and practices (Agile or not) and quantify the associated risk/cost to your project.
  • Only implement corrective action if the cost/benefit is justified.
  • Continuously evaluate the effectiveness of all processes and practices.
  • Constantly strive to eliminate waste; if it isn’t working, change it or stop doing it.
  • Use common sense.
Never Forget...

 

 


Oh..what it would be like if every blog, article, book, conversation that I have ever comprehended could be recalled, at will, in perfect technicolor detail. Unfortunately, I'm simply not wired up like that. Last year I read Derren Brown's Tricks of the Mind, a great read which I thoroughly recommend. In the book Derren explains some memory techniques which I religiously practiced. Sure enough after only a relatively short time I was able to recall, in order, a full deck of a randomly shuffled playing cards. Not only that but ask me what the nth card is and after just a moments pause could tell you with complete confidence. I must admit this is a great party trick, but does require locking yourself away in the toilet for an hour or so which is not so great. Transferring this sort of thing to the real world takes a considerable amount of practice, time and mental energy. Other than remembering the odd shopping list I have not managed to master this for any practical application.

Time for another approach. Until recently I have only considered using wikis for collaborative knowledge management. There are however a range of personal wikis that do a brilliant job cataloging all those snippets of information that you encounter during the day.

I've only tried out bLade but it works a treat. The beauty of bLade is it is purely file based so runs happily off a memory stick which now goes wherever I go. It also runs on Windows mobile, which I like the idea of but have yet to try out.

I have setup three Wikis, one for everything development related, one for personal stuff like important dates, recipes etc and one that I call Work In Progress which is just a brain dump of stuff which I use when I need to quickly get something down before it deserts me.

Simple, effective, and considerably less time spent in the loo!

When CryptoStream Goes Wrong...
I've just stumbled across an annoyance of System.Security.CryptographyCryptoStream. We are using it to decryrpt a encrypted file which works a treat, except when things go wrong.

Consider an API like this....

interface IStorage 
{
Stream OpenRead(FileInfo file);
}

class SecureStorage: IStorage
{
public Stream OpenRead(FileInfo file)
{
ICryptoTransform transform = GetCryptoTransform();
FileStream fs = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
return new CryptoStream(fs, transform, CryptoStreamMode.Read);
}
}

After you have finished reading you should close the CryptoStream which in turn should close the underlying stream. 

try 
{
Stream s = storage.OpenRead(file);
try
{
// read stream
}
finally
{
s.Close();
}
}

If all is well. In the event that the cypher data is corrupt we expect an exception while reading the stream. Not a problem our finally block ensures that the stream is closed and we can handle the exception as we see fit.

..Well not quite.

Calling Close() simply delegates to Dispose(true), in turn, dispose attempts to decrypt any remaining data in its internal buffer before closing the underlying stream. However, we have just discovered that the contents of this buffer is garbage and cannot be decrypted so an exception is thrown from Dispose() and we are left with an underlying stream that is left open.

Any immediate attempt to write to the corrupted file will be met with exceptions claiming that the file is already being used.

A workaround for this is to implement our own Stream which holds a reference to the underlying stream and is kind enough to close it when something goes wrong.

Testing SSL Enabled Smart Clients Using WebLoad
We have recently been having problems testing a smart client application with load testing software such as WebLoad. Whenever the load testing software was set to record the client would fail to communicate with the server. We eventually nailed the reason down to an invalid SSL Certificate. Most load testing software works by configuring a proxy that records http traffic. For SSL sites the client is required to negotiate and SSL handshake with the proxy and thus the proxy must issue a certificate when challenged. The problem is the proxy will by default present some sort of test certificate which your client will probably (and should) baulk at. The reason being that:
  1. The certificate is probably not trusted
  2. The certificate name returned from the testing software will not match the name of the requested site.
To get round this we need to get the load testing software to respond with the servers actual certificate and not its own.
To do this for WebLoad you need to do the following:
  1. Export the test server certificate from IIS. This is the server that the web services are hosted on. You should end up with a pfx file.
  2. Convert the certificate file generated from (1) to a pem file this can be done by using a tool such as openssl http://gnuwin32.sourceforge.net/packages/openssl.htm
  3. Open up a command prompt and navigate to C:\Program Files\GnuWin32\bin or wherever you have installed openssl
  4. Run the following command: openssl pkcs12 -in c:\certs\yourcert.pfx -out c:\certs\cag.pem –nodes
  5. Open WebLoad and go to the Tools > Record Options menu
  6. Select “Proxy Certificates”
  7. Select the certificate generated from step 2 and enter the certificate password.
  8. Select OK and test away.
Incedentally this is not a problem when running WSE2.0 out of the box which is a bit worrying really. The problem only surfaced when we switched to WSE 3.0. If you are interested you have complete control over the server certificate and whether to accept it. Below is an example of how to intercept the certificate, interogate any errors and choose whether you want to proceed.

// The following method is invoked by the RemoteCertificateValidationDelegate.
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
   if (sslPolicyErrors == SslPolicyErrors.None)
      return true;

   Console.WriteLine("Certificate error: {0}", sslPolicyErrors);

   // Do not allow this client to comunicate with unauthenticated servers.
   return false;

}

// Register the delegate
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);