Software engineering best practices
As we all continue our journey into software engineering we encounter issues and obstacles. We always find a way to work around them, solve the issue and move on to the next task. If we stop for a second and reflect on them, we will develop a much deeper understanding of the issues we are solving, and we would learn a ton. Here is a short list of tips based on my past experience and research that I would like to share with you.
1. It is always better to merge than to split.
By spending more time during the design phase we can split the code into smaller chunks. A requirement should be broken down into smaller requests, so that each request can be handled by a separate function/service. Once all these functions are created, they can easily be combined to satisfy the original requirement.
Notice that the opposite is much harder. If we put multiple functions into the same code, it is harder to split them apart. I have seen many duplication of code where one code was doing A+B+C, and then was duplicated to just do A+C. Maintenance can quickly become a nightmare, you update A+B+C code, but you keep A+C the same as it was out of scope. Now we have two versions of A, and C! (I know this sounds silly, but I have seen it in many places.)
That's why the Agile methodology has become so popular. You create three stories, and you sprint to create A, B, and C. You can then combine them in any way you want.
2. Be Explicit and document your code.
Where possible, write code that is short, straightforward and easy to understand. Often that will come down to single functions that are easy to test and easy to document. Even libraries can perform just a single function and then be combined for more powerful functionality.
Depending on the programming language used, you might need to add a line of comments for every line of code. This might sound excessive, but next time you have to debug someone else's code, you would really appreciate it. Most companies pay for gurus and expensive third party consultants to do the initial project and then will pass the code to their own (not so experienced) internal team. Having comments in the code will go a long way in helping the "new kids" to support the system.
These comments should describe "why" versus the usual "what" for a given process or code. Why is this code there, and if it is too complicated what is it doing.
3. Divide and Conquer.
I already mentioned breaking down the problem/requirement into smaller sub-problems. But then some of the resulting solutions might have dependencies on other solutions, if we combine a few of these solutions, we might still end up with monster code that is not easy to maintain. To conquer this monster, we need to keep them decoupled. Fortunately there are now easy solutions. Using JSON instead of XML can help with backwards compatibility, and using Queues to deliver the message (JSON) is a great way to decouple code. This is what Amazon's SQS documentation says about queues:
"In modern cloud architecture, applications are decoupled into smaller, independent building blocks that are easier to develop, deploy and maintain. Message queues can significantly simplify coding of decoupled applications, while improving performance, reliability and scalability."
4. Build metrics.
Running a code without metrics is like flying blind. Building metrics and logs will allow you to monitor and alert. It is always better to be alerted that you are about to run out of gas, than to be stranded. Building these metrics must be part of the initial design. Creating logs and designing their content must be part of the initial design. You won't believe how many times I have seen companies with tons of logs that are totally useless as they were just an afterthought. You can Elasticsearch your logs all you want, but if the logs do not have the data you need or cannot properly link their content to your workflow, you cannot get a good insight into what is going on in your system.
5. Avoid Scope Creep.
Scope creep is when new requirements are added after the project has started. Often these changes are not properly reviewed. The project team is expected to deliver them with the same resources and in the same time as the original scope.
Evaluate features based on their benefit and not the effort needed to implement them. Sometimes focusing on the low-hanging fruit first as a strategy can lead to an accumulation of more difficult tasks.
Identify features that can be layered in later. Can this new requirement be part of phase two? In my opinion this is a fundamentally important step in Agile development, get this right and you will have a great chance of being successful.
6. Avoid Patchwork, solve the root cause.
In an older organization, when you look at their existing code, you see nothing but patchworks and multiple versions of the same code running to quickly fix issues. A code that services multiple channels was split into two versions as one channel had issues. So now channel A, and B use code version 1, but channel C uses code version 2. This easily happens since channel A, and B were happy and were not whiling to spend any money on an upgrade. Decoupling functions, service providers and channels, plus building backwards compatible code/interface can help. (ex. Queues and JSON)
Conclusion
The list of software engineering best practices is very long. I have only mentioned a few points that I have seen over and over again. I wrote this article for myself as a reminder. I hope this helps you as well. I always say: