Evils in programming

0

Programming is a skill that involves the ability to write, understand, and manipulate code to create software, applications, and systems. The aforementioned programmed pieces of work then needs to be written, understood and manipulated by other programmers after the work has being published to maintain it.

If the original programmer did not adhere to best practices, use current available technologies or committed the ‘evils in programming’, the process to maintain the codebase would become extremely difficult to maintain.

Technical Debt

When programmers or development teams rush a project to finish it faster, they leave or even cause issues within the application that they would need to be fixing in the future. When you rush your decisions without proper planning you will most likely make bad decisions somewhere, overlook something or simply commit to a specific construct that would be extremely difficult or impossible to change later on if it ends up being a bad decision.

Rushed development could lead to inefficient algorithms and data structures, obsolete dependencies, inadequate testing coverage, overlooked documentation and ignored code reviews. All of these issues essentially causes more overhead for programmer(s), development team or the company.

When developers write code quickly to rush a project without focusing on code quality, it can yield duplicated code, unnecessarily long methods and poorly structured code. Rushed jobs also include overlooked bugs, either consciously or by accident. Temporary bug fixes sometimes gets so embedded into the application, that coming back to fix it properly (if you even remember about it) would be a feat in and of itself.

Code Quality

Writing overly complex or poorly documented code can hinder collaboration, maintenance and debugging, leading to inefficiencies and errors. Poor code quality can manifest in various ways, making software development challenging and error prone.

Spaghetti Code

Spaghetti code refers to code that is tangled and difficult to follow due to excessive nesting, complex conditional statements, and lack of modularization. Spaghetti code makes it hard to understand, maintain, and debug. It’s like a run-on sentence that just keeps going and going for miles.

Spaghetti code is what you get if you write your code in an unstructured format that is hard to follow. Using proper object-oriented programming or the appropriate variant for the task at hand would result in a more organized, maintainable codebase that is easier to understand, modify, and extend over time.

Magic Numbers

Using magic numbers (hard-coded numeric values) or hard-coded strings throughout the codebase without explanations or constants can lead to confusion, errors, and maintenance challenges when values need to be changed. A simple example is the value for ‘months’ in a mortgage calculating application: You could simply have the number 12 in the formula or, preferably, have a constant named MONTHS that was set to 12 at the beginning of the class/method.

Inconsistencies

Various inconsistencies also contribute to bad code quality which hinders code comprehension between collaborating programmers. Naming variables, functions, classes and other language constructs inconsistently makes the code ugly and increases difficulty distinguishing between various constructs.

Using clear and consistent naming conventions improve code comprehension and maintainability.

Poor Error Handling

Every application has cases where specific conditions are unfavorable for the process of the application. Not necessarily bugs but conditions that don’t meet the expectations required to reach the expected results. You can’t simply assume that everything is going to run smoothly and expectedly, especially if user input is involved.

Handling every possible case that could happen every step of the way improves security because unchecked error conditions could possible be exploited if discovered by a tainted programmer and it also improves user experience by providing feedback and informing the user what and where went wrong (if required) or at least sets the base for the user’s subsequent actions.

Inadequate error handling, such as catching generic exceptions or ignoring error conditions, can result in unexpected program behavior, crashes and security vulnerabilities. Robust error handling improves software reliability, user experience and has the application perform expectedly in every situation.

Code Duplication

Copy/pasting code instead of using reusable functions, classes or modules leads to code duplication. Duplicated code increases maintenance efforts, introduces inconsistencies, and makes it harder to update functionality consistently. If you ever need to change something somewhere, you would need to find every instance where that is used and update every duplication.

Poor Documentation

Insufficient or missing comments and documentation make it difficult for developers to understand the purpose, logic and usage of code segments. Failing to document code, system architecture, processes and decisions can make it difficult for team members to understand, maintain and troubleshoot the software. Clear and descriptive comments improve code comprehension and facilitate collaboration.

Overlooked Code Reviews

Skipping or rushing through code reviews without thorough feedback and validation can result in overlooked issues, such as coding standards violations, potential bugs, and suboptimal implementations. Regular code reviews promote code quality and consistency. Better to go through every step properly rather than rushing through and causing more headaches for yourselves or the team farther on on the timeline.

Poor Optimization

If you skip or rush through the planning phase of the application and choose inefficient algorithms or inappropriate data structures, that could lead to poor performance, scalability limitations, and increased resource consumption. Part of optimization is finding the best algorithm/data structure combination that performs well and doesn’t use too much resources while not hindering scalability or code comprehension/readability.

Optimizing algorithms and data structures improves software efficiency and responsiveness.

Dead Code

Dead code is dead weight in the application that causes unnecessary complexity and confusion in the codebase. A programmer working on maintaining the application after the original programmer could spend hours to find out that that piece of code is never used. Removing unused code reduces codebase size, improves readability, and enhances maintainability.

Bad Security

Security is important not only to the application but it’s important to the image of the company that will have it’s name/brand on the application. Loosing clients to the fact that some hackers managed to make your application behave maliciously would cost the company new clients down the road.

It is important to research what security measures are required for your application. Additionally, you should identify vulnerabilities within your application’s ecosystem and learn how to mitigate them.

There are many things that could hinder an application’s security including, but not limited to: unvalidated input, insecure authentication and authorization, insufficient data encryption, insecure configuration files, poor session management, failure to sanitize outputs, missing security headers, insecure file handling, and so much more.

To farther help secure an application, the application needs to have a strong logging and monitoring system that would help identify what user performed the action that made the application behave, or attempt to behave, unexpectedly.

Inadequate Testing

Insufficient testing, including lack of unit tests, integration tests, and thorough testing of edge cases, can result in undetected bugs and unreliable software. A growing application needs to be constantly tested to make sure every condition behaves expectedly regardless of the number of updates and optimizations that the application undergoes throughout it’s lifespan.

Testing your application involves unit testing, integration testing, regression testing, performance testing, security testing, user acceptance testing and using realistic test data for all of the tests.

Ignoring Best Practices

Programming has been a longstanding profession, characterized by the establishment of numerous practices, coding standards, and design patterns that are widely accepted as best practices among programmers. Failing to follow industry best practices, coding standards, and design patterns can lead to code that is difficult to maintain, scale, and extend.

Continuous Learning

Programming is an ever-changing landscape with new technologies rapidly evolving, tools, frameworks and best practices. Without moving forward and constantly learning new things to keep up with the rapidly evolving industry standards you risk stagnating your skills, using outdated systems and missing opportunities.

Programmers need to constantly learn new technologies, try new methodologies/best practices, expand their skills, work on diverse projects, seek feedback/mentorship, participate in formal training (workshops, conferences, on-line courses), collaborate and so on and so forth.

Embracing continuous learning involves a mindset of curiosity, adaptability, and a commitment to ongoing skill development and improvement. It requires active participation in learning opportunities, seeking feedback, collaborating with peers, staying updated on industry trends, and embracing change to thrive in the dynamic field of software development.

Contributing Factors

I think there are many factors that contribute to programmers performing inadequately (or committing any of the “evils” often associated with programming). Some of these factors include, but not limited to:

Time and Resource Constraints

Pressure to meet tight deadlines, manage limited resources, and balance competing priorities can contribute to stress and burnout among programmers.

Mental Health

High-pressure environments, unrealistic deadlines, and constant demand for new features can contribute to burnout and negatively impact developers’ mental health and well-being. Stressed programming could cause bad decisions which would impact the quality of code and code maintainability.

Complexity of Requirements

Ambiguous or constantly changing requirements can lead to confusion, rework, and difficulty in delivering a solution that meets application requirements.

Dealing with complex algorithms, intricate data structures, and challenging technical problems can be mentally taxing and time-consuming.

Developing and maintaining large-scale systems with numerous components, dependencies, and integrations adds complexity to software projects.

Working with legacy codebases that lack documentation, have outdated technologies, or are poorly structured can be challenging and error-prone.

Human Factors

Lack of communication between teams, programmers and other involved parties yields ambiguities which produces incompatible code between collaborators. Communication barriers and conflicts between involved parties also hinders productivity and quality of code.

Version Control

Failing to use version control systems effectively for code management, collaboration and tracking changes can lead to code conflicts, loss of code history and difficulty in code review.

Mitigating the ‘Evils’

It takes a lot of work for a programmer to stay recent and to constantly be in the loop of all evolving technologies and to work in such a way that works beneficially within a collaborative context. It is self-evident that to mitigate any of the coding practices deemed as ‘evil’ in programming, it requires the programmer to do the exact opposite of what the evil is.

The biggest things a programmer could do to help in producing quality application that is easy to maintain in the future for every party involved is to plan the application well, take pride in his/her work, document their work, do a lot of testing continuously and to keep learning and expanding their skills.

Obviously this are generic evils between all programming languages while each programming language has their own specific evils that programmers adhering to best practices do everything they can to avoid (like avoiding certain language constructs).

On the other hand, I don’t feel a programmer needs to over-engineer something specifically to avoid something within their programming language that would enable them to accomplish their task rather quickly. (Like avoiding while loops in computer programming applications).

Comments

No Comments. Be the first to make a comment.

Need to Register or Login to comment on post