Wednesday, February 24, 2010

Testing as a Concern

I was asked a question about unit testing based on this code:

   1: protected void Page_Load(object sender, EventArgs e)
   2: {
   3:     logger.Info(@"Loading the AgentDetails 
   4:         page");
   5:     
   6:     this.InitialiseRequest();
   7:     this.SetHeaderTabs(HeaderTabs1, 1);
   8:     
   9:     logger.Info(@"Webservice method 'getAgentDetails' 
  10:         is called from the Web References layer");
  11:     
  12:     WSLayer.AgentDetails agtDet = this.WebService
  13:         .getAgentDetails(this.AgentCode);
  14:  
  15:     this.AgentName = agtDet.Subagent[0].Fullname;
  16:     this.SetTitleBar(HeaderTitleBar1);
  17:     this.SetAgentDetails(AgentDetails1);
  18:  
  19:     logger.Info(@"End of Loading the AgentDetails 
  20:         page");
  21: }

Here is the question - “Can I write asserts inside this block itself?”. And a great tremor was felt in The Force.

From Wikipedia:

In computer science, separation of concerns (SoC) is the process of separating a computer program into distinct features that overlap in functionality as little as possible. A concern is any piece of interest or focus in a program. Typically, concerns are synonymous with features or behaviors. Progress towards SoC is traditionally achieved through modularity of programming and encapsulation (or "transparency" of operation), with the help of information hiding. Layered designs in information systems are also often based on separation of concerns (e.g., presentation layer, business logic layer, data access layer, database layer).

For those who are unfamiliar with this concept, it is a far reaching design guideline that can help us create code that adheres more effectively to the SOLID design principles. It also forces us to keep our code focused on the underlying behavior of each concern and to make better choices about how each concern will interact.

There is, however, one area that is never discussed in terms of its being a “concern”, but should be - testing. The same level of effort should be applied to testing (and by this I mean unit testing), as to the design of a UI or data access layer. In fact, the amount of time spent on testing should be more than any other concern, as it applies to all other concerns. This also means not putting debug code into your production code. That is a concern of testing, and should be treated as such.

We must raise testing to the same status as any other concern and treat it with the same level of dedication, discipline, and respect.

Wednesday, February 17, 2010

I Can Name That Month in One Extension Method

The other day I was working on a project where it was important to get the full name of the month from a specified date. So off I went to start writing an array that contained the full name of all the months. In the back of my mind, however, my coder’s conscience was letting me know this solution was a path to problems. I started thinking of the maintenance nightmares that would ensue when issues such as abbreviated month names and multi-lingual support would start to creep in (and turned out to be a requirement for this particular client). The last thing I want to do is try to keep up with lists of months and abbreviations in French or German or Hindi. So I went in search of a better solution and my travels revealed the .NET framework already supported this functionality.

The secret can be found in the CultureInfo class. Not only did this eliminate the need for multiple lists for names and abbreviations, it also has multi-lingual support. Score!

The method looks like this:

   1: CultureInfo.CurrentCulture.
   2:     DateTimeFormat.GetMonthName(1);

And this returns January. I didn’t want to have to type this out every time a month name was needed so it was time for the help of an extension method:


   1: public static class DateTimeExtensions
   2: {
   3:     public static string GetMonthName(this DateTime dt)
   4:     {
   5:         return GetMonthName(dt, 
   6:             CultureInfo.CurrentCulture);
   7:     }
   8:  
   9:     public static string GetMonthName(this DateTime dt,
  10:         CultureInfo currentCulture)
  11:     {
  12:         return currentCulture.DateTimeFormat
  13:             .GetMonthName(dt.Month);
  14:     }
  15: }

Now I can get the full name of a month from any culture. But wait, there’s more…


   1: public static class DateTimeExtensions
   2: {
   3:     public static string GetMonthName(this DateTime dt)
   4:     {
   5:         return GetMonthName(dt,
   6:             CultureInfo.CurrentCulture);
   7:     }
   8:  
   9:     public static string GetMonthName(this DateTime dt,
  10:         CultureInfo currentCulture)
  11:     {
  12:         return currentCulture.DateTimeFormat
  13:             .GetMonthName(dt.Month);
  14:     }
  15:  
  16:     public static string GetAbbreviatedMonthName(
  17:         this DateTime dt)
  18:     {
  19:         return GetAbbreviatedMonthName(dt,
  20:             CultureInfo.CurrentCulture);
  21:     }
  22:  
  23:     public static string GetAbbreviatedMonthName(
  24:         this DateTime dt,
  25:         CultureInfo currentCulture)
  26:     {
  27:         return currentCulture.DateTimeFormat
  28:             .GetAbbreviatedMonthName(dt.Month);
  29:     }
  30:  
  31:     public static string GetDayName(this DateTime dt)
  32:     {
  33:         return GetDayName(dt, 
  34:             CultureInfo.CurrentCulture);
  35:     }
  36:  
  37:     public static string GetDayName(this DateTime dt,
  38:         CultureInfo currentCulture)
  39:     {
  40:         return currentCulture.DateTimeFormat
  41:             .GetDayName(dt.DayOfWeek);
  42:     }
  43:  
  44:     public static string GetAbbreviatedDayName(this 
  45:         DateTime dt)
  46:     {
  47:         return GetAbbreviatedDayName(dt,
  48:             CultureInfo.CurrentCulture);
  49:     }
  50:  
  51:     public static string GetAbbreviatedDayName(
  52:         this DateTime dt,
  53:         CultureInfo currentCulture)
  54:     {
  55:         return currentCulture.DateTimeFormat
  56:             .GetAbbreviatedDayName(dt.DayOfWeek);
  57:     }
  58: }


Now we get months and days, full and abbreviated names, in any culture. Cool huh? Now we can write code like this:


   1: string date = "1/1/2010";
   2: string monthName = DateTime.Parse(date)
   3:     .GetMonthName();


Wednesday, February 10, 2010

#endregion

There has been some talk lately about regions and whether they are good or bad. I have finally loosed the shackles of regions once and for all. Yes, my code was once rife with what I thought were well organized regions of thought and code, but therein lies the problem. It is very seductive to become ensnared in the warm embrace and the illusion of organization that regions provide. In reality, regions hide code and this opens up the door for a crazy glue sniffing code fairy to sneak into your house. The next thing you know, there's money missing off the dresser, and your daughter's knocked up. I seen it a hundred times…but I digress.

If you feel compelled to wrap your code in a region, ask yourself why. Are your methods getting too long to read without paging? Does the class have so many properties that you spend more time scrolling than writing code? Are you using them to “clean up” the code? All of these are indications that the code is need of refactoring, or at the very least re-evaluation.

If your code is grouped within nice neat region packaging, you are probably ready to take the next step and move those regions into their own classes. Do not forget the Single Responsibility Principle is our friend. Regions also increase the likelihood that code that needs to be changed, refactored, moved, or deleted will get missed.

Removing regions also goes a long way to increasing code readability. One thing we should strive for is writing code in such a way that it communicates more effectively with other developers.

Regions are often the rug under which ugliness gets swept. It is time to release the dust bunnies and clean up your code.

Wednesday, February 3, 2010

Your Honor, I Object

Have you ever had a conversation with another developer that started off with you talking about one of the SOLID design principles or a design pattern only to have them dismiss you entirely with “yeah, but that will only add more classes to my project” or “that is over engineering the code”? Why are some developers so resistant to these ideas? I would suggest that it is due, in part, to fear.

Fear of what you ask. It is in three general areas: lack of knowledge (ignorance), lack of skill (laziness), Genius Developer Syndrome (exposure). So let us look deeper into the mindset of the “fearful developer”.

Ignorance is the lack of knowledge of something. When a fearful developer is presented with something they do not know or understand, they become defensive and dismissive. Rather than admit they do not know something, they will use baseless arguments that sound important such as, “that will potentially cause a proliferation of classes in my domain which will have a negative impact on the overall performance of the system”. If you examine arguments like this, you will often find them to be devoid of any substance and based solely on conjecture.

Class proliferation can occur, and is often a side-effect of poor design. The fearful developer is by and large a lazy one. The fearful developer does not feel obligated to educate themselves or to put in the time, effort, energy, and erudition necessary to acquire the requisite skills. They stick to a well worn path, even if that path leads to a dead-end piled high with technical debt or what I refer to as “spaghetti in a haystack”.

And then there is the deific ivory colored cocoon that some developers have made a career out of shrouding themselves in. They are more devoted to keeping alive the illusion that they are the infallible genius developer than admitting they are not perfect. This is the most egregious fear of all because it is the most self-serving.

The path of Zen Coding teaches us to always carry an empty cup, to never be satisfied with where we are, and to always look for ways to improve ourselves. It is our responsibility as professionals to constantly challenge ourselves so that we may avoid the hazards of the fearful developer.


Fear leads to anger. Anger leads to hate. Hate leads to suffering.







If ever worked on a project with a fearful developer you have, or with their technical debt on a codebase dealt, then you know what suffering is.