Lipstick on a Pig: learning the most important lesson in design
I just released a little tool called Lipstick on a Pig that helps keep the visual appearance of supported command-line applications in sync with the current light/dark mode setting (colour scheme) of your system in GNOME.
But why is this tool even necessary to begin with?
Let’s start at the beginning…
Getting to GNOME you
The GNOME display environment1, since version 42, implements support for light and dark appearance styles (aka colour schemes).2
With a GNOME extension like Night Theme Switcher, you can even automate the switch from light mode to dark mode based on time of day (or toggle it manually using a button in the system bar).3
Furthermore, newer terminal applications like Black Box follow GNOME’s colour scheme and automatically switch between their light and dark themes for the console and its content.
This is all great and it means that you can, for example, have your computer switch automatically to dark mode at sunset and have your terminal adapt to it automatically.
The immediately-obvious problem is that very few command-line applications adhere to the terminal’s theme, choosing to override it with their own theme settings, which, rarely (if ever) take the system’s colour scheme setting (light/dark mode) into consideration.
But is this the right problem to solve?
And is the command-line application layer the right place to solve it?
(Surely, I must think so because that’s the problem Lipstick on a Pig solves, right? Not really, no, read on…)
Solving the wrong problem
Think about it: The only reason command-line apps implement theme support is because they cannot rely on terminal apps to do so consistently.
If every terminal app in the world had consistent support for themes, command-line apps could just render their output, happy in the knowledge that it would get rendered in the person’s chosen theme.
So is the terminal app layer the correct place to define our problem?
The fact that every terminal app would have to implement theme support should be a hint that it’s not. That’s a lot of duplicated effort. (And last I checked there wasn’t a standards body for terminal apps, nor do I think we’ll see one anytime soon given they’re not exactly – unlike the web, say – a huge industry.)
So let’s look for the problem one layer higher in the stack, in the display environment/operating system layer.
Is the core problem that the display environment/operating system does not have support for text themes?
How do we know that this is the right layer to define our problem at? We know because if we define it at this layer, solving it will also solve it at the terminal app and command-line app layers.
Now that we know where to solve it, articulating the design problem becomes much easier:
“How do we ensure consistent syntax highlighting of text on an operating system that adheres to system colour scheme changes.”
So the ideal solution to this design problem would be for the theme settings that currently reside in a terminal app such as Black Box to instead exist in the Appearance settings of GNOME itself and for every app running on the system, including terminal apps, to use them when rendering syntax-highlighted text.
Were this to be implemented, it would mean terminal apps and command-line apps would no longer have to implement custom theme support themselves.
Which brings us to…
The most important lesson in design
The most important lesson in design is that design does not begin at solving a problem. Design begins at understanding what the right problem to solve is. Which means we must uncover where the problem actually is.
Most times, bad design (which results in tools that are unusable, overly complicated, etc.) doesn’t arise from solving a problem badly (although this can, of course, happen) but from solving the wrong problem.
This was the central thesis of my talk, Superheroes and Villains in Design, that I gave at Thinking Digital Conference in Newcastle almost a decade ago. I’d highly recommend you watch it, especially if you’re working in free technology. It’s more important than ever that the free and open alternatives we build today are not only ethically-sound but accessible, usable, and maybe even – heck, why not? – delightful. That’s the only way to ensure that people will actually use them. The Ethical Design Manifesto and Small Tech Principles can guide you in achieving this.
In the talk, I recount my less-than-delightful experiences trying to buy a ticket on the San Francisco Bay Area Rapid Transit (BART) system. While you can watch the video for all the hilarious details, suffice to say the folks who designed the BART ticketing system solved the wrong problem. They solved the problem of “How do we sell a ticket?” not the problem of “How do we get someone from point A to point B as effortlessly as possible.” If they had solved the latter problem, the confusing ticket machines would either look very different or perhaps not even exist at all.
Another example I give in the talk is that of a whole class of everyday devices that solve the wrong problem: washing machines. Nearly all washing machines today solve the problem of “washing clothes.” This is a problem nearly no one has (unless you wash clothes for a living or have a particular enthusiasm for the craft). However, nearly all of us have the problem of having dirty clothes we want to be clean. While they may at first appear to be the same problem, they’re not. These are two fundamentally different problems. Conflating them is the reason we have washing machines today with a plethora of settings that almost no one really understands instead of machines with almost no controls that you dump your clothes into and get clean clothes out of. (Hands up if you set your machine to the one or two settings you know work well enough and leave it at that.)
I won’t go into it again here as, in the talk, I sketch out what a washing machine would look like if it solved the right problem.
Spoiler alert: it comes out looking nothing like any washing machine you’ve seen.
Solving the right problem
So, to get back to the case in hand, the correct design problem we should be solving is how to ensure that any app on a system that renders syntax highlighted text does so consistently with every other app and in accordance with the system’s colour scheme settings.
Understanding the problem and understanding what level a problem should be solved at are inextricably linked.
We now understand that this problem cannot be solved at the level that Lipstick on a Pig solves it. (Now do you understand why I chose the name?) Therefore, we know that Lipstick on a Pig is not a design solution. Lipstick on a Pig is a hack; a pragmatic short-term workaround; a stopgap.
It’s very important that we don’t conflate hacks and pragmatic workarounds with actual solutions. The former are not without value. In fact, they might keep things ticking along for quite a while. But the moment we forget that they’re just temporary band-aids, we run the risk of incorporating them into our stacks and thereby weakening the foundations of those stacks. Where Murphie’s Hierarchy of Hacks goes, Murphy’s Law is usually not far behind. We eventually end up with brittle structures that can no longer be evolved or iterated upon without other parts of them collapsing, leading to complete rewrites or failure and abandonment of the systems for better alternatives.
Lipstick on a Pig
The problem Lipstick on a Pig solves is “how can we synchronise the visual appearance of command-line apps that implement their own theme systems with system colour scheme changes to provide people with a consistent/legible/readable experience.”
This complexity of the problem statement itself is the first smell that we’re solving the wrong problem at the wrong place.
And I’ve already baked in so many incorrect assumptions based on my belief (right or wrong, as it might be) on the difficulty of effecting change in the other layers in the stack.
I know that command-line apps should not be implementing their own theme systems (the operating system/desktop environment should). And I know that terminal apps should not be doing this either (because, again, the operating system/desktop environment should). I also know that by solving the right problem at the right layer in the stack4, it would create less work for – i.e., solve the problem for – all lower layers in the stack.5
And yet I’m releasing Lipstick on a Pig today instead of doing any of those other things.
Because getting people to care about consistency is hard.
And getting people to care about consistency in free/open source is even harder.
We still have an uphill battle even to get a desktop environment like GNOME to adhere to its own colour scheme settings. Why? Mostly because some folks like how something looks, consistency be damned.
GNOME has even formalised this inconsistency by not just having a light and dark mode but a “mixed mode.”
What’s mixed mode?
Quite bluntly, it’s an example of bad design (complexity and inconsistency) born out of a culture where design is still, to some extent, not practised from first principles but is subject to the aesthetic whims and fancies of individual developers and the compromises they (often times reluctantly) reach between themselves.6
It’s important to understand that these issues do not merely concern aesthetics and that they must not be driven by vanity. If someone has their system set to light or dark mode, there may well be important accessibility-and-usability-related reasons for doing so. So, beyond consistency (which itself lowers the cognitive load of the entire system), not respecting a system setting like light or dark mode is a perfect example of not respecting the people who use the tools we make. We must constantly remind ourselves that our preferences as developers do not override those of the people using the things we make.
On pragmatism and landfills
While I hope that the solution to the correct design problem in this case can be implemented at the correct layer in the stack, we must also be pragmatic. Sometimes all we can do is to implement a sub-optimal workaround (like Lipstick on a Pig) at the wrong layer in the stack.
One that we, ourselves, have control over.
I believe folks call this “pragmatism.”
(This is a concept I am trying more heartily to embrace these days in lieu of exotic expeditions to explore the spiralling depths of confrontation and bike-shedding and regular visits to the chasms of utter hopelessness and despair.)
And yet, even as I write this, I’m painfully aware that such “pragmatism”, alone, explains so much of how bad design comes about and why sometimes it‘s easier to start from scratch rather than to continue building on a system that is comprised of a landfill of hacks and workarounds.
X11, I’m looking at you, kid.
It also should hold a candle to what you can do in your own organisations to ensure that you don’t end up with a landfill on your hands: ensure designers have the responsibility and authority to affect change at any layer of the organisational stack.
And create a culture where design conversations take place from first principles, not personal preferences.
A map of solutions
So Lipstick on a Pig tackles the wrong problem at the most pragmatic and most sub-optimal level possible.
(Yippee! Don’t we all feel better now?)
It requires hacks to be implemented for individual command-line applications and thus has a potentially infinite problem space. This is literally the worst possible place to fix this problem and yet it is also the only place where I can fix it without engaging in (the often times frustrating process of) getting large open source projects to implement design changes.
And yet, if I didn’t believe that these things can change, I wouldn’t be writing this (admittedly rather lengthy, at this point, apologies…) treatise to accompany the launch of a simple little tool.
I do hope that in writing this I might influence those who have control over the more optimal layers of the stack to implement better solutions there. But I don’t have the time or wherewithal to fight those battles myself. I have my own projects – like Domain and Kitten – that I’m working on as a solo developer and they take up almost all my time. Even writing this feels like a luxury I can scantly afford right now while bigger problems remain unsolved.
With that goal in mind, here is a map of solutions, organised by whom it would require buy-in from.
1. Terminal app developers
One step up from Lipstick on a Pig would be to fix the problem at the terminal app layer while still essentially implementing the same technique Lipstick on a Pig uses with light and dark mode configurations for individual command-line apps.
A terminal app like Black Box, for example, could listen for system colour scheme changes and call the corresponding light or dark script. This would remove the need for Lipstick on a Pig and reduce the problem to one of configuration (you would still have to keep your light and dark scripts updated for the command-line apps you use).
Still suboptimal, but better.
2. Terminal app developers and command-line app developers
If we’re willing to open up the social effort required to implement a solution, we can stay at the terminal app layer and implement something better.
The terminal app could set an environment variable (maybe one that’s even eventually standardised by freedesktop.org) like
$XDG_TERMINAL_HANDLES_THEME. Command-line apps could, then, easily implement support for light/dark mode by checking for this environment variable and, if it exists, disabling their own theme support to use the system theme.
This solution is much better in that it could, eventually, lead to command-line apps not having to implement themes themselves if enough terminal apps adhered to the standard. This is the second-best solution, and likely the best compromise between purity and pragmatism, given how difficult it would probably be to get GNOME to implement the optimal solution. (If past performance is any indication of future behaviour, I’m likely going to get chided just for writing this. Mais, c’est la vie, non, mes amis?)
3. GNOME developers
Finally, to reiterate, the ideal solution would be for the operating system/desktop environment to implement a solution that can be used not just by terminal apps but by any app that display text with syntax highlighting (e.g., code editors with graphical interfaces).
Until then – or until one of the more optimal solutions outlined above are implemented by others – I hope you’ll find Lipstick on a Pig useful as a stopgap.
And, before you rush off to solve a design problem, remember to always ask yourself the most important question in design:
Am I solving the right problem at the right place?
Like this? Fund us!
Small Technology Foundation is a tiny, independent not-for-profit.
We exist in part thanks to patronage by people like you. If you share our vision and want to support our work, please become a patron or donate to us today and help us continue to exist.
Used by operating systems like Ubuntu, Fedora, etc. (Linux is confusing like that.) ↩︎
GNOME’s implementation of colour schemes is currently not holistic. Which is a nice way of saying it’s inconsistent and not very well supported by interfaces within GNOME shell itself. For example, if you want to create your own custom wallpapers for light and dark mode, you have to use GNOME Tweaks. ↩︎
The ability to schedule colour scheme changes based on time of day, having colour scheme changes animate smoothly, and having an easy to reach control for changing the colour scheme manually – in other words, basically everything the Night Theme Switcher extension does – are features that should really be added to GNOME itself and presented with intelligent defaults (e.g., switching to dark mode at sunset). ↩︎
Note that “the stack” does not necessarily just mean a technology stack. It includes socio-economic layers. While we’re mostly looking up and down the technological stack here, it’s quite possible that a wider analysis of a problem will reveal that the correct design solution must be implement in a non-technological layer. It may require, for example, changing the business model of an organisation. If you reach the top of the technology stack and you still cannot find an optimal solution to the problem, that’s a pretty good tell that the design problem (and therefore the solution) is at some higher, non-technological layer. In many ways, these are the hardest design problems to solve. Mostly because, in most organisations, problems at these levels are not seen as design problems and designers do not have the necessary authority or responsibility to tackle them. ↩︎
Were GNOME to implement system themes for syntax-highlighted text for light and dark modes, all apps – including terminal apps and all command-line applications – could consistently adhere to them without doing anything at all. Think of all the code (and thus complexity) removed from the equation were that to happen. ↩︎
Although this has gotten immeasurably better in recent years with the effect of folks like Tobias Bernard. ↩︎