Check out my interview on .NET Rocks! – TDD on .NET and Java with Paul Mooney
Providing performance-optimised frameworks is both a practical and theoretical compulsion. Thus far, my posts have covered my own bespoke frameworks designed to optimise performance or enhance security. I’ve outlined those frameworks’ design, and provided tutorials describing several implementation examples.
It occurred to me that providing such frameworks is not just about the practical – designing and distributing code libraries – but also about the theoretical – how to go about designing solutions from the ground up, with performance optimisation in mind.
With that in mind, this post will mark the first in a series of posts aimed at offering step-by-step tutorials outlining the fundamentals of Object Oriented and Test Driven design in C# and Java.
“But what do Object Oriented and Test Driven Design have in common with performance optimisation? Surely components implemented in a functional, or other capacity will yield similar results in terms of performance?”
Well, that’s a subjective opinion, regardless of which is beside the point. Let’s start with TDD. In essence, when designing software, always subscribe to the principal that less is more, and strive to deliver solutions of minimal size. You enjoy the following when applying this methodology:
- Your code is more streamlined, and easier to navigate
- Less code, less components, less working parts, less friction, potentially less bugs
- Less working parts mean less interactions, and potentially faster throughput of data
Friction in software systems occurs when components interact with one another. The more components you have, the more friction occurs, and the greater the likelihood that friction will result in bugs, or performance-related issues.
This is where Test Driven Design comes in. Essentially, you start with a test.
“OK, but what exactly is a test?!?”
Let me first offer a disclaimer: I won’t quote scripture on this blog, nor offer a copy-and-paste explanation of technical terms. Instead, I’ll attempt to offer explanations and opinions in as practical a manner as possible. In other words, plain English:
A TEST IS A SOFTWARE FUNCTION THAT PROVES THE COMPONENT YOU’RE BUILDING DOES WHAT IT’S SUPPOSED TO DO.
That’s it. I can expand on this to a great degree, but in essence, that’s all you need to know.
“Great. But how do tests help?”
Tests focus on one thing only – ensuring that the tested component achieves its purpose, and nothing more. In other words, when our component is finished, it should consist of exactly the amount of code necessary to fulfil its purpose, and no more.
“That makes sense. What about Object Oriented Design? I don’t see how that helps. Will systems designed in an object-oriented manner run more efficiently than others?”
No, not necessarily. However, object-oriented systems can potentially offer a great degree of flexibility and reusability. Let’s assume that we have a working system. Step back and consider that system in terms of its core components.
In an object-oriented design, the system will consist of a series of objects, interacting with one and other in a loosely-coupled fashion, so that each object is not (or at least should not be) dependent on the other. Theoretically, we achieve two things from this:
- We can identify and extract application logic replacing it with new objects, should requirements change
- Objects can be reused across the application, where logic overlaps
These are generally harder to achieve in unstructured systems. Using a combination of Object Oriented and Test Driven Design, we can achieve a design that:
- is flexible
- lends itself well to change
- is protected by working tests
- does not contain superfluous code
- adheres to design patterns
Let’s explore some of these concepts that haven’t been covered so far:
Think of your tests like a contract. They define how your components behave. Significant changes to a component should cause associated tests to fail, thus protecting your application from breaking changes.
There are numerous articles online that argue the merits, or lack thereof, of design patterns. Some argue that all code should be structured based on design pattern, others that they add unnecessary complexity.
My own opinion is that over time, as software evolved, the same design problems occurred across systems as they were developed. Solutions to those problems eventually formed, until the most optimal solutions matured as established design patterns.
Every software problem you will ever face has been solved before. A certain pattern, or combination of patterns exists that offer a solution to your problem.
Let’s explore these concepts further by applying them to a practical example in next week’s follow-up post.
Connect with me:
I’ve created the state printer project to easier create and maintain tests. Maybe you want to give it a spin https://github.com/kbilsted/StatePrinter
Thanks, I’ll take a look at that.
The idea is to make asserts on object dumps rather than writing many assets. I better improve the documentation to better explain that. .