About Jim Nielsen

Designer. Engineer. Writer.20+ years at the intersection of design & code on the web.

The RSS's url is : https://blog.jim-nielsen.com/feed.xml

Please copy to your reader or subscribe it with :

Preview of RSS feed of Jim Nielsen

Prompting the Wrong Question

2024-10-17 03:00:00

So there I am, working on a bug exclusive to Safari (we’ve all been there). I can’t figure it out so I ask AI, “Hey, this piece of code is not working in Safari, what’s wrong?”

The issue might be related to how Safari handles keyboard events, especially for certain keys…

It gives me some advice:

I’ve been staring at this problem for a minute, so I’m 99% sure none of those suggestions are of any help. I double check my work, but still the bug persists.

So I tell AI those suggestions don’t work. It responds by saying I may need to go to a “lower level”. It recommends:

I’m skeptical — but I’ve been wrong enough to doubt my skepticism. So I try that, but no dice.

I continue my conversation with AI. It recommends:

I don’t want to do this. What I’m trying to achieve I’ve seen done by a million and one other websites. They don’t do something special just for Safari, I shouldn’t have to either.

So now I’m getting a little testy in my prompts: “Do you have any other suggestions? You keep recommending the same ones over and over. It has to be something else.”

I apologize for the repetition. Let’s try a different approach…

Ok, I like the sound of that.

It begins telling me to register different events in a useEffect hook.

“Hm…that’s a little crazy town” I think to myself. But again, I’ve been wrong before. Plus who really knows how useEffect works anyway, maybe it’ll work? Plus this thing has the context of the entire internet, right? (Actually not sure if that’s a good or bad thing…)

No dice with useEffect.

I continue conversing with AI but it keeps spitting back the same suggestions wrapped in different language. Over and over:

I apologize for the repetition. Let’s try a different approach…

Eventually I give up.

I turn to humans for help. I ask a co-worker to take a look. He tries a few things, but still nothing. But then another co-woker says one of our fixes is working for him!

That starts us down the path of: what OS are you on? macOS Sonoma? Hey, me too. What version of Safari? Hmm…we’re on different minor versions of Safari. Shouldn’t be enough to warrant this big of a discrepancy? Then I turn inward, “It must be something about me, something specific to my browser…”

I stare blankly at my version of Safari. I’ve been here before — works fine for everyone else, but not for me? That can mean only a handful of things, one of which is…EXTENSIONS!

I only have a few installed, but I turn them all. Boom! Bug gone.

So the problem all along was an extension?! [insert sad trombone sound here]

AI kept taking me down this narrow hole of rewriting event listeners. Never once did it suggest, “Have you considered that perhaps the issue lies with you specifically, dear human?”

Surely there’s enough internet context for it to think: have you tried disabling extensions in the browser you’re testing?

I am not an expert in AI/LLMs. I would venture to guess the problem here is one of context. I set the context of the problem for the computer, and it stayed within the confines of the problem I gave it.

“Why doesn’t this code work in Safari?” I asked.

It never responded with, “Perhaps you are asking the wrong question.”

It’s a tricky thing — even for humans like myself — to pause, take a step back, and challenge the very premise of the questions we’re asking.

I felt so silly when the whole thing was resolved. If I had a nickel for every time I’ve been asked, “Have you tried disabling extensions?” I wouldn’t be here writing this blog post about fixing bugs during my day job because I wouldn’t have one.

But the lesson here (for me) remains: don’t forget to challenge the very premise of the questions you’re asking.


Reply

Prototyping Magic Tricks and Software

2024-10-15 03:00:00

In Penn & Teller’s Masterclass (no. 12 “Principles of Performing”) they explain how one of their favorite ways to design a magic trick is to come up with an idea and then act it out as if they already know how to do it. Here’s Penn:

We still start with an idea for a trick, how we want the whole thing to go without knowing how we’re gonna do it…Some of our best tricks have come from [this way of designing a trick]. [We like to] do the trick as though we didn’t have to do any trick. Just walk through it. Just go out there like the trick is going to work…We want to go out, have a card selected, know what it is, put it down, have a knife go through Penn’s hand, and there’s the card with blood coming down. Let’s just do that, like theater. Let’s just go through and act it.

To borrow parlance from digital design work, I would call this “prototyping a magic trick”.

The beauty of this approach, which Penn points out, is that you uncover aspects of the design of the trick by acting it out (hint: that means it’s “design” work).

For example, during the trick you may need to stealthily conceal something. It could be really hard to think about when and how you’re going to fit that into the trick. But, if you just start acting the trick out, you may discover that at a particular moment in time during the trick your hand naturally goes into your pocket. Eureka! Now you don’t have think about when and how you’ll conjure a moment for concealing, as you’ve instead uncovered how and when it falls naturally into the act.

Similarly, you may think you need something in the trick like a particular moment in time to shuffle the deck. And you could spend a lot of time thinking about how and when you’ll fit that in. But, as Penn notes, if you just start acting it out like theater (as if the trick worked) you may discover that there’s no need to shuffle the cards at all — in which case you’ve solved the problem by simply eliminating it.

So by acting out the trick, as if it worked, you discover things along the way you wouldn’t have thought of. And that discovery then informs the design of the trick.

This is the value of prototyping: you don’t have to figure everything out beforehand. You pick a place to start and let the natural process of problem solving birth the design of what you’re trying to make.

We think we can: 1) define a problem, 2) design a solution, and 3) implement it.

But the truth is: it’s difficult to define a problem without also beginning to solve it. “Implementation” is part of the problem definition phase — that’s why teams that go “define -> design -> implement” inevitably find things they couldn’t anticipate which then pushes back timelines because they thought they were almost done.

You have to start working on problems to fully understand them — and prototyping is a beautiful way to do that.


Reply
Tags

Grateful: Colors in console.log()

2024-10-10 03:00:00

So there I am, having an issue where my UI state isn’t updating correctly. What do I do? What every developer does: turn to console.log() and troubleshoot by logging values.

I have a named color (e.g. blue) and a corresponding HSL color string for that named color (e.g. 100 50% 0%). I log those in the click handler function where I expect the color to change.

onClick={() => {
  // Some stuff...
  
  console.log(
    `theme change: ${colorName} ${colorHslString}`
  )
}

Then I go click around in the UI and observe the bug. The problem is, when I look at the console to see if what the UI is doing matches what the code is doing, it’s impossible to tell. The values are indiscernible because I can’t read HSL.

Animated gif of a mouse clicking an orange button, then a purple button, then back to the orange button and the console logging HSL color string values each time it gets clicked.

Do you know if 262.1 83.3% 57.8% is “violet” off the top of your head? Well I don't.

Then this vague memory hits me: can’t you log something to the console with a bit of color? Sure enough, I find a reference in my notes!

So I update my console.log() statement to style the log statement the same color value it’s logging, making it super easy to visually diff!

console.log(
  `%c theme change: ${colorName} ${colorHslString}`,
  `color: white; background-color: hsl(${colorHslString})`
);

Now when it says “violet” it should actually paint a color that looks like violet. Here’s what debugging looks like under this scenario:

Animated gif of a mouse clicking an orange button, then a purple button, then back to the orange button and the console logging HSL color string values each time it gets clicked that are styled with a color.

Yes! That’s super helpful. I can see the color name being logged doesn’t match the color value. That gives me a really good sense for where the bug is.

I look at the code, fix the bug, then go back to the UI and test again:

Animated gif of a mouse clicking an orange button, then a purple button, then back to the orange button and the console logging HSL color string values each time it gets clicked that are styled with a color.

Boom! It works.

So I’m expressing my gratitude for being able to style console.log statements!


Reply
Tags

Ryan Dahl Talks Deno on The Changelog

2024-10-08 03:00:00

Ryan Dahl was on The Changelog to talk about Deno 2 specifically and his work on JavaScript more broadly. What follows are a few things that stood out to me.

His Regrets From Node Are Now in Deno

I think it’s interesting that Ryan’s famous talk 10 Things I Regret About Node.js served as the manifesto and launching point for Deno. And yet, he’s now re-introduced some of those regrets into Deno — out of practicality, a point he openly admits in the interview.

For example, here are some of his stated regrets from Node.js:

Regret: package.json

It's unfortunate that there is centralized (privately controlled even) repository for modules.

And now Deno has spawned a registry: JSR.

If only relative files and URLs were used when importing, the path defines the version. There is no need to list dependencies.

I loved this about the original version of Deno. No need for a package.json because package version info was in the module URL. But they’ve been moving away from this. Which leads me to:

Regret: require("module") without the extension ".js"

Needlessly less explicit.

Adjacent to his point about package.json, if you use relative paths or full URLs, all the info you need is in the string: package name, version, extension, etc.

But alas, it seems like these purist principles weren’t enough to sway folks, though I’m not sure if that’s simply because of the legacy convention and baggage of Node itself. Out of practicality, many of Ryan’s “regrets” about Node.js have made it into Deno and I appreciate his honesty in conceding the point (and his ability to articulate a rationale).

Play to Your Strengths

Jerod asks Ryan a great question: instead of building something new and different with Deno, why not concentrate your efforts in making Node.js better? Ryan’s response:

I’m not willing to sit in committee for 13 years trying to make [what we built into Deno by default] happen

He’s referring to all the base infrastructure around Deno, such as:

Ryan believes JavaScript continues to merit modern enhancements because, give its ubiquity, its such a core part of humanity:

JavaScript is not like other programming languages. It is the default programming language because so much human infrastructure is built on the web. And because JavaScript is like HTTP or CSS or HTML, it is one of the protocols of the web. It has a future unlike that of Swift. Lots of people use Swift. A lot of infrastructure is built on Swift. But it’s not like JavaScript. JavaScript will be here in 5 years, if not 10, if not 20, if not forever. It is deeply embedded in humanity at this point. And I think it is worth the effort to strive to make it simple.

It’s an intriguing thought that pokes at the tension between the idea of being a revolutionary vs. trying to change a system from within. We all only have so much time and we have to ask ourselves where that time is best spent based on our own faculties, strengths, and weaknesses.

Maybe you have strong political sensibilities and could make sweeping changes inside an established organization. Or maybe that’s your weakness and you’d be better off in the wilderness developing your ideas, which perhaps never fully develop into their own, self-sustaining platform or organization, but they may spread and infiltrate into the existing systems of your time and find root there.

Everybody has to find their own path. I can appreciate Ryan articulating the rationale for his (and Deno’s) — even though I’m still kinda sad about the module stuff tbh.

Last, But Not Least: Free JavaScript

You can sense Ryan’s passion for JavaScript which overflows when he talks about his initiative “Free JavaScript”.

Did you know Oracle owns the name JavaScript as a trademark? So, for example, nobody can have a conference called “JavaScript Conf”.

It seems kind of ridiculous when you think about it. Can you imagine some corporate entity owning the name of a core web technology? Like if Apple owned "HTTP”, or Google owned “HTML", or Microsoft owned "CSS”? That’d be absurd.

I already signed the petition.


Reply
Tags

“Easier and More Convenient” They Said…

2024-10-05 03:00:00

Comic of a woman at a ticket train ticket counter where the attendant tells her “OK, one more time: Go home and log on to our website from your computer, create an account and purchase your ticket with your credit or debit card, download the ticket to a smartphone, then come back at the allocated time... Just what part of easier and more convenient' don't you get?”

The other day in our morning rush before school my wife asked for help figuring out how to put lunch money on our kids’ school accounts.

For some time she’s been doing it “the hard way”: talk to the people in the front office of the school every few months and swipe a credit card. Every time she did it, they would remind her there was an “easier and more convenient” way to do it via an app. But that seemed like the hard way of doing it: find an app, download it, create yet another account (and another password to remember), enter a credit card, etc. So she asked for my help.

First I had to find the app in the App Store. This sounds like an easy task, but all I had was the name of a generic, three-letter service. Have you tried searching for an app with a generic name in the App Store? The results are legion, and you have no heuristics for gauging the authenticity of the app. To be honest, this was an app for a county lunch school program, which means it would probably look and feel like a phishing scam.

Once I finally found the app and verified with my wife that it was the one the school uses, I began the rest of the process: download and install the app, create an account and password, enter my credit card info, and tie my children to the account. I assure you, it was not “easy and convenient”. And when I was done, I was told it would take up to three days for the money to show on my account — and my kids needed lunch that day. Would they get it? Who knew!

So an instantaneous digital transaction would take a few days for servers to register it. Meanwhile I thought, “cash seems like a really innovative invention right now…”

And when I was all done with the task, the app had the nerve to ask me how my “experience” was. Experience? That was not an experience. Our family vacation we took this summer to Canada, that was an experience. What I had with this app was an ordeal.

Come to think of it, that’s the terminology product teams should be forced to use when they solicit people via email — “How was your ordeal with us?” Perhaps folks would reframe how many people view their service: as a task to be completed as soon as possible. And once we complete it, we forget about the app and move on with our lives.

Grumpy McGrumpster today with this post, I know.

These thoughts spur from this great article “Nobody wants to use any software” (hat tip to Eric Bailey’s newsletter), which states:

We don’t need to delight people in the software itself. Delight in software is almost always a delay.

The delight most people are looking for is outside of the software we’re building. Best to get them on their way, away from our thing, and on to the delight they’re looking for — their children, a walk through a field, a cookie and some milk, playing a tune on the guitar, whatever.

In my case, it was “just let me put some lunch money on my kids’ account” so I can get in the car and take my kids to school, talking Pokémon along the way and resting assured that they’ll have something to put in their belly when lunch time comes.


Reply

Putting the “Person” in “Personal Website”

2024-10-03 03:00:00

The other day I saw a meme that went something like this:

Isn’t it crappy how basic human activities like singing, dancing, and making art have been turned into skills instead of being recognized as behaviors? The point of doing these things has become to get good at them. But they should be recognized as things humans do innately, like how birds sing or bees make hives.

I thought about that for a minute, then decided: making websites should be the same!

The original vision for the web, according to Tim Berners-Lee, was to make it a collaborate medium where everyone could read and write.

Social media sort of achieved this, but the incentives are off. And it’s not just about ownership of the content you produce and who can monetize it, but the context in which you produce it. Mandy nails this in her recent piece “Coming home”:

While one of the reasons oft declared for using POSSE is the ability to own your content, I’m less interested in ownership than I am in context. Writing on my own site has very different affordances: I’m not typing into a little box, but writing in a text file. I’m not surrounded by other people’s thinking, but located within my own body of work. As I played with setting this up, I could immediately feel how that would change the kinds of things I would say, and it felt good. Really good. Like putting on a favorite t-shirt, or coming home to my solid, quiet house after a long time away.

Yes! This is why I believe everyone could benefit from a personal website. Its form encourages you to look inward, whereas every social platform on the internet encourages you to look outward.

A personal website has affordances which encourage you to create something that you couldn’t otherwise create anywhere else, like YouTube or Reddit or Facebook or Twitter or even Mastodon. Why? Because the context of those environments is outward looking. It’s not personal, but social. The medium shapes the message.

If I were to put this in terms of a priority of constituencies, it would be something like this:

Additionally, a personal website and a social platform are two different environments: one I’ve cultivated, the other I’ve been granted. As Mandy puts it:

[having a personal website] allowed me to cultivate the soil to suit my purposes—rather than having to adapt my garden to the soil I was given

Like dancing or singing, you don’t have to be skilled to do them. Personal websites should be the same. They’re for everyone. Like dancing and singing, their expression can be as varied as every individual human.


Reply

Randomness, Serendipity, and an “I Wouldn’t Recommend This” Algorithm

2024-09-30 03:00:00

Sean Voisen has a great post about 1) how we as humans think of randomness, 2) how computers simulate randomness, and the difference between the two.

He puts forth an intriguing thought: in a world increasingly driven by computation, how does that affect randomness in our lives? Here’s Sean:

We could all benefit from more randomness in our lives more than we may realize. By veering off the beaten path, by being exposed to new things we would otherwise never expose ourselves to, we increase the possibilities for serendipitous and creative encounters. But our increasingly computationally-dependent world is fundamentally incompatible with allowing this to happen.

Be exposed to things we would otherwise never be exposed to? That sounds like the antithesis of the algorithm.

The algorithm is: “You liked that? I bet you would like this!”

But where is an algorithm that says: “You liked that? I bet you would never choose this — but here it is anyway!”

I have to admit, I have a number of things in my life where I could say, “I would have never chosen ____, but it’s been one of the best things in my life!” Many things I would’ve never chosen, yet they came to me, and they’ve changed my perspective and outlook and my life.

Where’s that algorithm?

I suppose it’s hard to make money off of, “Here’s some stuff you would never choose for yourself.”

So, where possible, I like the suggestion to make room for randomness in your life — and that might just mean stepping away from the pseudo-randomness of the computer more often.


Reply

Blogging & Listening

2024-09-23 03:00:00

When you read a great blog post, the feeling you often get is: “I already knew this, I just hadn’t been able to express it!”

In this sense, writing a great blog post is about listening.

If you’re listening — to others, your coworkers, the people you follow, your own experiences, your users, etc. — there are undertones of something being said collectively. If you can hear it, write it down.

People convey important things without stating them explicitly. When those unstated things resonate with you, write them down and publish them.

Other people may love what you write because it resonates with what they’ve been feeling and hearing. It’s both validating and clarifying!

So if you don’t know what to blog about, listen. Listen to what you hear and write it down. I doubt you’re the only one hearing it, but you can be one of the few writing it down.


Reply

Estimated Reading Time Widgets

2024-09-18 03:00:00

Beware ye who enter, here be personal opinions.

I’ve never understood reading time estimation widgets. Why did these get so popular? Is it because they’re easy? I mean, you can grab one off npm no problem.

Screenshot of a large number of search results from npm for the keyword “reading-time”.

Baldur suggests a theory in his piece about estimated reading times:

At some point a programmer read in a study that the average person read 233 words per minute and decided that this would be a great way to estimate reading time for everybody on the fucking planet.

The “reading time” for an article always felt so personal to me. As Baldur also points out, it can be affected by so many variables, such as:

Because I’ve always seen reading time as such an incredibly personal thing, I’ve never once paid any heed to these widgets. In fact, I’ve been slightly perturbed a service would presume to know how quickly I could read an article.

That’s to say nothing of the fact that if I come to a text to understand it (or merely enjoy it for that matter), speed is the very last thing on my mind.

I’ve always viewed any service that sticks a “reading time” widget on its articles as the literary equivalent of fast-food: you’re not here for quality, but for expediency.

Personally, I think they devalue a text more than they add to it.

But hey, I’ll grant that’s just like, my opinion, man.


Reply

The Ruthless Edit

2024-09-17 03:00:00

Rick Rubin gives this advice about working in the studio with artists when making an album:

[Let’s say] We’ve recorded twenty-five songs. We think the album is going to have ten. Instead of picking our favorite ten, we limit it to: “What are the five or six we can’t live without?” [So you] go past the goal to get to the real heart of it, and then you say: “Ok here are the five or six we can't live without, now what would we add to that which makes it better and not worse?” It puts you in a different frame when you start with building and not removing.

I love this! So often in design, engineering, or product, you’re faced with this decision: how do we pare down what we have to something that feels like a cohesive whole?

The impulse is to ask, “Well what do we have to cut it down to?” Then, knowing the limit, you pick your favorites until you hit it.

But that impulse overlooks the fact that things don’t exist in isolation. They exist in relation to each other. So if you’re merely picking your favorites up to an arbitrary limit, you’ll be left with a whole whose individual pieces are great but don’t sum to anything greater.

This particular course of action creates a mindset where there is no more “creation” only “deletion”. You go from a mode of “creating” to a mode of “editing” but you never look back to creating.

Instead, Rick recommends this idea of a “ruthless edit” where you go beyond your initial limit, then shift back to “creating” mode.

If the limit is ten, you choose five. Then you switch from editing back to creating begin asking: how can we add back in a way that elevates the whole? This encourages you to not merely selecting things based on their individual merits. Rather, you select a core set of things that carry the thrust of what you’re trying to do and then you add complementary things around that core to bolster the very things you loved so much in the first place!

An Illustration

This can all sound a little theoretical with words alone. Let me try to illustrate with an example.

Let’s say you have roughly twenty five things.

Twenty five seeminly random black circles scattered on a white background.

And you’re told the limit is ten, so you single out your ten favorites.

Twenty five seeminly random black circles scattered on a white background, with ten random circles highlighted in red.

Then you cut away everything else, so you’re merely left with your favs. How well do they stand together as a whole?

Ten seeminly random red circles scattered on a white background

Contrast this with a scenario where you follow Rick’s advice.

You’re told the limit is ten, so you start with five of your absolute favorites — the ones you know you can’t live without.

Twenty five seeminly random black circles scattered on a white background, with five random circles highlighted in red.

Now you can ask important questions about building back up to ten. How do these five relate to each other? How do they relate to the remaining options? How can I choose five more that build on these core five favorites and produce something whose sum is greater than the individual parts?

As you look at these relationships, a new, underlying pattern reveals itself which you hadn’t seen before. So you choose five more which support your initial core selection, making the overarching whole better and more cohesive.

Twenty five seeminly random black circles scattered on a white background, with ten circles highlighted in red revealing an undelying structure and pattern to their arrangement.

What you’re now left with, once you remove everything else, is something that reveals a unified, pleasing whole.

Ten circles on a white background in a structured grid.

This all comes about by changing the process through which you make edits. Editing becomes a process where you ruthlessly select a core then switch back to “creating” mode and build something around that core to create something amazing!


Reply
Tags