Software engineers like acronyms. It makes it easy to remember and refer to certain ideas. You’ve likely heard the acronym YAGNI, which stands for “You Ain’t Gonna Need It.” The premise behind this is that as software engineers, we have a tendency to overengineer things. We often add features that we think we’ll need and then they never end up getting used. Applying YAGNI means basically means don’t add any feature until you are 100% sure that you need it. No premature optimization.
Adding extra unneeded features is problematic for several reasons. First of all it takes longer to write, because we are simply writing more code. Because there is more code, our code is more complicated and harder to understand and reason about. Often these features add in a bunch of special cases and conditional logic. This can cause our code to run slower. It can also make us more like to introduce bugs. Each additional line of code also increases our testing and verification burden.
YAGNI is a pretty well-known and fairly respected concept, but I read 2 articles recently that made me question how widely one should apply the concept.
PAGNI is the idea that you “Probably Are Gonna Need It”. It is not exactly anti-YAGNI, but the idea is that while avoiding premature optimization is a good idea in general, there are some things that you just always end up needing anyway. It also acknowledges that some things are just harder to add after that fact. So PAGNI holds that things that you are highly likely to need and which are easier to implement now rather than later, should just be implemented from the beginning.
I took a DSH Workshop at GDevcon. Fab led an exercise where we talked about some of the things that you always need in an application or that you always end up adding, regardless of whether the customer requests them or not. We also do this exercise in our DQMH workshops. Fab put together the original content for those workshops so that is not too surprising.
Here is a common list:
- Versioning – You always want to version your programs and display it to your users. The makes it easy to reproduce bugs. It also prevents you from trying to fix a bug that may already be resolved in a newer version. You should also consider versioning any file formats or APIs as well. You may never need it, but if you do, it is very hard to add after the fact and adding it is generally trivial.
- Logging – This is always useful for troubleshooting. It’s almost always worth adding timestamps to these too. Again hard to do after the fact.
- Metadata for datafiles – If you are collecting data in tdms files, it is very easy to add extra metadata. I wrote a free toolkit to make it dead simple. This is something that is very hard to add after the fact.
- Configuration – You always need to take some configuration input from users. So incorporating a configuration editor screen from the beginning is probably a good idea.
- Auto-generating config files with default values – If you have ever gotten a call where a customer had accidentally deleted a necessary config file or introduced some sort of typo or invalid entry, you’ll see the value in this. The solution is to have the code simply recreate the config file with sensible default values if it can’t find it. So if the file gets corrupted, you just tell the customer to rename it. The next time they run the program, it won’t find the file so it will generate a file with default values. They can then compare the two files and see where they went wrong.
- Constants in config files – Almost everywhere I drop a constant, I almost always end up moving it into a configuration file. It saves me from having to rebuild the application later when the customer changes their mind, which always seems to happen. In this case having the configuration screen setup early makes this very easy.
- HW Test Panel – The first thing I do for any hardware project is to create a hardware test panel. This let’s the technicians ring out all the connections and make sure everything is hooked up correctly, so I’m not wondering why my software is not working only to find out some sensor is not connected correctly. It’s also useful for troubleshooting problems once the system is deployed.