There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies.
– C.A.R. Hoare, The 1980 ACM Turing Award Lecture
I often get criticized for my mantra toward the development approach. Your code may be elegant, but mine f***ing works. In response, I hear statements ranging anywhere from “You don’t understand best practices” to “You hate testing!” In an effort to avoid repeating myself on a regular basis, I decided to write down my point of view on the topic. Adhere to it or not — your choice.
First of all, let me make a blanket statement here: the sentence “the project may be late — but the code [looks better/is easier to maintain/is cleaner]” (pick any that apply) is inherently flawed. If the project is late, it’s not done. Period. There is no way to justify being late by using code quality/elegance as an argument. If the client needs a Christmas promotion, and you deliver the best product in the history of promotions — on December 29th — it’s worthless.
Now, let’s address the “best practices” argument, which implies that in order to produce more maintainable code one needs to take more time. I will keep using the phrase “best practices” in quotes because standards vary across the board (despite some common misconceptions), outside of very common Best Practices 101 that every programmer should have imprinted in their brain before the first “Hello World” is written. With that said, “best practices,” however you define it, should be a natural coding standard for any decent developer. If you need to bake more time into the project time-line to make your code comply – you are, at best, new to the programming scene. To give a trivialized example, any seasoned programmer should instinctively know not to call the variables
$c, etc., and should properly indent code lines. Granted, there are more advanced “best practice” standards that one might mention, but the point stands – “best practices” is not a good excuse for exceeding your development timeline. And taking it a step further, a veteran programmer should know when and, most importantly, how to cut corners, if needed, to meet the deadline. Which brings me to my next point: over-engineering.
Like any experienced engineer, I understand the desire to build the best, most flexible and robust system for every project. I do. But I also understand the common business constraints of every project: time and money. Most projects have a definite deadline and/or a specific budget that must be met and, often times, building something grand is just not feasible within either them. This is where the developer must make a conscious decision to limit creativity to meet the goals. There is no excuse for spending a week to setup a “proper” caching layer for database queries on a 20-row table, that is only used from the administrative panel by three publishers. Understand the use cases. As cool as it may be to build a flexible and expendable XHR framework to support variable simultaneous requests; you don’t need to invest in it if the only feature that will be using it is an update to a visitors counter on one page. Understand the scope. I cannot stress it enough: a good engineer is not the one who knows how to build the most advanced system, but the one who knows when not to build that system.
In the world of software development, time-to-market is the driving force of the business. In the world of Internet application development, it’s even more apparent because of the dynamics of the web. When time is of the essence, the simplest solution is not often the best solution; it is always the best solution. And this brings us to our final point of controversy: technical debt.
I often hear the argument that cutting corners anywhere in the development process will accrue irreconcilable technical debt in the long-term, and the cost of that debt should be heavily factored in when making any decision in the process. In reality, this argument supports my point of view. This is exactly the reason the ability to assess when and how to cut corners is crucial when working on deadline-driven projects. There are different types of “technical debt”, and the quickest solution, given some thought behind it, will not necessary add to your technical debt. Similarly, over-engineering will not make you debt-free. The ability to make those decisions, often mid-project, is what separates veterans from rookies.
Additionally, often times people who speak to the dangers of technical debts do not take the business implications into account. Technical debt should be weighted against the actual ROI, because in many cases it is more cost effective to launch early. This way, though you may be accruing technical debt, you are also accruing revenue immediately, and you can reconcile the debt over time. This may be preferable to delaying your time to market so that you end up (arguably) debt-free in tech, but losing market opportunities and/or an immediate revenue opportunity which may be far larger over time than the cost of technical debt itself.
As software developers, we often think our job is to develop software, but, really, that is just the means to an end, and the end is to empower business to reach their goals. Your code may be elegant, but if it doesn’t meet the objectives (be they time or business) it doesn’t f***ing work.