Software is everywhere - from games to Bitcoins and from cars to dishwashers. What makes software so flexible that it can permeate such diverse domains? Why can so many problems be solved using software?
What makes these questions more perplexing is that, in the end, all software is just bits and algorithms that manipulate the bits. A bit is just a number that is either 0 or 1. Naively, one could think that nothing very exciting follows if a bunch of bits, even a whole lot of them, are combined. Yet, software (that is, bits and algorithms) controls pacemakers, guides astronauts to a space station and recommends you movies to watch.
How can something as complex as software be built from something as simple as a bits? Let's explore.
Just because the fundamental unit of software is a bit, a two-valued digit, doesn't mean that computers are unable to process other kinds of data. Engineers have found ways to encode many kinds of information as bits: numbers (a sequence of 8 bits has 256 different states that represent integers from 0 to 255), text (the letter A is encoded as a certain sequence of bits, the letter B is a different sequence, ...), images (this bunch of bits defines the color of the pixel at the upper left corner, this bunch tells the color of the pixel to the right of the first one, ...), and audio (this set of bits tells which frequency should be played at the time 145 ms, ...) among others.
The flexibility of data representations ensures that software can be applied to a wide range of domains. Many domains that were previously mostly physical have already morphed into software; movies are now bits on a network instead of VHS tapes.
Computers and mobile phones are not limited to a single task determined at the factory. Instead, new applications can be installed and executed easily. This has not always been as self-evident as it is today. Predecessors of computers, such as desk calculators, were built to perform a single task. It was a great insight by the early computing pioneers to notice that programs, in addition to data, can be stored in memory. Stored programs can subsequently be changed to give new instructions to the computer. Without general-purpose computers there wouldn’t be a huge variety of software available. Distributing diverse software wouldn’t be feasible if every application required a separate device. And no one wants to carry a large number of devices with them.
If programming were done on the bit level, developing large systems would be impossible. The number of details would quickly exceed the mental capacity of a developer as the complexity of the problem increased. To be able to solve complicated tasks, developers work on higher levels of abstraction. Abstractions save mental processing by hiding from view all unnecessary details.
To a developer a YouTube video is an abstraction built on compression algorithms, network protocols and storage formats (and each of those consists of even more levels of abstraction). Abstractions are built by grouping related chunks of data into data structures and by creating functions that manipulate these data structures. Related functions are collected into libraries. Applications are built on top of several libraries, each of which handles various subtasks. Complex software is often a system of interconnected applications.
Software is much easier to modify than physical artifacts. The speed of making changes in software encourages learning and a more iterative approach to development than what is possible in the physical world. The ease of modification and experimentation partially explains the large amount of software available today.
An intriguing feature of software (and technological progress in general) is that every new piece of software creates opportunities for even more software. Each invention modifies the ecosystem in small ways that may be inconsequential to the invention itself, but that are a breeding ground for new ideas. For example, advancements in compression algorithms have led to audio and movie streaming services and accurate touch recognition on mobile devices made the success of Angry Birds possible.
The rate of new opportunities keeps increasing because inventions are often combinations of existing ideas and as the amount of ideas tested in the real world increases, the number of their potential combinations grows at an exponential pace. It is as if the unexplored ideas that are just beyond the current state of progress form a boundary between existing and yet inconceivable technologies. Every time a novel invention is realized, the boundary moves a little bit further, granting us access to a new part of the idea space.
There will always be need for new software exploiting the opportunities born out of earlier progress. At the same time, it’s very difficult to predict exactly what the opportunities will be, because future inventions depend on technologies that are yet to be invented and the path of technological progress is never straightforward.
Explanations of why software is so prevalent can be roughly divided into two classes. The first class tells us that software is able to affect daily lives of people because it can adapt to many domains and because technological evolution induces a cascade of software innovations. General-purpose computers make it economically feasible to have a diverse range of software available. The second explanation class describes why building complex software is possible in the first place: thanks to its ethereal nature, modifying software is easy and abstractions make shaping of complex structures possible.