Avoid These 12 Programming Blunders: Common Software Development Pitfalls and How to Prevent Them
The world of art is characterized by a variety of conflicting opinions on what constitutes a great piece of art, and in a similar manner, programmers often hold differing views on what makes for excellent code, aside from the basic requirement that it doesn’t crash. Each developer has their own set of principles and standards. When a developer advises against doing something, it is likely because they have previously attempted it and experienced a significant failure.
However, problems may arise when we overreact to a mistake by going too far in the opposite direction. For instance, a team may avoid a problem with option A by selecting option B instead, but it may turn out that option B also has its own set of problems, resulting in another extended period of troubleshooting.
The good news is that you can learn from both the original mistake and the overcorrection. The best approach is frequently the one in the middle. This essay discusses some of the most frequent programming blunders as well as the dangers of taking the opposite route.
Playing it fast and loose
Neglecting the fundamentals is a simple yet common way to create code that is unstable and prone to crashing. This could involve overlooking how unpredictable user actions could impact your program. Will a zero be used as input for a division operation? Will submitted text always be of the correct length? Are your date formats compliant with the appropriate standards? Has the username been authenticated against the database? Even the smallest oversight can result in software failure.
One approach to addressing this issue is to leverage the error handling capabilities of the code. A developer who takes a lax approach might encompass their entire stack with a single catch block for all potential exceptions. They may simply log the error, return an error code, and pass on the problem to someone else to handle.
Focusing too much on minor details can also have negative consequences.
Some people believe that a skilled programmer is someone who checks both sides of a one-way street before crossing it. However, similar to playing fast and loose, this tendency can lead to problems. Software that is overly cautious can slow down operations significantly. While checking a few null pointers may not have much impact, some code is excessively anxious, checking repeatedly to make sure the doors are locked, making it impossible to get any work done. This kind of system is mired in a maze of verification and authentication procedures, with no processing taking place.
The key is to organize your code layers to verify data when it first enters and then let it pass through. Although there may be some errors as a result, that’s why error checking is included.
Too much theoretical complexity
Some programmers embrace the study of algorithms. They enjoy designing complex data structures and algorithms because they want to build the most efficient stack possible. Each layer or library must be perfect.
It’s a nice impulse but in many cases, the end result is a huge application that consumes too much memory and runs like molasses in January. In theory, it will be fast but you won’t see it until there are 100 billion users with 50 million documents per user.
Much of algorithmic theory focuses on how well algorithms and data structures scale. The analysis only really applies when the data grows large. In many cases, the theory doesn’t account for how much code it takes to shave off some time.
In some cases, the theory elides crucial details. One of the biggest time sinks is fetching data either from the main memory or worse from a database in the cloud. Focusing on the practical issues of where the data is stored and when it is accessed is better than an elaborate data structure.
Not enough theoretical complexity
Insufficient theoretical complexity is the opposite problem of being too engrossed in programming theory.
When code is written without taking into account the theoretical aspects of data structures or algorithms, it may perform well on test data, but may not be able to handle the load when real users start using it.
It’s important to address scalability concerns during the planning phase, as some features, such as comparing each data entry to another, may have inherent quadratic complexity that can lead to exponential slow-downs in optimizations. Sometimes, it’s better to dial back on what you promise to avoid overcomplicating the system.
Balancing theoretical complexity with practical considerations is a challenge, and sometimes it’s better to focus on careful iteration and load testing rather than premature optimization. As the old saying goes, “premature optimization is a waste of time.” Start with a basic program, test it, and then address the slowest parts.
Too much faith in artificial intelligence
We are in a moment where it is becoming clear that AI algorithms can deliver amazing results. The output is shockingly realistic and better than expected. Many believe that the age of the sentient computer has arrived.
AI sometimes provides data that is incredibly useful. Programmers have swapped search engines for large language models because they can’t stand all the ads and “amplified” features created by humans. They mistrust human interference and put their faith in machine learning.
It’s important, though, to recognize exactly what algorithms can do and how they work. Machine learning systems analyze data, then build an elaborate function that imitates it. They’re like clever parrots when delivering text. The problem is that they are programmed to deliver everything with the same confident authority, even when they’re completely wrong. At worst, an AI can be terribly wrong and not realize it any more than we do.
Not enough training data
An AI model’s performance is solely dependent on the quality of its training data. As machine learning algorithms become more accessible, programmers will have more opportunities to utilize them in various projects.
However, AI tools are often unpredictable and produce inaccurate results, primarily when the training data is inadequate. Rare scenarios that are not found in the training data, called “black swans,” can completely confuse an AI, resulting in random responses.
Collecting and organizing data for training an AI model is a significant task that requires a different mindset than traditional programming. It is essential to gather broad and representative data for creating a reliable AI model, which is not usually a part of a programmer’s training.
Trusting your security to magic boxes
Relying solely on “magic boxes” for security can be risky. Some salespeople may suggest adding cryptography as a quick fix, but this can create a false sense of security. While computer scientists have created libraries that offer a multitude of options to solve coding issues, utilizing them can also mask complex problems and even introduce new ones.
The issue of sharing too much code across various libraries is only beginning to be understood, as seen with the Log4j bug. Cryptography can also be a source of vulnerability, and assuming that linking an encryption library will provide complete security is a mistake.
In fact, the National Institute of Standards and Technology recently retired SHA‑1 due to its weaknesses. Many of these algorithms have subtle weaknesses, and fully understanding them requires more than just a quick read of the manual’s “quick start” section.
Can you really rely on yourself, even if you don’t trust others? Developers often fantasize about creating their own libraries. However, this mindset can lead to unforeseen problems in the future.
“Hackers are delighted to see homemade encryption,” warns John Viega, noting that even the most experienced programmers can make mistakes in safeguarding their systems from exploitation. So who should you trust? Yourself or the so-called experts who also make errors? The solution can be found in risk management.
Many libraries do not need to be flawless, so it is more effective to use a pre-existing library rather than writing your own code. The library contains optimized routines developed by a team. They may make errors, but the larger process can weed out many of them.
Too much trust in the client
Developers often overlook the fact that they do not have absolute control over their software once it’s running on someone else’s machine. Some of the most severe security vulnerabilities emerge when developers assume that the client device will behave appropriately. For instance, code intended to run on a browser can be modified by the browser to perform any action. If the developer fails to validate all the incoming data, things can go awry.
One of the easiest methods of attack is dependent on the fact that certain developers just pass the client’s data to the database, which works fine until the client sends SQL instead of a valid answer. For instance, if a website requests a user’s name and adds the name to a query, an attacker could input the name “x; DROP TABLE users;”. The database mistakenly assumes that the name is “x,” and then proceeds to delete the table containing all the users.
Resourceful individuals can manipulate the server’s trust in numerous other ways. Web surveys, for example, are an opportunity to introduce bias. Buffer overruns remain one of the easiest ways to tamper with software.
To make matters worse, severe security vulnerabilities can arise when seemingly benign vulnerabilities are linked together. One developer might enable the client to write a file, expecting that directory permissions will prevent any stray writing. Another developer may expose permissions simply to resolve an incidental bug. Individually, these coding choices are harmless, but together, they can enable arbitrary client access.
Not enough trust in the client
Excessive security measures can cause issues for an enterprise, even if there are no major security breaches. Too much security and intrusive data collection can discourage people from participating in social media sites and online advertising, leading them to either lie or drop out. Additionally, overly strict security protocols can hinder other practices, as seen in the example of having to loosen security measures to solve a software problem. As a result, many web developers are now trying to minimize security measures to make it easier for users to engage with their products and reduce the amount of data they need to defend. For instance, some websites have eliminated passwords and instead use a single-use email to log in. This is a simpler mechanism that is almost as secure as passwords. The book “Translucent Databases” offers several strategies for databases to store less information while providing the same services.
Closing the source
Determining the appropriate level of software code sharing with users is a complex issue for companies. According to John Gilmore, who co-founded Cygnus Solutions, one of the earliest open source software companies, choosing not to distribute the code goes against the code’s integrity. Gilmore believes that distributing the code is a simple way to foster innovation, and importantly, to identify and resolve software bugs. By sharing the code, individuals outside of the company can contribute to improving it by identifying and fixing bugs, adding features, and improving documentation. Although their contributions may not always be perfect, it often leads to more harmonious and better-structured code. Furthermore, opening up the code can encourage the creation of more modular and better-organized software, as others compile and transfer it to other platforms. As small adjustments are made to share the code, the outcomes are fed back into the codebase, leading to a better and more accessible product.
Openness as a cure-all
Although millions of open source projects exist, only a small fraction attract enough contributors to maintain, revise, or extend the code. The mere fact that a project is open does not guarantee practical results, as outside contributors may not have an incentive to put in the work. Moreover, opening up a project can add new overhead for communications and documentation. This extra work can be worthwhile for larger projects but can weigh down smaller ones. Additionally, opening up a project can strip away financial support and encourage mob rule. While open competition and creativity can yield great results, some developers may return to closed-source projects for the structure, hierarchy, and authority that support methodical development.Source link