STUPID - Bad Practices of Software Development
We've already mentioned the best practices for software development covered by the SOLID acronym. Similarly, there is the opposite acronym, STUPID, which, on the contrary, combines bad practices, mistakes, and antipatterns that lead to waste of both time and money.
The STUPID practice group consists of:
- Tight coupling
- Premature optimization
- Indescriptive naming
Let's explain them in detail.
STUPID starts straight with the controversial singleton that the intermediate programmers use, and the professional ones damn it.
If you want to violate LoD, Shy, Loose Coupling, DIP, IoC and a variety of other good practices, share dependencies in your applications through the Singleton antipattern. Despite of the initial sensation around the Singleton, over time it showed up that, basically, it was nothing but a global variable dressed in a nice suit of design patterns. And, of course, it brings the same problems as global variables do. Dependencies will be globally accessible and violate the fundamentals of the OOP. I'm sorry to hear that some companies ask about the Singleton pattern during job interviews and maybe they even use it in their corporate software. Be careful in interviews and try to describe the pattern neutrally. But don't use it in your applications, there will be less evil in the world.
Create a tight coupling in your applications, e.g. with the above mentioned Singletons or a bad assignment of responsibility, don't use GRASP, and you won't be able to maintain your applications soon. Tight coupling refers to the situation where there are too many unnecessary references between two classes. The whole system is then closely tied together, making it impossible to modify and difficult to extend. The opposite is the already mentioned loose or low coupling when the components are loosely bound with only a few references between them.
Untestability refers to automatic tests about which we have a separate course for each programming language here. If you haven't been interested in testing yet, I'd definitely recommend to study it. When designing classes, it's important to remember that someone will probably test them. It's similar to having to remember that the class will likely be inherited. For example, if you use Singletons, you'll make the dependencies impossible to mock and the class untestable (this is, by the way, one of the other disadvantages of Singletons). Another problem may be violating SRP, when methods are too long, vague, and e.g. instead of returning a value, they print something and so on. Such code can't be tested very well. These days, a complex application without at least basic automated testing is noncompetitive, the cost of testing real commercial applications manually is relatively high. You can find a lot of information about testing, including an introduction and a list of benefits and disadvantages, in the above-mentioned test courses in sections of various programming languages here on the network.
Regarding the early optimization, you may have heard the sentence
Premature optimization is the root of all evil
The principle says we should not deal with code optimization until it's really needed. It was found quite soon that before we put the application into a real production environment we have no idea what its performance would be and where exactly its bottlenecks are. The optimizations done by impatient programmers mostly only slowed down the development and weren't needed or sufficient in practice.
However, the principle doesn't say to write poor code. We should choose the
good and simple solutions and optimize them not before these fail. During one of
our IT trainings, an interesting debate was held on the choice of variable data
types. One of the participants objected to why we recommended using
int to represent all numbers, for example, when the age of the
users will never be more than 150 years, and
int has the range up
to 2 billion. Our answer was that
int occupies just 32 bits in
memory, so the 32/64 bit processor works with it much faster than it'd work with
a smaller 8-bit type. This optimization would probably have insignificant effect
on the performance, and similar thinking unnecessarily wastes the development
time. We're working on a separate course on the application optimization.
One of the rookie mistakes is choosing indescriptive names,
whether for variables, methods or classes. It doesn't make sense to have a class
name plural, a method name should be an imperative verb such as
attack(). Some people name variables as
text, and so on. Or, like
baz, unfortunately, you can find this in examples
in the official PHP manual. We always name variables according to what
they contain, it's a very simple rule and surprisingly many beginners
violate it. The correct names are, for example,
invoices. Consider the difference between the
array array and the
invoices array. The collection
name, of course, should be plural, the array of invoices must not be named as
i. Using similar identifiers slows down the
development of the application extremely, and as programmers normally receive up
to 4 average salaries, it also increases the development cost.
We've already talked about the duplicate code and DRY. Any code that is in the same or even similar form in multiple places of our application is automatically wrong and represents a potential threat to further development. Not only it's hard to understand the long code, but every change needs to be made at all the occurrences of the code, creating room for mistakes. For an exhaustive example of how to shorten code using the DRY and KISS rules, see Basic Best Practices for Software Design.