Good code is cheap code
For a long time I have maintained that good code is cheap code.
When I meet fellow developers and say this to them, the immediate reaction is one of shock, followed closely by a weak laugh as they try to pass it off as some kind of joke. Then slight fear as they look at me a little closer and realise I’m serious.
After the initial shock has worn off, they retort with an argument along the lines of “good code is not cheap, good code is the careful application of best-practice design patterns and methodologies established through decades of CS research and experience”.
I then go on to explain that what this definition fails to account for (and what many developers fail to understand) is that knowing the patterns, frameworks and technology is one thing, but knowing when and when not to apply them is much more valuable. Without knowing how a certain approach will help with the development of the system, there is great potential for the pattern to become a hindrance rather than a benefit to development.
I also explain that when I say “cheap code”, I mean code that requires few man hours to write, I don’t mean code written by inexperienced developers who will change minimum wage and plug away for 6 months living off nothing but baked beans and the occasional spoonful of dirt.
But… Patterns are good… mkay?
Yes, but why are they good? What benefits do they provide?
- Easier to maintain
- More robust product
- Easier to understand
- Easier to accommodate future enhancements
- Better traceability
And you will find that all this boils down to one thing: it’s quicker to do stuff in the long-run. It could be porting a system elsewhere, or adding a new feature, whatever it is, there will be a tangible time benefit to having implemented the pattern upfront.
So, we are in agreement then?
Kind of, but let me give you a brief and then let’s look at a couple of ways to implement it.
Create a mailer form in PHP that takes the value of a couple of fields and then emails them to a single individual. In addition to this, the form contents should be stored in a MySQL database.
Now, how do we implement this the best way? By following the traditional definition of implementing best practice design patterns, we should be thinking about:
- N-Tier design, including database abstraction layers
- Object-relational mappers
- Possible frameworks
- XML configuration and associated schema
I would say this is completely crazy, as the client’s request can be implemented in under 10 lines of code and within an hour (including testing). And when it comes to the goals that all of these patterns were trying to achieve (those of readability, portability, stability, etc.) implementing them would actually thwart these goals, leading to complex code that is difficult to understand and modify.
Now, say the client were to come along and request an alteration to the system, something like the addition of an administration interface. Here, you would get a win from having implemented several of the desirable bits; however you did actually pay a price for that when you first created the system. I would claim that the time it would take to refactor the simple code and create a simple business layer would still be less than what was required to implement the overly engineered initial implementation.
Let’s say, however, that the client requested an additional field be added to the form. Here the N-Tiered design is a real pain, as you have to go through each layer and add the required CRUD code.
One of the big reasons I find scrum attractive is that it forces quick work; it forces you to get stuff implemented and released at the end of each sprint. It doesn’t let you get ahead of yourself; it doesn’t give you the luxury of implementing things because that’s the “Right Way”.
Instead, you refactor when you are required to. Sure, this may mean you run the risk that the implementation of some features would take longer than they may have otherwise, however given the constantly shifting sands of product development it can be nearly impossible to know exactly how a product may be changed in the future. All the time you spent implementing all these attractive patterns could be a complete waste.
Some people have pointed out that this approach does not really allow for much reusability of newly developed components in other systems. I respond to this by stating that planning for reusability without knowing if/how/where something will be reused is almost as bad as implementing features that were never requested or required in the first place. If you have a clear vision for where something may be reused, then that is different as what you really have is an internal business requirement which should guide the development appropriately.
And now for my final thoughts…
- Know your design patterns and the benefits of each of them (I will always say the difference between good coders and great coders is that the great ones know their patterns);
- Plan your code to be cheap:
- Use patterns where they are going to be beneficial and will save you time;
- Ignore the patterns that will not (e.g. when was the last time you ported a system to a different DB?);
- Use frameworks where appropriate to speed up development;
- Refactor when required, don’t get ahead of yourself;
I think you will find by following this as a guiding principal, you will have cleaner code implemented in a shorter timeframe that will be easier to debug and less cumbersome to modify.