@radekmie
By Radosław Miernik · Published on · Comment on Reddit
I feel like all products I’ve been using daily for the past couple of years have decided to change their interface completely at least once within that time1. Sometimes it’s an improvement (e.g., PostHog). Sometimes it’s as bad as before but faster (e.g., Jira). And sometimes it’s just bad (no shots fired this time).
If you were on the other side, i.e., you were the one implementing it, you know it’s not an easy task. Of course, the scope of changes matters, as it’s easier to round all the buttons than change the color scheme2, but such changes often take way longer than anticipated.
Here are a few notes on how I’m doing it. Please note that I’m not a designer but a developer. But with a track record of going from Bootstrap 3 to Semantic UI to a custom design system within one app, I can say I have some experience3.
…even if it’s not a business requirement. While reworking the existing code may feel amazing – solving FIXME
s, getting rid of old workarounds, simplifying convoluted logic – it may also introduce new bugs your users will find amusing.
By making it opt-in (voluntarily or not), you can share the experiments with real users as soon as you have them, to gather some valuable feedback. If you’re not allowed to impact the actual users, try to convince your team to release it in a way that everyone could access it somehow.
No need to reach for the Konami Code straight away, but an additional parameter in the URL, a dedicated cookie, or a profile’s name containing a special sequence will do just fine. It doesn’t have to work perfectly (e.g., may require a refresh); in the end, that’s just an experiment anyway.
On the code side, you can be lazy cautious, and do the following:
X
component you’d like to rework to X_old
.X_old
instead of X
.X_old
use X
, if the user opted in for the change.In React it could look like this:
+import { Foo as NewFoo } from '../Foo';
-export function Foo({ ... }: FooProps) {
+export function Foo(props: FooProps) {
+ if (userHasOptedInForNewFoo(props)) {
+ return <NewFoo {...props} />;
+ }
+ const { ... } = props;
+
// React code...
}
(Some of you may find the above trivial, but based on how many developers were amazed by it, I decided to share it anyway. It’s one of those “ground truths”, I think.)
Remember to git commit
before altering X
! This way, there are no changes in X
itself – the app is now using the freshly copied X_old
, and X
can be altered in the next steps. Once you are done, make the app use X
again. This way the history of X
is preserved and easily backtrackable4. If you need to fix a bug, you can still work on X_old
in the meantime.
…even if it’s not a business requirement. I bet most people reading this post are not the ones responsible for the new designs. As your users will be happier about the new interface if it’s faster than its predecessor (even if they have to re-learn it over the next few weeks), you should aim for that.
This is also a good testing ground for trying out new technologies of all kinds. New browser API you could replace an outdated package with?5 New library you wanted to try out? New analytics tool you configured last year, but never sent anything to it? That’s your moment!
If none of the above apply, at least try to make the new code better in some way. And if it was perfect before (it wasn’t), just write more tests. ’Cause you do have tests for it, right?
…even if it’s not a business requirement. If it is, well, I hope it’ll work out! But jokes aside, refactoring should be the time when one deals with the mistakes of many before them. It’s one of the very few moments you can actually reflect on why it was done like this, and why you can do better this time.
Was it a lack of skill or knowledge? Was it a limitation of the technology at that time? Or maybe the requirements have changed since then? Whatever the reason was, I believe that is what makes a solid developer. I believe that the best way to learn is to deal with the consequences of your own decisions.
And don’t forget about your colleagues; especially the less experienced ones. Redesigns are rarely done on a tight schedule and are often well-defined (even if it’s just “It should work as before.”), which makes them perfect for learning6.
Redesigns are always a challenge for everyone – the teams budgeting them, the teams implementing them, the teams marketing them… But they’re also an opportunity for an organized growth; both of the project and the people. Try to make it worthwhile, even if you are at the very end of the decision chain.
Every removed FIXME
counts… I added two today, so I’d better get going!
Fun fact: a lot of these were caused by the European Accessibility Act. And another one: most apps were late by a week or so. But I live in Poland, not in the US, so suing them will not make me any money.
As long as it’s only about colors. The second it revolves around colors because it’s an accessibility topic, it gets way harder.
Of course, there were others in the meantime, but it sounds more impressive to migrate one app twice rather than two apps once. It does to me, I mean.
While we’re at it, I also recommend adding some sort of identification of decisions to your commits. For example, if you’re using some issue tracker like GitHub Issues or the aforementioned Jira, adding issue identifiers makes git blame
a logbook of decisions. Assuming your issues are well-written, of course.
Have you seen the Popover API? That’s one of my favorites in Baseline 2024. I won’t be able to use it for the next few years, though.
Either “learn” as in “learn React” or as in “learn how to deal with larger tasks”.