Tales from the AntiTestingSide - My Process vs. Typical Corporate America

Automated Testing and Test-Driven Development are wonderful concepts. They are time savers in the LONG RUN. That's the hardest part to grasp. What I want to get across is that in order to even GET to Automated Testing and TDD, the project has to have these methodologies in mind when gathering requirements and designing the system! This is where my process differs from most big corporate shops.

Typical development shop development process:
  • Business unit says they "need" a piece of software developed
  • Development shop talks to business unit and says, "Yes we can do that" (doesn't matter if they can't, cause answer is always yes)
  • Business Analyst's are sent for a few months to gather requirements
  • Over-formalized Use case's are created and sent to developers (not easily readable)
  • Programmers look at use cases and go back and forth with Business analysts about what needs to be done (waste of time)
  • Programmers start coding
....... 6 months later
  • Programmers still coding, no testing yet
  • Development of application is "finished" and is sent to QA
  • QA tests for a month or 2
  • QA finds bugs, sends defect list back to Developers
  • Developer spends weeks fixing defect list (waste of time and money)
  • Application sent back to QA to check one last time
  • QA finds defects, but they aren't show stoppers
  • Application is released and now falls into maintenance mode
  • Programmer starts working on first BugFix Release
  • Programmer makes changes, releases code as fix
  • Fix breaks already existing production code
  • Now a mess insues
  • ... and the process continues
Screw that. WAY too many things going on that could have been caught beforehand with a little better and easier planning along with automated regression tests.

How do we get there if we don't know where to begin? Easy.

Read my Use Case post first, before continuing.

My process:
  • Contact business that needs application
  • Find out who's going to be using it (think of this as "roles" within the application)
  • Ask HOW each of those people are going to be using it (i.e. ReservationSpecialist will search for an existing reservation)
  • Find out HOW a ReservationSpecialist searches for an existing reservation -- what do they usually search by?
  • By breaking down these simple business tasks (Elementary Business Process [Larman]) you can wrap an easier time estimation around it or have a really good idea of the difficulty for each task.
  • By using the SIMPLE use case format, that is your test case for code
  • Invoke TDD metholody for this use case
  • Rinse and Repeat -- it's that easy
The overall goal in my process is to get something working as soon as possible. The reason for this is to make sure it all works within the customer's infrastructure. It's better to catch issues in the beginning than at the end -- even if it's in a test environment. Sometimes you can develop and application and by the time it's LIVE, you find out that the user credentials aren't working or something of that nature. Catch it early!

Using the example above of a ReservationSpecialist... I would aim for requirements that would get me to an end product with limited features. This requires thinking on your part. Yes, it's difficult. Yes, it's your job. Yes, you have to use your brain more than you do now opening a bag of Fritos.

The application would probably be able to do the following:
  • Log a user in , if they don't exist have them create a login
  • Have an option to "search existing reservations"
  • Have a Search form for Existing Reservations that had options to search by and some way to submit the search
  • Have the Search form list the results
  • Deploy the application to the test server
  • Make sure everything is gravy
That would provide a "pipeline" to start making feature additions. As developers and programmers, if theres something we can "update" or "add features" to.. It's more enjoyable and more productive since we're ADDING to and not ALWAYS IN DEVELOPMENT.

...until next time.

When is it OK to not write a test?

As much as I love TDD and automated testing, sometimes it just doesn't fit in. I can assure you though, writing atleast one test that covers the majority of a requirement, is very worth it.

To answer the question "When is it OK not to write a test?", I'm going to have to say "never". If you break down the metrics as follows:

1. Write code
2. Stop application that's running in test environment
3. Clear/delete any logs
4. Start application in test environment
5. Click buttons, enter values, waste more time
6. Check all the values after doing Step 5

The above is just not feasible to sustain any type of momentum. Most projects are written like this, we must stop wasting so much damn time. The second I find myself doing something repeatedly I think, "How can I make this a test of some sort?". Whether it be integration or unit or just something automated, the redundancy must be removed.

Instead of the above example, do the following for each elementary business process:
1. Write test (NUnit framework)
2. Run test
3. Test failed (because there's no code, obviously, so now we have a test that we know is failing)
3. Write Code (so we can get the test to pass that we coded)
4. Run tests
5. ... rinse and repeat

Microsoft Exchange via CDOEX - Part 1

Why does Exchange 2000 suck for this? You have to use some of the COM libraries

Exchange 2007 won't have any issues since it will expose some WebServices from what I've read and heard.

The libraries needed to interact with Exchange2000 from .NET aware languages to my knowledge are:
  • Microsoft ActiveX Data Objects 2.5 Library
  • Microsoft CDO for Windows 2000 Library
My dislikes to this approach:
  • Not very clean to use
  • The COM Object hangs if you try to re-connect/re-access Exchange
    • I'd like to know if anyone out there has this happen to them, I might just be doing it wrong?
To remedy the hanging issue -- I implemented a static MailServerFactory.Create() method which created an AppDomain (thanks to my friend Thomas for making this suggestion) to run the Exchange2000 class in . This Exchange2000 class had the calls/creation of all the CDOEX objects and it works GREAT. Of course, the Exchange2000 class had to inherit from MarshalByRef to get through the remoting proxies across AppDomains.

Definitely more information will be posted for the next few parts.

Microsoft Exchange via CDOEX - Part 2

Heres the current structure of the code:

EmailServerFactory
|-->Create() :: ExchangeServerClass

EmailServerFactory.Create() will load an appDomain with the ExchangeServerClass.

The ExchangeServerClass makes calls to the MailParserFactory.Parse() method which is in the *same* assembly. And returns the following:

MailParserFactory
|-->Parse(emailAddress) :: IEmail

The client Console application is the following:

IEmailServerFactory emailFactory = EmailServerFactory.Create()
IEmail[] emails = emailFactory.RetrieveMessages(MessageFlags.New)
emails.ForEach(delegate(IEmail email) { Console.WriteLine(email.Subject); })

Since the EmailServerFactory.Create() method is loading an AppDomain behind the scenes and returning the IEmailServerFactory instance one has to be careful of the information being passed back from any functions from a class like that.

Line #3 throws an Exception because you're crossing AppDomain's at that point (trying to access a class that was created in another AppDomain). To remedy this problem I had to mark the classes as Serializable (the classes that implement the IEmail interface)

VB.Net is so dreamy it makes me want to vomit.

More code to instantiate a class:
Dim foo As Bar = New Bar()
vs.
Bar foo = new Bar();

Anonymous Delegates: haha, right

Implementing an interface: You have to mark all the methods in a class with "Implements "... Sometimes you want Explicit interfaces, sometimes you dont?

And the biggest thing that pisses me off that I ran across just recently.......... NON-NULL CONDITIONAL! This just makes you say "Wtf" over and over, I know I did.

Vb.Net Version
Return (Not foo Is Nothing)
C# Version
return (foo != null)

Which one of the above is easier to read for you?
(yes, the above code is bad, but still a pain in the ass nonetheless)