Jim Nielsen’s Blog

You found my HTML feed — I also have an XML feed and a JSON feed.

I ♥ HTML

Subscribe to my blog by copy-pasting this URL into your RSS reader.

(Learn more about RSS and subscribing to content on the web at aboutfeeds.)

Recent posts

Your Greatest Strength Is Also Your Greatest Weakness

View

Referring to product management, my old boss used to say, “There is no right or wrong, only trade-offs.” This applies to technology too (and, if you really think about it, life generally — but we won’t go that far).

As an example, what makes npm great? It’s so easy to install a dependency. What makes npm not so great? It’s too easy to install dependencies. npm makes it so easy to get a bunch of complexity.

In other words: its greatest strength is also its greatest weakness.

Nesting in Sass CSS is similar: nesting selectors aids readability, but do it too much and now nothing is readable. Again, a double-edged sword.

The things you extol about a technology are also going to be the things that get you into trouble because those are the trade-offs.

So to evaluate a piece of tech, you should ask yourself: what are the downsides of the the very things I love about this?

The folks at Linear articulated this perfectly in a post-mortem explaining why they were having issues related to speed. To quote their post:

These [speed] problems stem from trade-offs in our architecture. The reason Linear is fast is also the reason Linear is slow once workspaces grow in size.

The reason it’s fast (in certain scenarios) is also the reason it’s slow (in other scenarios).

The reason it’s great sometimes is also the reason it sucks sometimes.

Your greatest strength is also your greatest weakness.


Reply

Amazing Athletes of the 21st Century

View

This post is a secret to everyone! Read more about RSS Club.

Content warning: wherein I talk about sports. If that’s not your thing, feel free to skip this one.

I’m not a rabid sports fan. I don’t have a team, though I do have teams I hate (or rather, like to hate on). But I do enjoy following sports.

I’ve witnessed some pretty spectacular sporting events and athletic performances in my life, so when ESPN published “Ranking the top 100 professional athletes since 2000”, I read it with joyful nostalgia for all the amazing things I’ve witnessed.

To make it even more fun, I wrote down my own personal recollections for the people on this list.

No. 1: Michael Phelps

23 gold medals? 8 in a single Olympics? Dude was absolutely unreal. I don’t know if I’ve ever witnessed someone absolutely dominate a sport like he did.

Well, except for maybe…

No. 2: Serena Williams

"The way I see it, I should have had 30-plus Grand Slams," Williams wrote in Vogue in a 2022 essay announcing her impending retirement. "I didn't get there ... But I showed up 23 times, and that's fine. Actually it’s extraordinary."

Extraordinary indeed — both her and her sister.

No. 3: Lionel Messi

I’m not the biggest soccer fan (you can tell, I called it soccer). But that 2022 World Cup match where Messi finally won might’ve been the best sporting event I’ve ever watched.

Messi winning the World Cup in Argentina in 2022 was perhaps the biggest Hollywood ending that soccer has ever seen. After losing the 2014 final, it looked like it would never happen for Messi...[but] He scored twice in the final as Argentina beat France on penalties, sparking an outpouring of emotion and celebrations around the globe. "This guy transcends rivalries -- even between Brazil and Argentina," Brazil legend Ronaldo said. "I saw Brazilians and people all over the world rooting for Messi. It's a fitting finale for a genius who has marked an era." -- Sam Marsden

No. 4: Lebron James

No one has ever been this good for this long

His longevity is astounding. Breaking Kareem’s all-time scoring record? I never thought I’d see it.

No. 5: Tom Brady

I hate the Patriots.

But the sheer quantity of Brady’s rings is phenomenal. And he was a nobody!

Brady entered the NFL as a sixth-round pick "with little to no fanfare" and left "as the most successful player in league history."

When the Patriots told him he was done, he went to another team and won the Super Bowl the very next year. Absolute menace.

No. 7: Simon Biles

She’s does stuff nobody else in her sport has even attempted — and she does it in competition!

Biles has gone undefeated in all-around competition in every meet she has competed in, a staggering achievement in a sport that used to age-out athletes in their teens.

And she ain’t even done yet!

No: 8: Tiger Woods

ranked the No. 1 golfer in the world for 281 consecutive weeks and 683 overall

His career stats are otherworldly.

Like Serena, he has his own accomplishment named after him: The Tiger Slam.

And like Serena and Phelps, I’d be hard pressed to find someone who so completely dominated their sport like Tiger did.

He was perhaps the most clutch athlete I’ve ever seen. He always delivered when he had to.

No: 9: Usain Bolt

He was so much fun to watch. That photo of him winning is so, so good.

No: 10: Kobe Bryant

Who doesn’t say “Kooooooobbbeeeee” when they throw a piece of paper into the trash?

"He's like our generation's Jordan," Brooklyn Nets guard Cam Thomas told ESPN

I hated him (and the Lakers) at first. But he was so surreal to watch, so unbelievably clutch, I grew to love him.

Still hate the lakers though.

Others

A few others on the list who stick out to me:

  • Curry: The guy transformed the game of basketball.
  • Ledecky: Like Biles, she’s ain’t even done yet. Also this video.
  • Shaq: Most dominant ever. Made 7ft grown men look like ragdolls.
  • Mayweather: I don’t even like boxing, but 50-0? C’mon.
  • Sorenstam: Dominant. Baller move to play in a PGA event too.
  • Ronaldinho: A brief but bright shooting star. “If longevity were not a factor in defining the greatest...then Ronaldinho”.

Reply
Tags

I Don’t Like The Term “IC” Either

View

I really liked Robin’s piece, “Stop calling yourself an IC”.

I still remember the way I felt the first time I heard that term. It was used in a way where its connotations conveyed a kind of laziness via lack of ambition. And I thought, “But wait, I am an individual contributor — and I like it. Is something wrong with me?”

Learning this term and glimpsing how it was used by folks above my paygrade was a bit of a shock. But, with time, I began to realize that everyone seemed to use the term so nonchalantly, like it was the most natural, descriptive term in the world for labeling a certain class of people.

So, as with many things that rub me the wrong way, I mostly just went on with my life. Pick your battles, ya know?

But when Robin posted about his dislike for the term, I had to at least write this little post to say: I don’t like it either.

In fact, it reminded me of another term I once heard and found myself shocked to hear people use so nonchalantly: “the talent”. Have you heard this?

From what I understand, it’s a term used commonly in creative fields like music, film, etc., to refer to the people who do the performing or creating.

For example, managing a series of concerts at a stadium with performances by the likes of Taylor Swift, Beyonce, or Rihanna? They’re all merely “the talent” that are performing at the stadium.

The term, I imagine, is meant to differentiate one class of people (the “talented” individuals) from the other classes of people who surround and support them (e.g. managers, producers, agents, etc.).

The context in which I heard the term was a planning meeting, where its usage conveyed an idea along the lines of: “Whatever ‘the talent’ comes up with, we’ll take it, market it, and sell it.” (Talent and creativity being mere commodities, you see.)

I remember thinking the term seemed so flippant. How could they call them “the talent”, as if they were a mere auxiliary to the task at hand? “More like ‘the backbone’ or ‘the heart and soul’ or ‘the driving force’ of everything you’re doing,” I thought.

Anyhow, that’s all a long way of saying: I agree with Robin, I don’t like the term either and I won’t be calling myself one.


Reply

Text Prompts Circumscribe The Surface Area of Possible Solutions

View

I was reading Chase McCoy’s notes about Figma’s move into the AI space and this one line stuck out to me (emphasis mine):

Generating UI designs from scratch, based on a text prompt

This reminded me of my note from a Wall Street Journal interview with Jony Ive where he talks about problem solving. He notes that when you set out to solve a problem you are open to a flood of ideas because the only clear thing is the problem itself. If all you can say is “I’m going to make this person’s life better” then the possibilities for doing that are almost endless.

But once you begin talking about solutions, you begin to drastically narrow down your possibilities. Here’s Ive:

Language is so powerful. If [I say] I’m going to design a chair, think how dangerous that is. Because you’ve just said chair, you’ve just said no to a thousand ideas.

In short: language is a design tool.

It reminds me of a project I worked on a decade ago where we named a solution early on, then later hit a wall only to realize that our initial name was our stumbling block:

Our innocent naming choice had not been innocuous. It held subtle and misleading connotations which had led us down a road of wrong assumptions where we kept trying to fit a square peg in a round hole.

My takeaway from the project?

Naming is important and should be revisited as you iterate. The way you name something, even in the initial stages when a concept or idea is fuzzy, contains vital bearings on the direction of the project—whether you’re consciousness of it or not.

As human-computer interface design barrels toward generation from a text prompt, this idea seems more important than ever.

When you use language to describe for an LLM the solution you want, you circumscribe your possible solution area. As Ive says, if you say you’re making a chair, you’ve said no to a thousand other ideas. If you ask AI for “a card display for a song”, you just asked for one thing which means you said no to a thousand others.

Language is a powerful design tool.


Reply
Tags

Creating Some Noise on Behalf of Silence

View

How do you write about the value of silence?

It’s kind of absurd when you think about it. Do you use words to extol the value of something whose essence is the very absence of words?

It’s like making a painting of the invisible. Do you use visible means to depict something that exists outside of the visible?

Nonetheless, here I am with this blog post.

Via a recommendation from my wife, I recently finished reading “The Stranger in the Woods: The Extraordinary Story of the Last True Hermit” by Michael Finkel. It’s about Chris Knight, a man who chose to disappear into the woods in Maine and live alone with no human contact for almost three decades.

Reading the book, you realize, “Damn, this guy led a life that was the very antithesis of our world of hyper-stimulation.”

When the author asked him to describe his experience of solitary quietude, the best Knight could do is declare that words failed him. “Silence does not translate to words” he said.

As the author points out, Knight’s observations are inline with other writings praising the value of silence. Emerson said, “He that thinks most, will say least.” The Tao Te Ching states, “Those who know do not tell; those who tell do not know.”

Anyhow, it’s a good, short read. Now I’m left with the impression that perhaps we could all use a little more silence…[as I generate some more noise in the world with this blog post to say that]


Reply

All About That Button, ’Bout That Button

View

In modern SPAs it’s common to immediately escape baked-in browser behaviors. For example, using <button> often looks like this:

<div>
  <input type="text" name="q" />
  <button
    type="submit"
    onClick={(e) => {
      // Stop the baked-in behavior
      e.preventDefault();

      // Do something with the input's value
    }}
  >
    Search
  </button>
</div>

But a framework like Remix encourages writing mutations as declarative HTML that works without — or, perhaps better stated, before — JavaScript, using semantic elements like <form> and <button type="submit">.

<form action="/search">
  <input type="text" name="q" />
  <button type="submit">Search</button>
</form>

From this starting point of HTML — which functions before JavaScript loads & executes — you can then begin to progressively enhance your <form> with JavaScript that intercepts default browser behavior (e.g. <form onSubmit={...}>) and enhances the experience however you prefer.

As I‘ve worked more closely with forms and buttons, I’ve learned a few things.

For example, did you know you can submit a form with a button that lives outside of the form it submits? Use the form attribute:

<form id="my-search-form" action="/search">
  <input type="text" name="q" />
</form>

<!-- Somewhere else in the DOM -->
<button type="submit" form="my-search-form">
  Search!
</button>

Or, when a form submits you can open the result in a new tab (you can stick target on the <form> itself too and it’ll do the same thing):

<form action="https://google.com/">
  <input type="text" name="q" />
  <input type="hidden" name="site" value="my-blog.com" />
  <button type="submit" formtarget="_blank">Search</button>
</form>

That’s a neat progressive enhancement trick because it allows the user to input a query right there on your website and then, if JavaScript is enabled/working, you e.preventDefault() and take over the interaction there on the page. But if JS is disabled or fails to load, the interaction still works and submitting the form opens a new tab on the user’s device with results for their query.

There’s a bunch of other button attributes for overriding parent form behaviours, such as: formmethod, formenctype, formaction, and formnovalidate.

If you’ve worked in a Remix app where you’re trying to build user interactions that work both with and without (or before and after) JavaScript, you’ve likely encountered many of these. They are very useful mechanisms.

“But why”, you might ask, as an example, “would you want to have two buttons on a form, one that traditionally submits the form with validation and one that uses formnovalidate to submit the form and bypass validation?”

I could go into detail describing one such use-case in a recent codebase, but it will suffice to rather quote the imitable Chris Coyier who had a similar issue years ago:

When you submit [<form action="/submit">], it’s going to go to the URL /submit. Say you need another submit button that submits to a different URL. It doesn’t matter why. There is always a reason for things. The web is a big place

A big place indeed.


Reply

Digital Trees

View

Trees have many functions:

  • they provide shade,
  • they purify air,
  • they store carbon,
  • they grow fruit,
  • and they’re aesthetically pleasing.

What’s intriguing to me about trees is their return on investment (ROI).

It takes years, even decades, to grow a tree to the point where you feel like you get to reap its benefits.

Because of this, many trees end up being cultivated more for others than for ourselves. They can be a living embodiment of giving over extracting.

With the web going the way it is — what with AI and its extractive penchant, poisoning the well from which it sprang — it makes me wonder: what are the “trees” of the web? Undoubtedly many (metaphorical) trees on the web were planted by others but we enjoy their fruits.

For me personally, one example is the free and open blogs of folks whose advice and education have gifted me the know-how necessary to be employed as an interdisciplinary website maker.

Which makes me wonder: what trees am I planting? Trees I will gain little from in my lifetime, but others may revel in their fruits far into the future?

Pay it forward. Plant a digital tree.


Reply

Cool URIs Don’t Change — But Humans Do

View

Here are two ideas at odds with each other:

  1. You should have human-friendly URIs
  2. Cool URIs don’t change

If a slug is going to be human-friendly, i.e. human-readable, then it's going to contain information that is subject to change because humans make errors.

If “to err is human” then our errors will be forever cemented into our URIs at publish time.

For example, if I write:

/the-earth-is-flat

But later realize I was wrong, I can change the content at that URI but am forever stuck with the erroneous idea expressed in my slug (if my URI is to remain cool).

Whereas if I’d had a non-human-readable URI like this:

/19382

Then I can hide from my errors by merely updating the content at that URI anytime I want.

How do you get around this problem?

In my post about great URI designs I note how StackOverflow addresses this via a URI design that puts the machine-readable identifier first, then the human-readable slug second.

/:id/:slug

This allows the slug to change over time without breaking links. For example, you could publish:

/19382/the-earth-is-flat

And later change it to:

/19382/the-earth-is-round

And both will resolve to the same resource. It doesn’t matter what you put in the position of :slug it’ll always be as if you merely typed:

/19832

Granted you can’t protect from people putting misleading information in your URIs. For example, this would resolve to the same resource as the others:

/19382/the-earth-is-a-triangle

That said, there is one problem with the StackOverflow example: it doesn’t work with simple static file hosts where you don’t have control over routing logic.

The McGyver, jerry-rigged version of this URL would be to use a search param that doesn’t do anything other than provide human-readable context. For example:

/19382?the-earth-is-flat

That would work with a static file host without special routing logic (though it’s still subject to abuse same as the StackOverflow example).

So, to my original example:

/19382?the-earth-is-flat

Could later be changed to:

/19382?the-earth-is-round

And it remains cool 🕶️

Not saying you should, but you could.


Reply

A Local-first Codebase Opens the Door to More Collaborators

View

I thought this was interesting: Dax Raad on the local-first podcast observes how a local-first model drastically simplifies the experience of building an app, both as an individual and as a team.

He talks about how his wife is not an engineer but she learned to be more hands on in the codebase of the project they work on together.

For them, one of the things that’s been “crazy helpful” about a local-first approach is that all the data for the app is “just there” locally. For Dax’s wife, as a beginning coder, it’s such a simple model to work with. She’s not trying to figure out how to round trip to the server and keep data in sync. Dax handles all that upfront. The result?

There's not all this weird like, loading states, or like fetching it, or like just a whole bunch of complexity around getting data back and forth. It's solved in one part of your app, and then you never have to think about it anywhere else.

So from a team productivity point of view, she can build any feature she wants, even if I didn't explicitly think about it from the backend point of view, because she has all the data locally.

She's like, “I want to create a view that searches through this set of data.” She can just go do that. All the data is there. [It’s] very, very straightforward.

And it's actually wild how much of a productivity boost that has on your team, because…with every new feature you’re not rebuilding [yet] another way to sync that data back and forth.

When every single feature you build has to scaffold the lifecycle around fetching, updating, and revalidating the data that’s being changed, you alienate people who could otherwise collaborate on the front-end because they don’t know how to build the show spinner -> fetch -> render -> update -> show spinner -> revalidate loop (we spend a lot of time and effort on the coordination problem).

I’ve been in this position. As someone who started writing mostly HTML & CSS, then later moved to writing view logic with languages like JSX, I could only take my design work so far. Then I’d have to leave it for someone else to “wire things up”, which often resulted in them having to re-write a lot of what I did because it didn’t take into account the architecture of the network layer.

But that problem — how do I get (and update) the data required to build and style a functioning UI as a front-of-the-front-end engineer — can be solved up-front by a local-first architecture, allowing more people to collaborate on building UIs.


Reply
Tags

Custom Elements Don’t Require a Hyphen as a Separator

View

Scott Jehl reached out to help me resolve a conundrum in my post about what constitutes a valid custom element tag.

The spec says you can have custom elements with emojis in them. For example:

<emotion-😍></emotion-😍>

But for some reason the Codepen where I tested this wasn’t working.

Turns out, I’m not very good at JavaScript and simply failed to wrap everything in a try/catch.

What’s funny about this is that <my-$0.02> isn’t a valid custom element but <my-💲0.02> is!

Anyhow, I’ve since updated that post and now things work as the spec says. All is good with the world.

But that’s not all.

In my convo with Scott, he pointed out that custom element tag names don’t need a hyphen as a separator of characters, they only need the hyphen.

This kinda blew my mind when I realized it. All this time I’d been thinking about the rules for custom elements wrong.

You aren’t required to have the hyphen as a separator:

<my-tag></my-tag>

You’re just required to have it:

<mytag-></mytag->

Those are both valid custom element tag names!

Which means, if you have a really simple element and can’t think of a better name than an existing HTML element, you can do this:

<h1->My custom heading</h1->

Or this:

<p->My custom paragraph</p->

Or, I suppose, even this:

<ul->
  <li>My custom unordered list</li>
  <li>That still uses normal li’s</li>
  <li>Because why not?</li>
</ul->

I’m not saying you should do this, but I am saying you could — you know, nothing ever went wrong doing something before stopping to thinking about whether you should.


Reply