Saturday, April 19, 2008

To become a better programmer

I think some books might help to become a better programmer. This is my personal list:

Erich Gamma, Richard Helm, Ralph Johnson, and John M. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional Computing Series)

The book came out, when I finished university and started by first full time job as an programmer. The theory of patterns taught me about the importance of names for concepts and the importance of communication with other developers. Five years later I went to a conference just to see Erich Gamma. Of course he spoke about patterns, but combined his talk with TDD, JUnit and a comparison of Java and C#. The lecture was not very long but brilliant. That was the first time I heard about TDD and got test infected.

Martin Fowler Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series)

I read the book, when I already worked on enterprise applications for several years. The book was an revelation. Most of the problems described there I know very well, but now I got names for them and so many alternative solutions. This book gave me the possibility to better reflect about design and architecture decisions. This book was partly responsible that I became the architect of our project.

Martin Fowler, Kent Beck, John Brant, and William Opdyke Refactoring: Improving the Design of Existing Code (Addison-Wesley Object Technology Series)

Beside the refactorings and the theory, this book helped me so much to convince my team members of the benefits of TDD.

Eric Evans Domain-Driven Design: Tackling Complexity in the Heart of Software

Brilliant book! The concept of the 'ubiquitous language' helped me very much for my day to day work. Using the 'Layered Architecture' pattern to separate technical details from the business concepts helped to better organize our software components.

Bertrand Meyer Object-Oriented Software Construction (Book/CD-ROM) (2nd Edition) (Prentice-Hall International Series in Computer Science)

Maybe this is the oldest book in my collection. Nevertheless it is still useful for me. I use assertions and 'programming by contract' nearly every day. This concepts can be used together with TDD very well. Even if you do not use Eiffel as the programming language, you can implement an assertion class for every other programming language in several minutes.

Mary Poppendieck and Tom Poppendieck Lean Software Development: An Agile Toolkit (Agile Software Development Series)

I never believed that other industries can teach the software industry about new concepts. After reading this book I know that the people from Toyota were very clever and the software people can learn a lot from them. Now I always try to find some 'waste' in our processes.

Kent Beck Extreme Programming Explained: Embrace Change (2nd Edition) (XP Series)

Although I never had the chance to work in a full blown XP project, this book is still a constant source of inspiration.

Kent Beck Test Driven Development: By Example (Addison-Wesley Signature Series)

If you start with TDD, read this book.

Gerard Meszaros xUnit Test Patterns: Refactoring Test Code (Addison-Wesley Signature Series)

If you already worked a little bit with TDD, then read this book.

I'm very sure everyone has its own list. I would be glad to here from other people about their favorite books.

Monday, March 31, 2008

Mail Attachments without files

I just received a comment about an article I wrote for www.codeproject.com. The article describes how to create and send mails with attachments in C# (no rocket science :-). The attachments are created in-memory without any file system access by the use of a memory stream: http://www.codeproject.com/KB/IP/InMemoryMailAttachment.aspx

Friday, March 28, 2008

TDD for Beginners

Recently a colleague of mine, which is a quite experienced programmer, wants to write his first code using TDD. It takes only minutes until he encountered the first obstacle. It seems that TDD is quite difficult for beginners. I will describe some of the problems and show code examples to help TDD beginners to become familiar faster with this excellent technique. Based on these kinds of experiences I described also a pattern called Own Library Interface which is applicable in the situation described below. My colleague needs to implement a background service, which monitors a database. The background service has to send notifications to one or more external receivers. He designed an EmailSender class, which can be initialized with all email related information like the smtp server, the sender and the receiver email addresses. Now he wants to write the SendToAll() method, which only needs some information for the receivers:
public void SendToAll(string subject, string details)
He has already poked around in the .NET framework and has found the SmtpClient class for easy sending of emails. He wants to use this class in his own EmailSender class. He knows that he first has to write a test, if he wants to follow the TDD principles, before he can begin with the implementation. He starts to implement the test method, which should verify the successful execution of the method:
[TestFixture]
public class EmailSenderFixture
{
  [Test]
  public void SendToAll()
  {
    // Setup
    EmailSender sender = new EmailSender();
    ...

    // Exercise
    sender.SendToAll("TestSubject","TestDetails");

    // Verify
    // ?
  }
}
How can he verify the outcome of the SendToAll method? One solution would be to let his own class send emails to an email account and then checking the correct behaviour of his class by retrieving the emails via POP3. This solution has some disadvantages:
  • The tests would be very slow.
  • The tests need special preconditions (context) to run (smtp server, email account).
  • The tests would not only cover the functionality of the class alone but also the .NET framework class SmtpClient. Framework classes do not need to be tested, because it can be assumed that they work correctly. (Even if they do not, we can't do anything about that)
  • The retrieval of emails via the POP3 protocol has to be implemented only for the automated tests, which are currently not need for the production system.
I would always prefer to use state verification, that means verifying the outcome of a method by inspecting the state of the manipulated object, but in this case the class has no state which can be verified. As we have seen, the state verification of a backdoor (a real email account) has many drawbacks. An other solution would be the use of a mock object as a test double for the SmtpClient. Currently our SendToAll method is empty and uses no dependent object, which can be mocked out. My colleague decided to use mock objects to verify the behaviour of his class. He starts implementing an initial version of his method, before he finishes his test method. The initial version looks like this:
public class EmailSender
{
 private SmtpClient smtpClient;
 ...
 public EmailSender(
  SmtpClient smtpClient,
  string host,
  int port,
  string from,
  params string[] recipients)
 {
  this.smtpClient = smtpClient;
  this.from = from;
  this.port = port;
  this.host = host;
  this.recipients = recipients;
 }

 public void SendToAll(string subject, string details)
 {
  smtpClient.Host = host;
  smtpClient.Port = port;

  foreach (string recipient in recipients)
  {
      smtpClient.Send(
   from,
   recipient,
   subject,
   details);
  }
 }
}
He already injected the SmtpClient object via the constructor and uses this object to send the emails. This is a nice try but unfortunately he can't mock out the SmtpClient yet. The SmtpClient framework class does not inherit from any interface nor does it declare its methods as virtual, so he can't create a mock object for SmtpClient. This lack of 'mockability' is quite common for most of the classes in the Microsoft .NET framework. Cwalina and Abrams [1] are describing rules for the design of framework classes: "Class-based APIs can be evolved with much greater ease than interface-based APIs because it is possible to add members to a class without breaking existing code". From the perspective of framework designers it is absolute understandable, that most of the classes do not use interfaces. As unit test authors we have to write our own interfaces which mirror the API of the framework classes as close as possible and later write very thin wrappers inheriting from our interface. My colleague only uses two properties and one method of the SmtpClient class. He only needs to declare these members in his new interface:
public interface ISmtpClient
{
 string Host { get; set; }
 int Port { get; set; }
 void Send(string from, string recipients,
      string subject, string body);
}
Now he can slightly modify his EmailSender class to use the ISmtpClient interface instead of SmtpClient framework class directly:
public class EmailSender
{
 private ISmtpClient smtpClient;
 ...
 public EmailSender(
  ISmtpClient smtpClient,
  string host,
  int port,
  string from,
  params string[] recipients)
 {
  this.smtpClient = smtpClient;
  ...
 }
 ...
}
He finishes his test and verifies the behaviour of the EmailSender class. He is using the NMock2 framework for his mock object:
using NMock2;
...
[Test]
public void SendToAll()
{
 // Setup
 Mockery mocks = new Mockery();
 ISmtpClient smtpClientMock = mocks.NewMock<ISmtpClient>();

 EmailSender sender = new EmailSender(
  smtpClientMock,
  "smtp.test.com",
  25,
  "sender@test.com",
  "receiver1@test.com",
  "receiver2@test.com");

 Expect.Once.On(smtpClientMock).
  SetProperty("Host").
  To("smtp.test.com");
  Expect.Once.On(smtpClientMock).
  SetProperty("Port").To(25);

 // We expect that the Send method is called for every recipient
 Expect.Once.On(smtpClientMock).Method("Send").
  With("sender@test.com", "receiver1@test.com",
       "TestSubject", "TestDetails");
  Expect.Once.On(smtpClientMock).Method("Send").
  With("sender@test.com", "receiver2@test.com",
       "TestSubject", "TestDetails");

 // Exercise
 sender.SendToAll("TestSubject", "TestDetails");

 // Verify
 mocks.VerifyAllExpectationsHaveBeenMet();
}
This test runs very fast and it does not need any special context like an smtp server or an email account. Before he can use the EmailSender class in a production environment he has to implement a thin wrapper around the SmtpClient framework class:
public class SmtpClientWrapper : ISmtpClient
{
 private SmtpClient smtpClient = new SmtpClient();

 public string Host
 {
  get { return smtpClient.Host; }
  set { smtpClient.Host = value; }
 }

 public int Port
 {
  get { return smtpClient.Port; }
  set { smtpClient.Port = value; }
 }

 public void Send(string from,
  string recipients,
  string subject,
  string body)
 {
  smtpClient.Send(from, recipients, subject, body);
 }
}
This wrapper needs not to be tested, because it adds no new functionality to the framework class. The EmailSender class can now be used in the background service:
public void Run()
{
 EmailSender sender = new EmailSender(
  new SmtpClientWrapper(),
  "smtpserver.xy.com",
  25,
  "sender@xy.com",
  "receiver1@xy.com",
  "receiver2@xy.com");

 while (!stopped)
 {
  // Check something
  string checkResult = Check();

  // Send email
  sender.SendToAll("Check", checkResult);

  // Sleep for 20 minutes
  Thread.Sleep(20*60*1000);
 }
}

Conclusion

Applying TDD as a new technique for software development is sometimes not easy for beginners. When we need to write software, which has to use framework classes, we need to use mock objects and we eventually have to introduce new interfaces and wrappers. The same problems we saw with SmtpClient arise when we have to use classes like System.ServiceProcess.ServiceController, System.Diagnostics.EventLog, System.DirectoryServices.ActiveDirectory.Domain, System.Net.NetworkInformation.NetworkInterface, System.Net.Sockets.Socket, System.Environment, Microsoft.Win32.Registry just to name a few. I hope this article can help a little bit to overcome the first hurdles when using TDD the first time.

References

[1] Cwalina, K., Abrams, B.: Framework Design Guidelines, Microsoft .NET Development Series, Addison Wesley, 2006