For the last few days I’ve been thinking about some things that were said in a system design conversation that I had. To set the tone, we were talking about a greenfield web application that was to be written using the Microsoft development stack.
The conversation headed down a rabbit trail that covered beliefs in a number of different areas including the age old Stored Proc vs. Parameterized SQL. That’s one argument that I’m sure all of us have seen batted around enough to be able to speak clearly, professionally and with authority on. The discussion point that caught me off guard was where object inheritance was linked to performance degradation. I’d never heard this argument made before. I was confused. I was flabbergast. I was speechless….well….almost. Above all, I was left curious. Does inheritance cause performance problems in .NET code?
Like any programmer worth the donut they eat in the coffee room every morning, I Googled the question. Of all the results that were returned only two were remotely interesting. First there is a page on MSDN about Asp.NET Configuration File Hierarchy and Inheritance, which, while interesting and addressing performance, isn’t related to object inheritance. The second was a post by David Boschmans which discusses Code Reviews with a focus on Performance. In that post he discusses the use of inheritance with .NET attributes, which, again, is quite interesting, but not what I was looking for.
So Google draws a blank for me. I own Visual Studio, I’m currently between contracts and I haven’t yet purchased Halo 3 so I figured what the heck, let’s do a little experiment. First I wrote a little bit of code that had an Animal class and a Dog class which inherited from Animal. All that I had was a property of Animal.Legs which was not overridden in the Dog class. The timed code tested looping over 50 million instances each of the Animal and Dog classes and performing the following line of code:
foreach(Animal animal in animals)
foreach(Dog dog in dogs)
What I found was that over the span of running each of those loops for 50 million items and averaging each one over 10 different runs, the Animal typed loop took approximately 1.054 seconds and the Dog typed loop took approximately 1.037 seconds. The difference between the two and then apportioned to each of the 50 million items is hardly worth the math (0.00000000034 seconds per item) to consider it a problem for the average LoB application that we see written.
So I figure that there may be something to a deeper nesting of inheritance so I added a Shepherd type (inherits from Dog) and a GermanShepherd type (which inherits from Shepherd surprisingly enough). None of these classes override the Legs property on Animal. I performed the same test again, this time comparing Animals to GermanShepherds. The average run time for the Animal loop was 1.038 seconds and the average for the GermanShepherd loop was 1.018 seconds. The difference (0.0000000004056 seconds per item) was once again indiscernible for the average LoB application.
Finally I wanted to try something with some different types in the loop. I compared the standard loop for Animals against the following loop against a list of GermanShepherd objects.
foreach(Animal animal in germanShepherds)
Of all the tests this is the one that I expected could possibly run with a noticeable difference. Like the others, 50 million items and 10 sets later the Animal loop averaged 1.028 seconds and the Animal against German Shepherd loop averaged 1.018 seconds. Once again the difference per item (0.0000000001872 seconds) is negligible.
So out of all that I’ve proven that the points I made in the discussion about inheritance performance degradation were well founded. Inheritance does not appear to have any significant effect on the performance of simple code. Now, these are trivial examples and they may have some flaws, but the discussion I was having was centered around the idea of inheritance and simple properties causing problems.
As I’ve noticed with people from certain technical backgrounds, performance is made a paramount and primary concern. While I agree that performance can be a concern, and that basic performance measures are needed, I can’t buy into a though process that makes performance an overriding concern until it has been proven to be an overriding problem.
Performance can reach the forefront of my thought process in two scenarios. First, performance is a stated requirement of the application acceptance. In that case I’d still defer the performance question until it has been proven that it can’t be met. The second situation is where performance is obviously not acceptable. User style testing by a developer that is only just bearable is probably a sign that performance concerns should start rising up the list of risks. While in the conversation that triggered this whole thought process we hashed out the system usage numbers and the rough estimates were only about 3000 hits per day. Finding that out in the conversation told me that this was never going to be an issue regardless of what any research found.
Please don’t take these test results as gospel. They were hacked together in a short period of time and didn’t test a very good spread of situations or concerns. For me it was more about satisfying curiosity in the simplest way possible.