Works on My Machine

Development on RAD systems (such as C#) are usually prone to logical errors for the following reasons:
  • Distinct and obvious errors do not cause catastrophic crashes:
    • Languages such as C++ do not really have these issues: if your code runs for more than 5 minutes with no memory leaks and crashes you can be pretty sure it will run for 3 days on anyone's machine.
  • Developers tend to get lazy because the language is so convenient and helpful:
    • Languages such as C++ don't have this problem because of the simple fact that if you are lazy it just wont work.
  • Developers assume a false sense of security because of features such as the GC:
    • The GC isn't a golden hammer and most are far from perfect.
    • There is no OperatingSystem.Create() method, nor should you treat the language in such a way that there is.
  • And many, many more!

Because of these distinct problems developers must assume a rigid testing development process, however, TDD (test driven development) does not solve all of the above problems and is not a suitable development paradigm alone (it should rather be seen as an addition to another paradigm). Developers must assume responsibility for their code and combine a working development paradigm (such as Extreme Development) with TDD.

Being an operating system, Ensemble is rather difficult to test. Features such as the Memory Manager could be hard to test reliably outside of the kernel (especially because these features communicate directly with the hardware). Developers should try thier best to provide interfaces which can be used outside of the kernel. For instance, the Memory Manager could be interfaced as follows:

public abstract class MemoryAllocator
{
  public Alloc(MemoryRegion region) {...}
  public DeAlloc(MemoryRegion region) {...}
  public long MemorySize { get {... } }
}

public class MemoryManager
{
  public static MemoryAllocator Allocator
  {
    get { ... }
    set { ... }
  }

  public static Object Allocate(Type t)
  {
    // Find a free location.
    MemoryRegion region = new MemoryRegion(start, length);
    Allocator.Alloc(region);
    Object o = new Object(t, region);
    return o;
  }

  public static void Free(Object o)
  {
    Allocator.DeAlloc(o.Region);
    // Free internal tables.
  }
}

public class KernelAllocator : MemoryAllocator
{
  // Real, fast and error-agnostic allocator.
}

public class TestAllocator : MemoryAllocator
{
  // Fat (large) objects to ensure memory is not allocated twice.
}

public class MemoryManagerTests
{
   public void ManagerTest()
   {
      MemoryManager m = new MemoryManager();
      m.Allocator = new TestAllocator();
      // Allocate a large amount of objects.
      ((TestAllocator)m.Allocator).Verify();
   }
}

works-on-my-machine.png (29.5 KB) Jonathan Dickinson, 05/12/2008 09:21 AM

Also available in: HTML TXT