Configurability in Times of Complexity
In the design of modern technological systems, a persistent challenge surfaces as complexity increases: the difficulty of managing configurability. Whether in consumer software applications, embedded systems, or autonomous vehicles and aircraft, the ability to configure a system to meet diverse needs often grows in proportion to its complexity. While configurability provides flexibility and power, it also introduces cognitive and operational burdens on users, often creating a tension between utility and usability. This text explores the nature of this trade-off, examining its underlying causes, manifestations in various domains, and potential strategies to manage it.
At its core, configurability refers to a system's ability to be tailored to specific tasks, environments, or user preferences. Complexity, meanwhile, refers to the number of interacting components or the degree of variation and behavior (variety of states) a system can exhibit. As systems grow in sophistication, the range of potential use cases expands, and with that expansion comes the need to expose more options to the user. In some cases, this exposure is essential, as abstracting away certain details would compromise the control and performance that the system is designed to provide. The challenge lies in deciding how much configurability should be exposed and how it can be managed without overwhelming the user.
In software engineering and human-computer interaction, this trade-off has been recognized and studied extensively. Researchers have observed that the proliferation of features and configuration options can lead to what is sometimes called "feature fatigue". A well-known study by Thompson, Hamilton, and Rust (20051) found that while consumers are initially attracted to products with more features, they often become less satisfied over time as the complexity of using those features sets in. This mismatch between expected and actual utility highlights a problem: configurability that is too granular or poorly organized can reduce user satisfaction and increase the likelihood of error.
This issue becomes particularly acute in systems where abstraction and the need for precise control dance in a trade-off. Take, for example, Adobe Photoshop. As a widely adopted tool used by photographers, designers, and digital artists, Photoshop must support a vast array of creative workflows. Abstracting away configuration options in the name of simplicity risks removing essential capabilities. Thus, the software exposes a massive number of settings, menus, panels, and modes, many of which are interdependent. The complexity here is not accidental but essential to serve the breadth of professional use cases, but the cognitive load it imposes is real and unavoidable.
A similar pattern emerges in embedded systems development. Modern microcontrollers such as the STM32 or ESP32 families come with an enormous, borderline ridiculous range of peripherals and operating modes. The associated reference manuals often exceed a thousand pages, and the configuration of even basic features like UART communication or timer interrupts can involve careful coordination across multiple subsystems, including clock trees, power domains, and GPIO settings. The complexity is driven by the device’s general-purpose nature: it must support a wide range of application domains, from industrial control systems to wearable fitness trackers. Because the optimal configuration depends so heavily on the application context, abstraction is difficult to achieve without sacrificing efficiency or specificity.
The problem is not limited to software or electronics. In the aviation industry, the operation of modern aircraft, while ostensibly clear in its goal of transporting people safely from one location to another, involves an immense array of configurable systems. Despite having clear, well-defined control goals, aircraft must operate in a three-dimensional, highly regulated, and safety-critical environment. Factors such as airspace constraints, weather systems, aircraft performance limitations, and air traffic control directives all contribute to a need for meticulous pre-flight configuration and in-flight system management. The automation present in modern avionics adds its own layer of complexity, offering powerful capabilities through autopilot and flight management systems, but also requiring pilots to understand and correctly operate dozens of interrelated modes and settings. Misconfiguration is often the root cause of critical failures in complex systems, a lesson that applies equally to the cockpit2 and the data center3.
Yet, not all systems suffer equally from configuration burden. Electric vehicles, for example, present an interesting contrast. Despite their undeniable increasing complexity, the user experience is typically more streamlined than that of internal combustion vehicles. This is largely because the control goals in electric vehicles are both well-defined and narrow in scope—accelerate, brake, charge, monitor range—and because manufacturers have invested heavily in hiding technical complexity behind layers of automation and smart defaults. Where configurability is needed, it is often surfaced only when relevant, a strategy known in interface design as progressive disclosure. The difference lies not in the complexity of the underlying system, but in the consistency of the user’s goals and the feasibility of making intelligent assumptions about what configuration is appropriate.
Ultimately, the tension between complexity and configurability reflects a deeper design question: who bears the burden of choice? In systems designed for mass consumption, reducing cognitive load is paramount, and designers often make strong assumptions to eliminate the need for user configuration. In more technical or mission-critical systems, however, those assumptions may not hold, and configurability becomes necessary, even if it is inconvenient or intimidating.
Designers can mitigate this tension in several ways. One is through better tooling: visual configuration tools, templates, and code generators4 can ease the cognitive burden, though they can also introduce new layers of abstraction that may obscure system behavior. Another is through more adaptive systems that adjust their configurability based on context or usage patterns. And of course, documentation: when complexity cannot be eliminated, it must be explained clearly and systematically, allowing users to make informed decisions. Sure, documentation complexity grows with system complexity, so there’s also a bit of a challenge there.

The relationship between complexity and configurability is an inevitable one in many systems. While the ideal of simplicity remains attractive, it is not always compatible with the demands of fine control, precision, and flexibility. Understanding when and why configurability is necessary—while designing interfaces, tools, and workflows that support it without overwhelming the user/operator—is one of the central challenges of modern system design.
In some reports, misconfiguration appears as the second most frequent type of primary error in commercial aviation: https://www.atsb.gov.au/sites/default/files/media/36891/Survey-_common_flying_errors.pdf
I learned the hard way that code generators can also introduce their own bugs https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/818406/halcogen-various-bugs-in-halcogen-version-04-07-01