Best Practices, Budgets and Deadlines – Have Your Cake and Eat it too
What are good programming best practices and are they worth following in a project?
The subject of best practices has already been extensively described in the articles on SOLID, KISS and automatic testing. However, the question remains as to whether, and to what extent, the application of these procedures affects the timing and complexity of the order.
The answer to the first question is obvious - the time to implementation the project will be longer.
The first issue that will always come up with the vast majority of customers is the time to complete the order and, consequently, its cost. In many cases, questions the client’s side start with "And it can’t be faster?" or "Why so much - isn’t it just a bit of functionality?! " And at this point, one of the most difficult stages of the software development process begins - explaining to the client the complexity of the problem that superficially seems trivial. Eg. adding a button for sorting through an existing list of products. And from the client’s perspective, well, there is a list and it works (although sometimes not great), and they just want to add one new functionality without touching anything else..
An overwhelming majority of customers aren’t prepared to take on additional costs, and even if they have the extra budget, they’re not happy with the suggestion of unplanned investments. From the customer's point of view, this is completely understandable. However, an experienced programmer should consider all possible scenarios and try to share them with the client.
In this article, I’d like to offer my perspective on the situation, based not only on my own experience, but also on the well-known book Clean Code by Robert Martin, a.k.a. Uncle Bob.
I’ll present here the thoughts of a six-year developer with experience in a variety of projects (e.g. legacy code, where developers discover the revelation of coding based on very good standards.
Let's start with the conventional answers to two questions:
- do you always have to apply best practices?
- and will ‘overdoing it' with these practices be a step back?
Both of these questions are a definite 'yes'.
I’d like to present the basic tenet doctors follow: 'First, do no harm'. It’s clear that the weight of our work doesn’t compare with people saving lives, but the adage itself, in my opinion, perfectly reflects the essence of things.
So how do you do it, not hurt it, not overdo it, and at the same time retain the quality of the code?
We’re going to try to answer these questions.
For starters - never give quotes based solely on experience, or off the top of you head. “I've done it a thousand times, under a variety of conditions, this certainly won’t exceed 10 hours,” are famous last words, which the client has gotten used to, so any changes in the budget will be hard to accept.
Each project deservers it’s own understanding.
Therefore, you should always first ask the customer for a few hours to audit the existing code, to know exactly what you are dealing with. At this moment, nearly every customer will respect and appreciate your professional approach.
What should you pay attention to during an audit?
First of all, it makes sense to "read" the code, get to know it in the state it’s in and determine if it’s suitable for development or if it would be better to rework this particular functionality.
Aspects that should be verified and scored are:
- code readability (for KISS and the first two SOLID principles)
- way of retrieving data from the database (whether ORM was used or everything is based on pure SQL queries)
- whether the project is based on a version control system (GIT, SVN).
The purpose of the audit is to become aware of the complexity of the task and thus to provide the client with a reliable valuation. Of course, always remember to add a standard margin of time to cover any problems that arise.
As I mentioned, regardless of what code we find, we should stick to best practices. Adding some piece of logic, whether it’s ready functionality or creating a comprehensive proprietary solution, there are several important points to keep in mind:
- my code is my business card (or my employer’s)
- we have to consider that conscientious customers will seek other companies to verify the quality of our solution.
The second point is that after us the code may be modified by other companies, and if they get something completely wrong, it’ll certainly be a stain on both our reputation and our client's.
The code must be easy to expand and modify - it’s very rare that the client will get exactly what they want, and regardless, can change their vision - and we, of course, having good intentions, taking care of their portfolio, had written just a few dozen lines of code to get things up and running. Any rewritten fragment of code would require a change in the overall logic.
In the case of code where we have applied the rules: Single Responsibility and Open / Closed the task is relatively simple. On the other hand, when we have given ourselves a logic block without any possibility for expansion, we are probably looking at starting again from square one, or an extensive amount of refactoring. In the end, will the customer get their product any faster? Rather not ... a programmer's job is perpetual development.
Therefore, in my opinion, the possibility of writing code that does not follow best practices, exists. Whenever I hear arguments claiming that its not worth upholding high standards, because the customer wants something quick and cheap, it reminds me of dropping a car off at the mechanic and getting it back held together with tape and chewing gum. Does it work? It works, only for a while, but it works. The repercussions of this approach will surface quickly, but the request was met - the order was fulfilled in a very short time and at a low cost. Do you really think brands are built on meeting deadlines, or rather meeting standards of quality?
This doesn’t mean, however, that you can just disregard a client’s financial criteria and focus solely on code quality. As I mentioned before, the key is to strike a balance and try not to "overdo it”. Imagine a project where the client wants the previously mentioned functionality - adding a button for sorting through an existing list of products. If you want to follow best practices, you should start by checking whether the current code has gone through testing - if it’s not there, it’s necessary to add it. And to implement unit tests, you’ll probably need to refactor, and even rewrite, the existing code.
The real question is whether this is even necessary? No.
Of course you could say that testing the system will significantly reduce the risk of unwanted activities, which in turn means that you do not have to push for testing when changing the existing code if the client does not agree to the tests - but in my opinion, never introduce a payment system integration which has not been thoroughly tested. Everything should be based on common sense and the individual needs assessment of a given functionality.
What about legacy code?
Exactly - how do you apply best programming practices in code which is completely obsolete, but for a number of reasons (not just budgetary constraints) needs to be maintained? In this situation, the aforementioned rule should be applied - "First, do no harm."
If you touch just a fragment of logic that is inconsistent with best practice standards - for example, someone has pasted the HTML code in the controller, of course, you’re not going to now spend hours cleaning up the controller, adding views and downloading transfer data to models. Legacy code should not be repaired without a clear customer request, because this is the kind of work that will most likely not improve the controller. If the contract is simply to maintain a website, then we minimize any interaction that we could have with legacy code.
It is important to still maintain standards in regards to legacy code. If you add a new functionality block or logic to this mess of code, then this new functionality should still be written with the highest standards possible. In addition to the reasons for this mentioned above, I’d like to add one more. The first developer's reaction to an order for adding to, or changing, a significant piece of logic in any legacy code should be: how many places will I have to change the code, and will the code that I change affect anything else? This comes up in 90% of projects an always ends with something breaking down.
What's the solution?
In order to fully understand the essence of best practices in programming, you must first realize that they’re not a limitation, they’re a way to facilitate your standard of work in order to gain and retain the trust of your clients.