Measure Twice, Optimize Once; Wash, Rinse, Repeat.
The title to the post was taken from an entry Larry Osterman http://blogs.msdn.com/LarryOsterman/archive/2004/05/03/125198.aspx. In this blog, Larry correctly points out that we should truly understand where and if we have a performance issue and if so...exactly where is the performance slow-down occurring. It's true. When I first started off in the software business, one of my first technical mentors taught me to constantly test for performance as I develop and that I should make sure I understand where any performance slow-down is before fixing it. True or false, have you ever fixed a performance problem only to find out the problem was actually somewhere else? If you haven't, you probably aren't being honest with yourself. It's a learning experience that every cowboy programmer goes though.
To add a tangent thought, as developers and architects we also often create unnecesary optimizations. How many times have you been in a code review or seen something where it was suggested to optimize because you could squeeze out a millisecond or two of additional performance without asking the question “Is it fast enough“. It is a dangerous game we play. In one sense we always want to have screaming code but in another instance the business requirements don't necessarily care as long as it is “fast enough“. So why do we bother?
For example, if I always wanted the fastest data-access, I would have my DataAccess Tier always return a SqlDataReader/OracleDataReader, etc; however, I know that if I do this I am:
- Forever tying my Business Logic Layer to understanding the different exceptions that might be thrown by these different readers (yes they are layer specific...a pet peeve of mine but another subject altogether).
- I am also requiring my clients to correctly close the connections.
Instead, I like to wrap my DAL in such a way as that it always returns disconnected data and returns exceptions defined within the DAL. This let's me control exception types and properly manage connections and connectionstrings. Does this mean that I never return a reader? No, we always need to balance performance with “Tier Purity”; however, my default DAL implementation is still very performant and fast enough for the vast majority of client tiers. Now if I was handling millions of credit card transactions in a short time period...well that's different. Or if my result set was sufficiently large and a client applications needs were such that disconnected data wasn't performing, I would then look at streaming the data. Here performance far outweighs Tier Purity....My point is, most business applications care about being fast enough and business sponsors don't give a da&$ about squeezing out the last bit of performance. We as architects and developers must understand the difference.
-Mathew Nolton