3

Dieter Rams’ design principles applied to source code

 3 years ago
source link: https://uxdesign.cc/dieter-rams-good-design-principles-applied-to-source-code-b21559969170
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Dieter Rams’ design principles applied to source code

Photo of Deiter Rams
Photo of Deiter Rams

Dieter Rams is arguably the most celebrated and influential product designers of the last century. His ten principles of “good design” influenced product design the world over. Part of what made Ram’s ten principles so compelling is their ability to be adapted to virtually anything that is created, from socks to software.

And that is exactly what we shall set out to do. We are going to apply Dieter Ram’s ten principles of Good Design to software. Not the end user product — much can be found about that — but to the source code.

Image of source code written in COBOL
Image of source code written in COBOL
(https://www.slideshare.net/pirhilton/beautiful-code-75527547)

Good design is innovative

“The possibilities for progression are not, by any means, exhausted. Technological development is always offering new opportunities for original designs. But imaginative design always develops in tandem with improving technology, and can never be an end in itself.”

Original BRAUN weighing scale (Tonarmwaage) used to define the correct counterweight of a record player’s tonearm
Original BRAUN weighing scale (Tonarmwaage) used to define the correct counterweight of a record player’s tonearm
Braun Tonarmwaage, 1962 (https://en.wikipedia.org/wiki/Dieter_Rams). Used to define the correct counterweight of a record player’s tonearm.

Our software source code need not be outlandish or complex to be innovative. In fact, it’s quite the opposite. Innovative source code seeks to discover the pattern of a problem, and solve the entire category in elegant ways. a² + b² = c² is innovative. It has immense implications, but it is not complex.

Likewise, higher-order functions like map or reduce are innovative solutions to the problem of changing a list of things into something else. These solve the category of iteration while remaining flexible enough to do virtually anything within that iteration.

React is another innovative design solution within code.

(@cowboy on twitter) inadvertently coined a very apt description at one time: “Rethinking Established Best Practices”. It has since gone on to have a tremendous impact on the Front-end community challenging us to reconsider what separation of concerns means for front-end and that we can think of user interfaces to be a pure function of the state.

Each of these advances leveraged the best technologies and ideas available to take the next leap in terms of developer interfaces. There are many more examples of innovative design in software and they all share a common thread. They each managed to simplify a concept in creative and approachable ways.

Good design makes a product useful

A product is bought to be used. It has to satisfy not only functional, but also psychological and aesthetic criteria. Good design emphasizes the usefulness of a product whilst disregarding anything that could detract from it.

Braun pocket calculator designed by Deiter Rams.
Braun pocket calculator designed by Deiter Rams.
ET 55 control LCD: Dieter Rams + Dietrich Lubs: 1983 (https://readymag.com/shuffle/dieter-rams/products/)

Of all Dieter Ram’s ten principles, this is probably the one that is most naturally adhered to, at least at first blush. Market forces tend to ensure that the products we build are generally “useful” in the sense that they fulfill a functional need that consumers have. However, Rams lists psychological and aesthetic aspects of usefulness that serve to draw users to one product over another. UX designers sometimes speak of “delight” and it is these psychological and aesthetic aspects which are being invoked.

In software development, code obviously must be functional, in the sense that it must function. But our source code can and should also be psychologically useful and aesthetically useful. Code that is overwhelming in complexity or volume is psychologically distressing and not particularly useful. Best practices such as restricting the scope of a file, function, or class to one purpose helps in limiting psychologically distress and using tools such as cyclomatic complexity linters will help to make sure new comers to a code base can quickly get up to speed.

Good design is aesthetic

The aesthetic quality of a product is integral to its usefulness because products are used every day and have an effect on people and their well-being. Only well-executed objects can be beautiful.

Universal Shelving System designed by Deiter Rams
Universal Shelving System designed by Deiter Rams
606 Universal Shelving System, 1960 (https://en.wikipedia.org/wiki/Dieter_Rams)

When we talk about the usefulness of source code, we are generally speaking of developers' ability to work within it. Rams says that the aesthetic quality of a product is integral to its usefulness. So what is aesthetic source code then? “Only well-executed products can be beautiful”, he says.

It is commonly said that code is read far more often than it is written. We read code to understand it. Like a well-written book, well-written code tells a story. But more than that, well-written, aesthetically pleasing code is clear, concise, and unambiguous. It focuses the eyes on what is important and seeks to eliminate noise.

Code formatters go a long way in helping to make aesthetically pleasing code. Prettier, a code formatting tool, even has it in the name. It promises to make your code “prettier.” Beauty, as they say, is in the eye of the beholder, but some things are more objective than others, and consistently and thoughtfully formatted code is always preferable to unformatted, inconsistent code.

Formatting only gets us so far though. Just as anyone can apply a set of design criteria to make something look less bad, it takes thought and skill to create something beautiful, something that elegantly satisfies our requirements.

One way to do this is to push edge case handling to the edges of the application. If/else statements, type checks, try/catches. These are not aesthetic. Control flow constructs such as these disrupt the flow of reading. They should be avoided where ever possible and minimized when not. Many patterns exist to help encapsulate and mitigate the need for control flow interruption such as Promises and Monads.

Good design makes a product understandable

It clarifies the product’s structure. Better still, it can make the product clearly express its function by making use of the user’s intuition. At best, it is self-explanatory.

A pocket transistor radio designed by Deiter Rams bearing a striking resemblance to the original iPod
A pocket transistor radio designed by Deiter Rams bearing a striking resemblance to the original iPod
Pocket transistor radio (https://www.lifeofanarchitect.com/who-is-dieter-rams/)

We all seek to write code that is understandable. We often refer to understandable code as being “maintainable.” Code that is difficult to understand is even more hard to maintain. Fear grows proportionally to the understandability of the code we are seeking to change it. Many books have been written on the topic of understandable code in an attempt to bottle the trick to consistently reproducing it. Some of them are useful. Many are not. The real trick is, there is no trick. Like so many things in life, it takes effort, practice, and intention.

One thing we all do is to document our code with comments that describe what our code is trying to accomplish. This is sometimes necessary, but when it is, it also represents an opportunity for improvement. After all, “at best, [our code] is self-explanatory.” Striving to write self-explanatory code is practicing good design.

Good design is unobtrusive

Products fulfilling a purpose are like tools. They are neither decorative objects nor works of art. Their design should therefore be both neutral and restrained, to leave room for the user’s self-expression.

FS 80 TV, 1964; A television designed by Deiter Rams.
FS 80 TV, 1964; A television designed by Deiter Rams.
FS 80 TV, 1964 (https://www.lifeofanarchitect.com/who-is-dieter-rams/)

Unobtrusive code gets out of the way. There are many ways code can be obtrusive to engineers. It can be laden with unnecessary syntax noise, excessive annotations, boilerplate, concept fatigue, or “magic.” But perhaps the most common form of obtrusiveness is bad abstractions. A bad abstraction is unclear. It is a puzzle piece that almost but doesn’t quite fit. So every use requires building up a little here, or shaving off a little there. A sure sign of a bad abstraction is the need for a growing collection of configuration options or arguments. Good abstractions, like good code generally, get out of the way to let you do your job. It presents itself as a useful tool that allows you to express what needs to be done, not an obstacle to overcome. There is always an element of learning, but if you find yourself routinely “wrestling” with your code, it is too obtrusive.

Good design is honest

It does not make a product appear more innovative, powerful or valuable than it really is. It does not attempt to manipulate the consumer with promises that cannot be kept.

Vitsœ 601 Easy Chair (1960) designed by Deiter Rams
Vitsœ 601 Easy Chair (1960) designed by Deiter Rams
Vitsœ 601 Easy Chair (1960) (https://gizmodo.com/10-iconic-dieter-rams-designs-from-a-store-that-sells-h-1045228746)

Have you ever had to work in a new code base that took months to be productive in? Navigating around opaque, obscure, or obtuse patterns and practices that require seemingly secrete knowledge of magic incantations to make things work? I have more often than I care to admit. So often in our efforts to “simplify” all we end up doing is creating “magic.” Magic is the enemy of good design. It calls attention to itself, not the work at hand. It is a form of misdirection and deception, actively hindering the understanding of what’s going on under the guise of productivity. It is a lie. Honest code can be followed. It leads from one call to another. Dishonest code masks its functionality behind build steps, generated files, and side effects. Dishonest code is handy-wavy.

Good design is long-lasting

It avoids being fashionable and therefore never appears antiquated. Unlike fashionable design, it lasts many years — even in today’s throwaway society.

Braun Clock (1985) designed by Deiter Rams
Braun Clock (1985) designed by Deiter Rams
Braun ABK 31 (1985) (https://gizmodo.com/10-iconic-dieter-rams-designs-from-a-store-that-sells-h-1045228746)

We have a problem in our discipline. We are obsessed with the new and shiny. What is the hot new framework, library, pattern? We chase these things as if it were the air we breath, but we give them little thought. We secede our thinking to the thought leaders, or the big organizations. It seems like the JavaScript framework fatigue has died down somewhat of late, but it has not been all that uncommon for full rewrites in new technologies to happen almost on a yearly cadence.

Products change. Business needs change. These are givens. The code we write should build in that expectation from the start. Our architectures, philosophies, patterns, and principles should not have to change with the market winds, they should be able to accommodate them. Paradoxically, code optimized for change, needs to change less often than code not anticipating change. It’s obvious if we think about it. If we anticipate change, we build in fewer hard assumptions. As assumptions inevitably change, the code is already able to adapt to it without having to first tear down the foundations. Code that is long-lasting, is built to anticipate regularly changing assumptions.

Good design is thorough down to the last detail

Nothing must be arbitrary or left to chance. Care and accuracy in the design process show respect towards the consumer.

HLD 4 Hairdryer 1970 designed by Deiter Rams for Braun
HLD 4 Hairdryer 1970 designed by Deiter Rams for Braun
HLD 4 Hairdryer 1970 (https://gizmodo.com/10-iconic-dieter-rams-designs-from-a-store-that-sells-h-1045228746)

Intentionality and purpose in everything is a challenge. There are as many ways to accomplish an end in code as there are engineers. To write well-designed code it is not enough to know that dictionaries, tuples, maps, linked lists, and trees are all data structures. One must also be able to choose the best one for the circumstance. Furthermore, one must be able to articulate why that is the best choice.

“If you can’t explain it to a six year old, you don’t understand it yourself.” — Albert Einstein

Do you import a library or write your own? Why this pattern and not that one? Do you use semicolons or rely on automatic semicolon insertion? Do you accept the defaults of your code formatter? Do you know why they are the default? Do you know what is being enforced? Well-designed code is not arbitrary. It is intentional from its architecture to its formatting. There is nothing wrong with accepting defaults, as long as you know what the defaults are and why they are.

This becomes more challenging the more people are involved. More people inevitably leads to conflicting perspectives. There is almost never a “right” choice, there are only tradeoffs. Intentional decisions recognize the tradeoffs and make choices with eyes wide open.

Good design is environmentally friendly

Design makes an important contribution to the preservation of the environment. It conserves resources and minimizes physical and visual pollution throughout the lifecycle of the product.

LE1 electrostatic speaker, 1959 designed by Deiter Rams
LE1 electrostatic speaker, 1959 designed by Deiter Rams
LE1 electrostatic speaker, 1959 (https://www.oobject.com/le1-electrostatic-speaker-1959/)

Sure, the actual code itself is all digital, but code is meant to be executed and that execution has a cost. Not only that, costs are not evenly distributed. Servers must be run, which takes a lot of cooling. Code is downloaded to browsers across networks of various speeds and reliability — often at a direct cost per MB to the one downloading it. Well designed code takes these costs into consideration

There is also visual pollution to consider. This is the noise that surrounds the signal. As mentioned before, code is read far more often than it is written. The denser the communication the better. Where there is lots of information not pertinent, or that could easily be derived from context, there is noise. Noise distracts us from the message, the logic of the code we are attempting to understand. Therefore, well-designed code is well-organized code. Well-designed code is annotated with comments or types only where necessary and only as much as is needed. It is wise to choose patterns that maximize communication and minimize distraction. Declarative code is dense communication, imperative code is noisy communication. “Take me to the airport” conveys the same information to an Uber driver as a long list of turn-by-turn directions.

Good design is as little design as possible

Less, but better — because it concentrates on the essential aspects, and the products are not burdened with non-essentials. Back to purity, back to simplicity.

L-2 speaker (1958) by Dieter Rams for Braun
L-2 speaker (1958) by Dieter Rams for Braun
L-2 speaker (1958) by Dieter Rams for Braun (https://www.lifeofanarchitect.com/who-is-dieter-rams/)

E=MC²

Einstein’s mass-energy equivalence equation is undeniably simple. It is beautiful, elegant, functional, and understandable. It is all these things because it describes its intent in the simplest way while still being complete. There are no if statements. No switch statements, temporary variables, or state. It is so simple, a child can comprehend it, yet it took one of the brightest minds of the 20th century to distill it.

Simple is difficult. But it is also beautiful. Well-designed code is simple. It takes thought, reworking, refactoring, and the ruthless elimination of the unnecessary to arrive at it. But once there, once the problem the code is solving has been distilled down to its essence. It is complete.

0*F7z2Y6kepZqOVLM5?q=20
dieter-rams-good-design-principles-applied-to-source-code-b21559969170
The UX Collective donates US$1 for each article published on our platform. This story contributed to World-Class Designer School: a college-level, tuition-free design school focused on preparing young and talented African designers for the local and international digital product market. Build the design community you believe in.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK