slashbinbash.de / Opinions on Software Development

This is a collection of personal opinions on different software development topics.

False Assumptions: The Root of all Evil?

In my experience, false assumptions are one of the most common mistakes that lead to bugs. False assumptions creep up everywhere, especially along abstractions and interfaces.

User requirements can be based on false assumptions about the problem that needs to be solved. Translating user requirements into software functions is another source of false assumptions, if the programmer is unfamiliar with the language or terminology of the problem domain.

Programming languages have many abstract concepts whose behavior cannot be correctly predicted, unless they are fully understood by the programmer. The programmer may draw wrong conclusions if their mental model is based on false assumptions about the code, or the system that the code is running on.

Operating systems behave differently depending on the version of its APIs, drivers, libraries, and the overall configuration of the system. Your program competes with other programs for resources like memory, threads, access to hardware, etc. Any system that is a black box from the point of view of the programmer, inevitably leads to the formation of false assumptions.

If you have false assumptions, you cannot make any reliable predictions about how your code will behave. Learn to recognize when you are making an assumption. Admit that you are making an assumption. Evaluate the risk of what would happen if the assumption were false, and estimate the cost of mitigating the situation.

It's better to admit that you don't know something, than to base your work on false assumptions.

What programming language should I learn?

It depends on what you want to do, but I generally put programming languages into three categories:

Most software developers that I know, know at least 3 or 4 different programming languages.

Should I make my project open-source?

I have a somewhat reserved opinion about open-source.

In my opinion, there are only a few types of projects that need to be open-source:

That's not to say that you shouldn't make your project open-source, if you want to join and contribute to the open-source community.

Resourcefulness and Optimization

I'm frustrated about software developers who have no regard for efficient resource management. The bloated and slow software that we use today, is a result of the industry and academia failing to address the cost of computing.

The truth is that every memory that you allocate, every function that you call, every thread that you create, every file that you open, every framework that you use, has a certain cost attached to it. This cost might seem insignificant to you, but it is not zero. You should always consider the performance and memory implications of your algorithms.

Considering the performance and memory implications of your algorithms is not premature optimization. It's good design! Making optimizations based on false assumptions, that's where people make mistakes.

The least that I expect from a software developer, is that they don't shrug off matters of performance, and instead search for solutions that strike a good balance between the resources that are required to run the program, and the benefit that they deliver to the user.

Elegant, Evil, and Clean Code

There are developers who are heavily invested in writing beautiful, clean, or elegant code by following the rules that are layed out by industry gurus. These gurus give the impression that there is a consensus in the industry about what constitutes good code. When in reality, these are just guidelines that are handed down by senior developers, who all have their own subjective opinion on how good code should look like.

I would argue that these words don't communicate clearly what it is that makes one solution better than another. Speaking of "elegant" code is highly subjective, and for most people a gut feeling. What seems "clean" to you might be incomprehensible for someone else. The use of "evil" may lead to dogmatic thinking about what is allowed and what is not allowed to be written in a programming language.

I would like to see developers who don't use words like "beautiful", "clean", "elegant", or "evil" to describe code. Instead, they should be able to articulate, in their own words, why one solution is better than another, given that both solutions produce the correct result. Otherwise, it is nothing more than opinion or personal taste.

Creativity in Software Development

I think there is a misconception when it comes to creativity in software development. What we need are developers that solve difficult problems in creative ways. What we don't need are developers who write code in creative ways.

Don't be creative when you write code. Write down what the machine has to do, as readable as you can. Try to make your decisions and intentions clear to other readers, so that there's no room for interpretation or false assumptions. If you can do that while minimizing the dependencies in your code, you are probably already better than the average developer out there.

Communicating Intent in Source Code

When reading other peoples code, I sometimes find myself in a situation where it is unclear why the code is written in the way that it is. I would say that the code isn't communicating the intent of the programmer very well. This is made more difficult by the fact that it is not always easy to express intent within the constraints of a programming language.

Another word for "intent" is "purpose". Does the code that you have written serve a clear purpose? Are you communicating the purpose of your code well? You might be able to read the instructions and understand what the machine is doing, but why is it doing it?

It is easy to obfuscate intent by adding abstractions, indirections, and misusing the programming language by doing things in a way that are atypical. It is also easy to obfuscate intent by over-engineering, there is too much ceremony around the code that actually does something, or it appears as if the solution does not fit tightly around the use-case because it tries to be applicable to many different use-cases.

Intent can also be destroyed when changes are made to the code without understanding the context in which these changes are made. This can lead to code that doesn't follow a clear sequential logic or hierarchical structure, but it still appears to work. Breaking sequential logic means i.e. interleaving unrelated instructions and going from a pattern like AB to A1BA2. Breaking hierarchical structure means that you are mixing different levels of abstractions in close proximity to each other, i.e. accessing operating system APIs close to business logic.

Design patterns and clean code can help us to express intent. But I would argue that you cannot express your intent by simply applying rules. You get it by practicing, learning the subtleties of a programming language, and getting feedback from other programmers.

On Logging and Error Handling

Generally speaking, I think that logging is appropriate when you need to be able to:

  1. Establish a sequence of events that led to a bug or crash
  2. Get a snapshot of some runtime state, before the application is terminated

However, you should not use logging instead of proper error handling.

First, logging is a side-effect. You typically cannot tell from a function signature if the function is going to log or not. If the function is logging to disk, it may have adverse affects on the runtime behavior of the application. Not only the disk access, but also the handling and modification of strings that occurs during logging, can lead to memory and I/O related issues that are not appropriate for certain areas of code. For instance, you would not expect standard containers or data structures to log information to disk whenever certain events occur inside the implementation. You would also not expect functions to log data to disk inside a hot code path or loop, because system calls may impact performance negatively.

Second, logging adds a dependency that may not be appropriate for certain areas of code. For instance, if I am using a math or image library, I don't want to pull in a logging dependency or library into my project. Leave the logging up to the user.

Third, there is no way for a user of a function to react to errors and warnings that are only logged but not communicated through proper error channels. If you are into unit testing, how are you going to test a function if it logs instead of clearly communicating its error states through code?

Fourth, good logging requires enough context about what is happening in the application. If you log in one of the lower levels of your application, or at some abstraction layer that cannot know the concrete implementation, the informative value of the logging will be equally low or abstract. For instance, lets say you decide to log every time that you fail to write to an abstract stream, you don't know if it is a stream to a file, a network connection, a printer, etc. You would need more information to determine the reason for the failure and what use-case triggered it.

Fifth, depending on the implementation, logging may or may not be thread-safe. This means that in a multi-threading environment, you have to be very careful about how you log, otherwise the log output may be garbled, or the threads may block each other when trying to log.

Therefore, my opinion is that:

  1. Logging can supplement already existing error handling mechanisms with more information about the runtime state
  2. Logging should be done at the appropriate levels of the application

Refactoring Code

You cannot reduce the complexity of a problem by refactoring code. Refactoring code will not make a problem less complex.

The only thing that makes software less complex is removing code. If refactoring code allows you to remove code, that's a win.

Otherwise, you are only rewriting the code in a way that you can read it. The next person who cannot read your code will rewrite it again. Don't assume that your code is more readable.

Capitalism and Software Bloat

I see software as a tool that solves a particular problem, like a hammer. Once you've produced the hammer and it is shipped to the customer, there are no more changes. Of course, some people like their hammer to have a certain handle, or color, but nobody expects you to put a screw driver on the other end, and maybe a bottle opener on the side, and it needs a mechanism so that the bottle opener can be exchanged in the future, maybe for a letter opener, or a cork screw - we don't know yet.
I know the hammer example sounds silly but that's exactly what we do to software.

Unlike a hammer, software is never really done. It needs to be maintained. Bugs have to be fixed. The hardware, operating system, frameworks and APIs change. If you want to keep selling the software that you have already released, you have to regularly update it. There are even laws that force you to update your software and keep it functional for up to two years after purchase.

However, for some reason, we have accepted that adding features to a product that was released 5, 10, or maybe 20 years ago, is a sensible thing to do. We have also accepted that GUIs have to change every 2-4 years so that it looks "fresh" or up-to-date. I think some part of it has to do with the capitalist mindset, that expects constant economic growth. As a result, software products have been growing out of proportion.

Blaming it all on capitalism is a little bit too easy, tho. I think there are a few factors that play into this - not all of them have to do with money.

You would be mistaken, if you believe that this kind of thing can only happen in a capitalist society. There are plenty of free and open-source projects that are suffering the same fate, i.e. Linux desktop environments, internet browsers, programming languages, software libraries, and APIs.

The only solution is to design your software in such a way that it is possible to add value independently of the released product, i.e. through content. After development is finished, you should only do maintenance and add content. Under certain circumstances, you may add a new feature, if you remove an old one. You could also create an entirely new product.

It is a human trait to always want newer and better, and more of it. As long as there are no real consequences, we will continue to create bloated software.

How much is software worth?

In the last decade I have seen a sharp decline in what people perceive to be the value of software products. You can also see an increased entitlement in software users. As a result, I've been thinking about what software is actually worth.

With mobile apps costing only a dollar or two, with digital game stores giving away games for free to bolster their customer count, with entire software industry branches switching to subscription models, with companies giving away their software for free when you purchase the hardware, I cannot help but think that we are teaching our customers that software, and by extension software development, has no worth. It doesn't help when at the same time, the quality of software is going down. It also doesn't help when we are selling half-finished products or alpha-versions for full price.

On the other hand, people are willing to pay millions for software products that haven't even started development yet (see various Kickstarter projects and disasters). They are happy to pour money into Early Access games that are not finished, and probably won't be for another 5-10 years. And despite all the outrage, people are spending millions on micro-transactions and in-app purchases.

Another metric that people apply, is how much use or entertainment they get out of a software product, measured in hours. This is sometimes compared to the price of movie tickets, or cost of certain food items, like pizza or a regular meal at a restaurant. I think this only goes to show how difficult it is to articulate how much software is worth.

The open-source community and small developers who are giving their software away for free, make it even more difficult to give a good answer. What is software worth, if the people who are involved in creating it, are willing to work without getting payed for their work? I know a few software developers that have a steady income and do this as a hobby, or don't want to deal with taxes. But what you are signaling to people is that you are willing to provide your time and expertise for free. You better make sure that you are doing it for the right reasons.

I think its on us to educate ourselves better before buying products, not giving in to marketing promises, and supporting the developers who really deserve it.

A Case for Software Engineering

Software Engineering implies that creating software is akin to building bridges or constructing a hospital. Although software is much more abstract than a car or an airplane, it requires principles for design, construction, and maintenance, just like its physical counterparts.

Language standards like the C++ ISO standard have to be considered when developing software with the C++ programming language. Decisions have to be made regarding the software architecture, i.e. how the different systems in our solution operate and communicate with each other. Hardware specifications and requirements have to be considered. Predictions are made about how the software will operate, including a risk analysis. Security standards have to be considered when software failure may result in injury or death.

Tools are used to build software. Libraries and frameworks provide the fundamental structure of the software. Test are performed to determine the runtime performance, memory usage, robustness, reliability and security of the software, the results of which have to comply with the requirements or specifications of the project. Building software is a team-effort that requires managing teams and coordinating their work to achieve the goals of the project.

Software has to be maintained over a long period of time, ranging from a few years to a few decades. Bugs and problems have to fixed. It has to be kept functional with new hardware, operating systems, and programming language versions. Should requirements change, it has to be modified, restructured, or extended.

A Case for Software Craftsmanship

Software Craftsmanship implies that creating software is akin to carpentry or masonry - it is a craft and an art. Building good software requires skill that is gained through many years of programming and mentoring. There is also a creative component to building software, which allows the individual programmer to express what they believe to be well-crafted software, through the use of a programming language.

You create a rough sketch in your mind or on paper of the piece of software that you want to create. Then you try, through programming, to build what you have in your mind. Along the way, you run into technical problems that need to be solved, as well as design decisions that have to be made. By going through this process you start to see the shape of what you are trying to build more clearly, until you have your first working prototype.

The best analogy that I can think of is stone sculpting. You start with a big block of stone and a goal in your mind. First you work on the big shapes, then the rough features, then the details, and finally the polish. It isn't a perfect analogy because software is never really finished, in the sense that a sculpture is finished, but the process of finding the shape in the stone by carving it, is similar to finding the shape of the software by programming it.

Similar to how people who paint, write, or make music as a hobby, there are people who enjoy programming as a pastime.