Archive for March, 2010

Book Review: Clean Code

cc_bookReview_CleanCodeI just finished my March book from my 2010 developer-oriented book reading list, so I thought I would share some thoughts on Clean Code by (Uncle) Bob Martin before moving on to my April book, Real World Functional Programming: With Examples in F# and C#.

Rating - star_sm star_sm star_sm (out of 5)

Prerequisites – The code samples in the book are in Java, so if you’re not a Java developer it’s probably worth going through a quick tutorial first. Most of the examples rely on low level coding constructs, so you can skip familiarizing yourself with the Java APIs and focus on just the basic language syntax and the common data structures. A quick 10 minute read of this high level language comparison will probably be sufficient for most C# developers.

The Good

  1. Conceptually Cohesive – Choosing “Clean Code” as a title and topic of a book was somewhat risky because it is such an intrinsically nebulous concept. However, Bob Martin overcomes these hurdles by defining “clean” as any practice that makes code easier to understand. Just like usability experts carved a respectable science out of UI design, this book adds objective weight to the topic by examining seemingly subjective practices through a lens of measurable efficiency. For example, “code noise”, such as redundant comments, is bad because it causes unnecessary eye movements and scrolling. Likewise, descriptive names, short methods, and small classes are all preferable because they minimize the short-term memory requirements of the reader and thus increase the speed of comprehension as well as the capacity to discover logic flaws.
  2. Thought Process Over Rules – Although the catalog of code smells and heuristics that Bob Martin provides towards the end of the book are helpful, his ability to recreate his thought process while refactoring code is definitely one of the more valuable parts of the book. Context is everything and learning rules without fully understanding when it is appropriate to apply them will almost always cause more harm than good (e.g. design patterns). The way the author sometimes changes his mind and even reverses himself as the code takes shape is a superb teaching technique because it models how to fully analyze the context. There were several times where I disagreed with his final solution, yet still felt satisfied that I had learned new ways to think more critically about the choices I was making.
  3. Code-Centric – Like rules without context, abstract concepts without extensive grounding in concrete examples are worse than useless. Another strength of the book is that it is code-heavy without ever being repetitive or wasting time on obvious examples.

The Bad

  1. Length of Case Studies – Although I firmly agree with the code-centric approach the book takes, I think it was a mistake to chose such large code samples to refactor in the second half of the book. I might have been more patient with the constant page flipping and mental gymnastics involved in reconstructing how code had changed if I weren’t already so used to using tools like Resharper, Subversion, Beyond Compare, and Fisheye. At the end of the later chapters I felt the same frustration I feel anytime I’m forced to revert to a manual task that provides a fraction of the value for a lot more effort. I just don’t think books are the appropriate medium for these types of large code reviews.
  2. Several Extraneous Chapters – There were several chapters in the middle of the book that seemed out of place and thus distracted from the main theme. For example, the chapter and rather large supplemental appendix section on concurrency devoted too much time to multi-threading fundamentals rather than focusing on the main them of how to increase readability. Likewise, several other chapters covered topics that were not directly relevant or were dealt with at a level that was too superficial. It reminded me of methods that Uncle Bob criticized in the book for mixing levels of abstraction. It would have been better if they had just been cut out of the book.

Conclusion – I struggled when trying to come up with an overall rating for this book because I absolutely loved the first hundred pages of the book but was decidedly less excited about the rest of it. Ultimately, I gave it three stars because I think it deals with a really important topic and does it quite well for a sizable part of the book.

If you are either a junior level developer or else haven’t read many other books about refactoring (e.g. Martin Fowler’s classic Refactoring), then I would consider this book a must-read and would definitely buy it. Otherwise, you’re probably better off just borrowing it and only reading the first one hundred pages or so.

Popularity: 1% [?]

Ninja Level Productivity Tip: Evading an Unwanted Meeting in 3 Easy Steps

Do you have a meeting coming up that you desperately wish you could get out of?

Try this nifty trick that I picked up from my boss.

  1. Find a meeting at least 1 week in the future and click “Propose New Time” (or whatever the non-Outlook equivalent is in your mail client).
  2. Make up a believable excuse for pushing the meeting back 15-30 minutes and put it in the proposal comments.
  3. Set the date to 15 minutes and 90 years in the future. The 90 years is crucial because 2100 is on the same daily structure as 2010 and shares the same digits, so it is easy for someone to overlook.

blog_meetingProductivityTip

As long as it is at least a week into the future, there is a good chance that the person will completely forget about it since it will no longer show up on their calendar to remind them.

If they do catch the date, you can always claim that you fat-fingered the date by accident.

Now go forth and use all that time that you’re going to gain back for the powers of good.

Popularity: 6% [?]

The Case of the Caffeine Overdose: A CQS Mystery

The following is a dramatic re-enactment of an actual Command-Query Separation crime. The real entities have been replaced to protect their identities and to keep yours truly from getting pelted with a barrage of nerf bullets.

The Scene of the Crime:

This crime occurred within this seemingly innocuous piece of code that was designed to help developers cope with those nasty meetings that pointy haired bosses are always making them attend.

   1: while(meeting.InProgress)
   2: {
   3:     if (developer.IsSleepy() && meeting.IsBoring)
   4:     {
   5:         developer.HideBehindOverweightCoWorker();
   6:         developer.Doodle();
   7:     }
   8: }

About 100 iterations into the while loop, the developer entity shown here threw a null reference exception and went to that garbage collector in the sky.

Although everyone initially assumed that this was yet another meeting-induced suicide, the stack trace autopsy clearly showed that the object had mysteriously been set with lethal levels of caffeine.

Clues:

Forensic debuggers made the crucial breakthrough in the case after uncovering the following suspicious code snippet while running a routine ReSharper “Find Usages” command.

   1:
   2: if (task.IsImportant)
   3: {
   4:     while (developer.IsSleepy())
   5:     {
   6:         developer.RedoCriticalTask();
   7:     }
   8: }

After intense questioning, the suspected block of code finally admitted to never having experienced an infinite loop despite having no obvious exit conditions.

This was enough for investigators to attain a warrant for the source code of the IsSleepy method, which revealed the following damning evidence.

   1: public bool IsSleepy()
   2: {
   3:     bool isSleepyResult = hoursOfSleepLastNight < 4 && todaysMeetings.Length > 2 && isCloudy == true;
   4:     if (isSleepyResult)
   5:         AddEspressoShotToIV();
   6:     return isSleepyResult;
   7: }

The poor, unsuspecting developer object was injected with a shot of espresso each time the IsSleepy check was performed.

The IsSleepy method was clearly misleading clients by returning a value and thus impersonating a query method even though it surreptitiously performed an action (a.k.a. command) behind the scenes.

This is reckless violation of the classic Command-Query Separation law established by Bertrand Meyer (not to be confused with the more recent architectural level rule introduced by Eric Evans).

The unsuspecting victim didn’t have a chance.

The Sentence:

The person responsible for this atrocity was easily apprehended with a TortoiseSVN Blame and eventually sentenced to refactor the code. The reformed code can be seen here:

   1: public bool IsSleepy
   2: {
   3:     get
   4:     {
   5:         return hoursOfSleepLastNight < 4 && todaysMeetings.Length > 2 && isCloudy == true;
   6:     }
   7: }
   1: if (task.IsImportant)
   2: {
   3:     while(developer.IsSleepy)
   4:     {
   5:         AddEspresoShotToIV();
   6:         RedoCriticalTask();
   7:     }
   8: }

The Moral of the Story:

If your method returns a value, then you should avoid performing any actions.

There are a few rare exceptions to this design rule (e.g. Stack.Pop), but this is a firmly rooted expectation on the part of API consumers and violating it will inevitably lead to frustrating Heisenbugs.

More importantly, you should never ever ever write a blog post after watching a classic episode of CSI. No good can come of it.

Popularity: 2% [?]

My Legacy to the ALT.NET Movement

I was just debating whether I should try to sweet talk my wife and bribe my boss into letting me go to the upcoming ALT.NET conference in Houston.

I went to the first one in Austin a couple of years ago and just came across this satirical post that I wrote shortly afterwards. It is based on some creative interpretations of pictures that were taken at the event.

Besides being the most fun I ever had blogging, it also represents the closest thing I have to a legacy in this once vibrant movement.

Check out the post if you missed it the first time around and make sure to reserve the weekend of April 30th – May 2nd if you like or are up for experimenting with the open spaces format.

Popularity: 1% [?]

Code Comments, What Are They Good For?

You guessed it…absolutely nothing.

Well at least according to Uncle Bob in his book, Clean Code.

Here are some quotable gems:

“Comments are, at best, a necessary evil”

“The proper use of comments is to compensate for our failure to express ourselves in code.”

“Every time you write a comment , you should grimace and feel the failure of your ability of expression”

If you feel yourself getting all worked up now, it’s probably because you just experienced several flashbacks to times when a quick executive summary could have saved you hours of puzzling your way through long, frustrating jumbles of logic that ended up having nothing to do with the task at hand.

How could anyone possibly object to a comment when it has potential to save so much time for others in the long run? Isn’t it just because they’re lazy or hate documentation with a passion and are trying to rationalize their own personal preferences and\or shortcomings?

While I can certainly imagine situations where this is the case, I agree with Bob Martin that there is an alternative approach that solves the same problem more elegantly.

Consider the following before and after examples:

Before: With Comment

   1: // determine if I am ready for coffee run
   2: if(weather.IsGray && DateTime.Now.TimeOfDay >= new TimeSpan(0,15,30,0) && thermos.IsEmpty && task.isBoring)
   3:     coder.SneakAwayToStarbucks();

After: With Extract Method Refactoring

   1: if(coder.IsReadyForCoffeeRun())
   2:     coder.SneakAwayToStarbucks();
   3: ...
   4:
   5: private bool IsReadyForCoffeeRun()
   6: {
   7:     return weather.IsGray && DateTime.Now.TimeOfDay >= new TimeSpan(0, 15, 30, 0) && thermos.IsEmpty && task.isBoring;
   8: }

The second code sample provides the same executive summary description of the code, but does it in a more concise way thus helping to eliminate unnecessary scrolling, mental processing, and eye movements while trying to understand the code at a high level.

More importantly, it reduces the chance of becoming a victim of the following scenario.

   1: //wait until coffee cool enough to drink. If it takes too long throw tantrum
   2: if (CoffeeIsTooHot())
   3: {
   4:     Wait(maximumPatienceInMinutes);
   5:     if (CoffeeIsTooHot())
   6:         throw new TantrumException();
   7: }
   8:
   9: DrinkBlackNectorOfTheGods();

If you look closely at the code, you’ll notice that the comment doesn’t really describe what’s going on.

Based on the comment alone, I would expect the application to let me drink my coffee as soon as it reaches an appropriate temperature. In reality, the code will make me wait 10 minutes (my maximum patience level in minutes) before it will even test the temperature again.

This would likely cause me to waste time in a debugging session the first time I noticed that my app was still making me wait even though the coffee temperature was well below the acceptable threshold in the database. That would make me cranky indeed.

This particular example might have just been caused by someone not putting enough effort into accurately describing a comment.

However, a more common scenario for code-comment mismatches occurs when a developer changes or refactors some commented code and then simply forgets to update the comment accordingly. It’s the same type of error that frequently occurs any time you have to keep two disparate dual entry systems in sync. It’s the reason we strive so hard to be DRY in all aspects of software development.

Of course, there is still the possibility of a mismatch when we express code intent through method, class, or variable names instead of comments, but it is less likely to go unnoticed because the code and description are now much more tightly coupled.

Even when following this approach there are definitely some times when you’ll still want to fall back on comments, such as when expressing design intent, protecting yourself legally, or providing xml comments for externally exposed public API’s (NOT internal systems).

However, the vast majority of cases can usually be expressed just as effectively in code.

So the next time you catch yourself writing a comment, it’s worth asking yourself if you can achieve the same goal more concisely through a simple refactoring (renaming, extract method, or insert variable).

Disclaimer: No matter how much I agree with this approach, I grudgingly admit that this still falls pretty firmly into the realm of subjectivity. I’ve simply had too many arguments with superb developers who prefer to see a mix of high level comments and detail code all at once rather than being forced to go to different methods to see detailed implementation. Nevertheless, I can assure you that my subjective opinion on this subject is clearly the right one…:-)

Popularity: 2% [?]

Is Faulkner More Relevant than Knuth in Today’s Development Landscape?

Once upon a time, developers fretted over making their code lean and fast.

LightInAugust

To excel in those days of scarce hardware resources, developers had to master algorithms, outsmart compilers, and perform death defying feats with pointer arithmetic.

Oh, how things have changed…

Now hard drive space is cheaper than water, memory sticks grow on trees, and you can’t buy a digital watch that doesn’t have multiple cores. By contrast, developer salaries have continued to rise steadily over the years, thus making the time a developer spends on a task the most expensive part of the software equation.

This explains why developers who would have been idolized by their peers less than a generation ago for their low level, bit-twiddling prowess are now often scoffed at for their sins of “premature optimization”.

As a result, today’s thought leaders spend considerable effort figuring out how to stem the relentless tide of software entropy, a goal that loosely falls under the umbrella of maintainability.

Knowing how to write a bubble sort or explain the difference between a depth-first and symmetrical traversals in search algorithms might earn you some geek “street cred”, but it is unlikely to improve your daily life much if you’re like most other developers. For example, it won’t help explain to a pissed off CIO why that simple modification to your department’s favorite legacy app just took a week to complete and introduced two new bugs in the process.

What developers really need to excel today is some insight into how to write code that is an order of magnitude easier to grok and modify.

This is exactly what Bob Martin (aka Uncle Bob) attempts to do in his book Clean Code (which happens to be my March book). He examines code expressiveness from a variety of angles, such as naming, composition, code length, commenting, and formatting, and applies the same rigor to reducing the amount of time it takes to understand code that was once applied to improving algorithm performance by computer science giants like Donald Knuth.

Although Uncle Bob prefers the craftsmanship analogy to describe our profession, most of the recommendations in the book suggest to me that coders should spend more time thinking like writers.

This resonates with me because I often feel more like a writer than an engineer at the end of the day given the amount of mental energy I spend picking just the right variable, method, and class name or how much effort it takes to organize code at the just the right level of abstraction so that it effectively conveys the meaning of the work being done.

It also explains why the industry has been so enamored these last few years with things like Fluent Interfaces, DSL’s, and executable specifications, which all attempt in some way to bring the world of code closer to the world of natural language.

All of this makes me wonder if the Back to Basics meme that was floating around the blogosphere over the last few years is really the most productive direction to take if we want to improve the state of our profession.

Rather than pushing Knuth’s the Art of Computer Programming, should we instead be handing out classic pieces of literature to new developers as a way to fine tune the natural language portion of their brains? Would this do more to help eliminate the ubiquitous coding monstrosities like the one colorfully illustrated in this Uncle Bob video?

I’m not saying we need to start recruiting from English instead of Computer Science departments, but it is an interesting thought.

Popularity: 2% [?]

Reducing overloading ceremony with C# 4.0 optional parameters

It could be because I’m still suffering from upgrade fatigue due to a massive migration to .NET 3.5 that we recently completed at work.

Then again, it might just be because C# 4.0 has received little fanfare compared to the LINQ and lambda magic unveiled in C# 3.0.

Whatever the reason, I didn’t get around to installing Visual Studio 2010 and experimenting with the new C# 4.0 features until just a few days ago.

Optional and Named Parameters, the first feature that I’m excited about, appears like a pretty minor feature on the surface but it has the potential to eliminate a lot of noisy “ceremony code”.

The concept is very simple and familiar to anyone who has specified a default value in a SQL Server stored procedure.

Up until now, when we’ve wanted to provide defaults for a method in C# and offer the API consumer a more concise way to call the method, we’ve had to rely on overloading.

Take the following common case code snippet as an example:

   1: public void TakeOrder(string name)
   2: {
   3:     this.TakeOrder(name, "Americano");
   4: }
   5:
   6: public void TakeOrder(string name, string drink)
   7: {
   8:     this.TakeOrder(name, drink, "grande");
   9: }
  10:
  11: public void TakeOrder(string name, string drink, string size)
  12: {
  13:     string order = String.Format("{0} wants a {1} {2}", name, size, drink);
  14:     orders.Add(order);
  15: }

Although the client code below is nice and concise, the method definitions contain a lot of duplication.

   1: StarbuxWench wenchDuJour = new StarbuxWench("Russ");
   2: wenchDuJour.TakeOrder("Brian");
   3: wenchDuJour.TakeOrder("Grif", "Mocha");
   4: wenchDuJour.TakeOrder("Kim", "Latte", "tall");
   6: wenchDuJour.PlaceOrder();

You might not notice it at first because you are used to it, but imagine if you had to provide a separate sproc definition for each optional parameter in a stored procedure.

Besides being noisy and high on “ceremony”, overloading is suboptimal because it doesn’t make the default values that are being utilized explicit, which can sometimes lead to unpleasant surprises for the consumer. I recently experienced this first hand when I wrongly assumed that the default value for comparison type for String.Compare was a case insensitive comparison.

Another limitation of overloading is that it requires a unique combination of types, which means that I couldn’t provide an overload with just name and size because they are both strings and I already have a definition with two strings (name and drink).

Now consider the C# 4.0 alternative:

   1: public void TakeOrder(string name, string drink = "Americano", string size = "grande")
   2: {
   3:     string order = String.Format("{0} wants a {1} {2}", name, size, drink);
   4:     orders.Add(order);
   5: }

Besides being much more concise and saving you the trouble of having to modify your code every time you want to expose a new parameter combination, it also solves the unique type combination limitation as well as hiding default parameteres from the client.

Here you can see that I’m skipping the second parameter by using the new named parameter syntax, which should be very familiar if you’ve ever worked with ruby.

   1: wenchDuJour.TakeOrder("Jacob", size: "grande");

Here’s a snapshot of the intellisense, which makes the defaults explicit.

optionalParams

As I mentioned before, this feature is pretty trivial when compared with lambdas or LINQ, but anything that removes cruft from my code is a welcome addition to the language.

Popularity: 1% [?]

Refining My TDD Strategy

I’ve been doing various degrees of Test Driven Development for several years and am still a strong advocate, but I’m definitely in one of those stages now where I am rethinking my approach.

The last time I found myself in this position was several years ago during my pre-mocking days when my test suite was taking an hour to run, the majority of my test failures were data-related ghosts, and the sql-laden setup and teardown sections of tests were painful to create and even more painful to maintain.

Now I find myself facing similar types of friction even though the causes may be different. Tests require too much effort to write due to mocking requirements, especially in areas of legacy code that need to be refactored to use dependency injection. Test failures are too often false positives caused by simple refactorings due to the tight coupling caused by interaction-based testing. The overall number of tests is difficult to manage from the perspective of documenting system behavior or being able to quickly discover whether a test already exists for a particular piece of functionality that is being modified.

As a result, our department has clearly stalled in its effort to incorporate TDD into our everyday development process and now I’m trying to figure out how to rectify that.

My current thinking is that the best way to make TDD a viable and sustainable option is to selectively use it only when it provides a net gain in value.

I know that this is somewhat of a blasphemous thought because TDD\BDD is more about design than automated testing, which means that it is supposed to be baked into the development process and therefore not optional (or so I thought).

Although I have definitely experienced moments where TDD has improved both the usability and elegance of my design by making me start from the perspective of the API consumer and incrementally add features in the simplest possible way that works, I have also seen plenty of cases where it provides little or no benefit in terms of design. For example, I often seem to write code that must fit into an existing design, follows a well known pattern, or only slightly modifies an existing method.

The same holds true for refactoring. While there have definitely been times where TDD has improved the quality of my code by providing a safety net that allows me to catch more bugs and refactor more freely, there have also been times when I’ve gained little value in this respect due to the simplicity of the code. In fact, lately I’ve noticed that there have actually been times when I have been less likely to refactor a section of code due to TDD because it had a large number of interaction-based tests around it that would all have to be changed to accommodate the implementation changes.

Finally, let us not forget that any and all code is intrinsically a liability. Since test code tends to grow at a much faster rate than normal code, the long term maintenance cost of your test suite becomes even more of an important factor to consider.

Ultimately, it seems as though some criteria for making a simple cost-benefit analysis are in order to help decide when it make sense to use TDD.

So far I’ve come up with the following:

When to write a test:

  1. The design is unclear.
  2. You’re implementing an important or complicated piece of business logic.
  3. You’re about to implement a hack or sub-optimal solution because you’re afraid of breaking something in an existing piece of messy, complicated code.

It also occurred to me that just because you write a test doesn’t mean that you have to commit it. There are several design artifacts (whiteboard, napkins, etc) that are extremely helpful despite being disposable. Occasionally writing throw-away tests would certainly allow me to gain the design benefit without incurring the cost of maintaining a test that has little long term value.

With that in mind, the following scenarios seem like reasonable examples of when it makes sense to take the extra step of committing a test:

When to commit a test:

  1. The code is important to the business and heads will roll if someone unintentionally breaks it.
  2. The code is complicated and the next poor schmuck who touches it to make an enhancement has a good chance of unintentionally breaking it.

Other ways to improve the cost-benefit ratio of testing:

  1. Use SRS to isolate important business logic – By favoring small classes and composition and focusing your testing efforts at this level rather than a higher level where they all meet, you will drastically reduce the setup cost of mocking out all the dependencies that probably aren’t relevant to your test anyway.
  2. Favor state-based testing over interaction-based testing – I’ve run into a  few scenarios where interaction-based testing has been a blessing, but it seems like more often than not it just leads to inappropriate coupling with the implementation details that results in brittle test code. Use it sparingly.
  3. Make test suite spring cleaning a post release ritual – Nothing succumbs to entropy like code. Test code is even more critical to keep clear, concise, and organized, because this has the potential to represent the specifications of how your system works. If something is no longer important delete it. If the test name isn’t clear or the folder structure isn’t optimal for finding features, then invest the effort to change it. Otherwise, the broken window theory will take affect faster than it takes Visual Studio to load.

Am I way off base here? Does anyone else have additional criteria for deciding when it makes sense to remove yourself from TDD mode?

Popularity: 2% [?]

Book Review – Lean Software Development: An Agile Toolkit

FebBookReview_LeanI just finished my February book from my 2010 tech book reading list, so I thought I would share some thoughts on Lean Software Development: An Agile Toolkit by Mary and Tom Poppendieck before moving on to my March book, Clean Code by (Uncle) Bob Martin.

Rating - star_sm star_sm 1/2  (out of 5)

Prerequisites – This book doesn’t assume any prior knowledge, but it helps if you’re familiar with some basic Agile concepts. If you’re like me and prefer to have some mental hooks in place before starting a non-fiction book, then also take a few minutes to read the wiki summary page first.

The Good

  1. Easily Consumable – Unlike the vast majority of technical books, this one is well structured, concise, and well written. The authors package up the information in 7 easy principles and 22 tools which neatly correspond to chapters and subsections. Weighing in at a slim 180 pages, many of which contain easy-to-read project anecdotes, business novelettes, and case studies, the book can easily be read in the span of a week.
  2. Broadly Applicable – This book is all about concepts and principals that can can be applied incrementally to almost any scenario. In other words, you can still get value from it even if you don’t have the desire or the freedom to change your current development methodology.

The Bad

  1. Management Genre – It has been a while since I’ve read Dante, but I’m pretty sure that at least one of the inner circles of hell is dedicated to making developers recursively read management drivel until they beg for mercy. While this book is very developer-centric and arguably has potential to greatly improve the quality of life for the average developer, it is still firmly grounded in the business-management genre and thus may inevitably irritate developers in a number of subtle ways.
  2. Too Vague at Times – While the focus on broadly applicable principles has its strengths, it could also be frustrating for someone who is looking for a more concrete and instructional guide to help them overhaul their Software Development Lifecycle. This book is probably best used in conjunction with other more detailed and prescriptive resources.
  3. Potentially Out-Dated – Despite being written in 2003, this book remains remarkably relevant. However, it is not at the forefront of Lean-inspired thinking these days and does not take into account the lessons learned from the front-line agilistas over the last 7 years. Based on some preliminary research, it appears that the current Lean-inspired trend is focused around Kanban, which you can find out more about here and here.

Conclusion – As long as none of my negative bullet points are deal breakers for you, then I would go ahead and recommend reading the book. If your bookshelf already over-floweth or you can’t justify spending another penny on tech books, then this might be a good one to “thoroughly browse” cover to cover at your local bookstore over a series of lunch breaks.

Popularity: 1% [?]