A long time ago, a mentor of mine passed on some good advise for developers that has stuck well with me: “Make it work. Make it right. Make it fast.” While this simple mantra is likely influenced by Donald Knuth’s famous and misquoted statement that “premature optimization is the root of all evil”, it’s more about how a developer should approach development altogether.
Breaking it down…
What I’ve always loved about this simple advice is that if a developer takes the steps out of order, such as putting emphasis on design or performance, there’s a very strong possibility that the code will never work.
Make it work…
Developers should take the most pragmatic solution possible to get the solution to work. In some cases this should be considered prototype code that should be thrown away before going into production. Sadly, I’m sure that 80% of all production code is prototype code with unrealized design.
Make it right…
Now that you know you know how to get the code to work, take some time to get into a shape that you can live with. Interesting enough, emphasis should not be placed on designing for performance at this point. If you can’t get to this stage, it should be considered technical debt to be resolved later.
Make it fast….
At this point you should have working code that looks clean and elegant, but how does it stack up when it’s integrated with production components or put under load? If you had spent any time in the last two steps optimizing the code to handle load of a thousand users but it’s only called once in the application – you may have wasted your time and optimized prematurely. To truly know, code should be examined under a profiler to determine if the code meets the performance goals of the application. This is all a part of embedding a “culture of Performance” into your organization.
Aligned with Test Driven Development
It’s interesting that this concept overlaps with Test Driven Development’s mantra “Red, Green, Refactor” quite well. Rather than developing prototype code as a console app, I write tests to prove that it works. When it’s time to clean up the code and make it right, I’m refactoring both the tests and the code in small increments – after each change, I can verify that it still works.
Later, if we identify performance issues with the code, I can use the tests as production assets to help me understand what the code needs to do. This provides guidance when ripping out chunks of poorly performing code.
By following either the “red / green / refactor” or “make it work / right / fast" mantras mean that I don’t incorporate best practices or obvious implementation when writing the code? Hardly. I’ll write what I think needs to be written, but it’s important not to get carried away.
Write tests. Test often.