Jon Plummer

Today I Learned

Engaging with the material presented in critique

A designer recently pointed out that they were quiet in critique because they weren’t sure what to talk about or how to engage with the material being presented. They noted that several others always seem to have something useful or interesting to say in critique, and asked for ways to be helpful.

The good news is that the presenter should give you some good raw material to work with. At the beginning of their presentation they should quickly mention

  • where they are in the project
  • the design goals for the work, and other relevant goals
  • what they are thinking about
  • what sort of feedback would be most helpful

and these provide fine starting points with which to engage the work.

Then there is your experience of the work as presented.

  • Does this make sense to me?
    • Does this conform with my understanding of the system?
    • Would I understand this as a lay person?
      • How much specialized knowledge do I need to have to make use of this?
      • Does this use words and concepts I am already familiar with?
      • Does this ask questions I am prepared to answer?
  • Does the design seem likely to be familiar/usable/intuitive/operable?
    • How standard is the usage of the interface elements, patterns, or design system components used in the design?
    • Does this introduce new interactions where familiar ones would do?
    • Is it clear what I would get from operating each control?
  • Does this seem like a complete experience, or a fragment?
    • Does this narrow slice fit well where it is intended to fit?
    • Does it have a beginning, middle, and end? Does my work as a user pay off?
    • Are there other experiences that it might depend on or contribute to?
      • What would it take to coordinate this experience with those others?

And, of course, you can zoom out a bit. This can require a delicate touch depending on the sort of feedback desired and how late we are in the project.

  • How well does the design address the goals the presenter offers?
    • Are the presenter’s goals or project goals clear? Sensible? Customer-centered?
  • Is the customer value clear?
    • Is the path to that value straightforward?
    • Is that value demonstrated by the new capability?
  • Is the design or workflow well-explained? Is it going to be intelligible to team members?
  • How does this relate to my projects or service areas?
    • Do I recognize anything from my current or past projects that is relevant/useful here?
    • Do I recognize work or difficulties for other teams in this projects?
    • Are there knowledgeable people that could help with this project that I can introduce?

A quick note on agent conversations

Conversational design has become an important topic of late, and at work we’ve been chewing on this for a few different conversation channels and purposes. Familiar old principles from consumer electronics setup and other experiences are coming up anew, such as

  • Don’t ask if you don’t have to. Detect and test, detect and confirm, infer and confirm, offer the most common option, and only if forced just ask without offering.
  • Only ask questions the user is prepared to answer. There’s little point in asking if you won’t get a confident answer; find another way to learn the needed information.
  • Stay away from inviting yes/no answers. It speeds the conversation along to offer a choice, A or B, rather than merely asking if A is acceptable. Avoiding the yes/no answer gets us to a conclusion more quickly and feels proactive. If need be you can offer a complete option A and suggest you have other options; the choice is logically equivalent to yes/no but feels better.
  • Offer options that are complete. Insofar as possible, offering an option that is complete allows the user to select quickly and get to the happy conclusion; breaking a decision up into many parts feels slow and cumbersome, programmatic and unnatural. “I have Il Fornaio at 7:30pm on Thursday, does that sound good” is a nicer thing to assent to than separately negotiating which restaurant, what day, what time only to be faced with “sorry, I don’t have that time. What other time?”
  • Offer nearby alternatives. In the restaurant example, when the user’s preference can’t be met, rather than negotiate the whole thing again, offer nearby options. “I don’t have Il Fornaio at 7:30pm, but there’s a table at 8:30pm. Would you prefer that, or would you like me to look for another restaurant at 7:30pm?” is a question I’d much rather answer than “Il Fornaio is not available at 7:30pm. Available times are 4:00pm, 4:30pm, 5:00pm, 8:30pm, 8:45pm, 9:15pm. Which would you prefer?” The underlying business may know what their customers would prefer, which variables are more important, so…
  • Understand user feelings about multivariate choices. Is it more important to see the doctor you usually see, or to have an appointment at the time you prefer? Is it more important to go to the tire shop you usually go to, or do you need the flat fixed right away? Etc.

The “hidden” pages of jonplummer.com

This site has a handful of “hidden” pages. They aren’t secret but they don’t live in the main navigation; they serve utility functions rather than human browsing habits. Making them public and giving them URLs is a nod to the “view source” ethos of the web. Everything is here, everything is inspectable, and everything is open.

1. The main RSS feed

/feed.xml

This is the lifeblood for those of us who still believe in the open web and subscribing to and reading periodic content on our own terms. It contains all the blog posts from the site.

How the RSS feed is generated

It’s built using a Nunjucks template (feed.njk) that iterates over the collections.post collection in 11ty. It outputs XML compliant with the RSS 2.0 specification. I use the eleventy-plugin-rss to help with some of the formatting, ensuring dates and absolute URLs are handled correctly.

Why an RSS feed

If you use a feed reader (like NetNewsWire, Feedly, or Readwise Reader), this is how you get my updates without checking the site manually. It’s the “subscribe” button of the decentralized web.

2. The links feed

/links-feed.xml

A specialized feed for the “found links”—the interesting articles, tools, and videos I find around the web that don’t warrant a full blog post but are worth sharing.

How the links feed is generated

Similar to the main feed, this uses a Nunjucks template (links-feed.njk). However, it skips the main posts in favor of the short link posts that appear between them. This is easy because those posts appear in a separate data file (src/_data/links.yaml). This allows the feed to present a chronological stream of fun and interesting things.

Why a links feed

If you only want the curated list of cool stuff I find and not my long-form rambling, or if you want to pipe these links into a different tool, this is the direct line.

3. The readme

/readme/

This is the “About This Site” page’s technical cousin. It renders the actual README.md file from the project’s root directory. I produced it because GitHub expects one, and the source code for this site is on GitHub.

How the readme is generated

This is one of my favorite little 11ty tricks. The page (src/readme.md) is just a wrapper. It uses a custom readFile filter to grab the contents of the project’s README.md, then pipes it through a markdown filter to render it as HTML.

// .eleventy.js
eleventyConfig.addFilter("readFile", (filePath) => {
  return fs.readFileSync(filePath, "utf8");
});

Why a readme

It ensures that the documentation in the code repository and the “about this project” page on the live site are always perfectly in sync. No copy-pasta required. If you want to know how to build or run this site locally, this is where to begin.

4. The changelog

/changelog/

A chronological list of changes, fixes, and updates to the site’s codebase and content.

How the changelog is generated

Identical to the readme strategy, the src/changelog.md file includes the root CHANGELOG.md using the readFile filter. This keeps the project history transparent and accessible without me having to update two different files. Every time I commit a change and build the site, the latest commit message gets summarized and added to the changelog.

Why a changelog

If you’re wondering when a specific feature was added or if I’ve fixed a bug you noticed, this is the record. It’s also a good accountability tool for me to see how often (or how rarely) I’m shipping updates.

5. The technologies list

/technologies/

A detailed breakdown of the building blocks: Eleventy, Node.js, specific plugins, and testing tools.

How the technolgies list is generated

This one is currently a static Markdown file (src/technologies.md). While I could automate it by reading package.json, I prefer to generate then edit this list to add context about each tool and remove the overly-obvious, rather than just dumping a list of version numbers.

Why a technologies list

If you’re a developer looking to build a similar site, these are my ingredients. It breaks down not just the “what” but the specific libraries handling things like RSS, dates, and accessibility testing.

6. The sitemap

/sitemap.xml

A map of the site for search engines.

How the sitemap is generated

A Nunjucks template (sitemap.njk) iterates through all the collections (post, portfolio, page) and outputs an XML file that follows the sitemap protocol. It includes last-modified dates so crawlers know when to come back.

Why a sitemap

You probably don’t, unless you are a robot. But if you’re building a site, you need one of these to ensure Baudu, Yandex, Yippy, Ecosia, Bing, Kagi, Ask, et al can find all your pages efficiently.

My recent experience with AI-assisted coding

This blog has gone through a lot of generations – once a portfolio site, then a self-hosted WordPress blog (boo, Matt!), later a static site backed by local WordPress as a CMS, and now an Eleventy-based generated static site.

I initially tried to make Eleventy work on my own, but the software development landscape has changed so much from when I dabbled in it professionally in the early 1990s (I’ve designed the whole time, but haven’t done any implementation in an age) that even getting my bearings was a rocky start. Homebrew, Node.js, TypeScript, NPM, Nunjucks, Liquid, YAML, Git, all are new since then. None of these is terribly complicated, but shake them all up in a bag and you can be left wondering what’s working, what’s broken, where to put things, and where to look. Heck, the notion of server-side JavaScript was fairly new when I turned my focus to design leadership. CSS was just becoming popular at that time, we had just started dabbling in Mercurial rather than Subversion, and JSON was something you read about on Douglas Crockford’s site.

So I turned to Cursor. Critically, the first thing I asked it to talk through with me was a plan to take my WordPress site export, stand up an 11ty project locally, and migrate all of the content. I then beefed up that plan with all of the ideas I had about keeping things on GitHub, improving the local site, deploying it to my shared host, improving the typography, improving meta tags, etc. And, again critically, I asked for help grouping those wishes and ideas into sensible chunks and prioritizing them. I didn’t always agree with the recommendations, but having a plan and thus being able to work it in priority order (any sort of order, really) prevents scattered and incomplete efforts.

It was also important to have Cursor not just race off and do things on its own, but talk through them first and prefer small interventions rather than large ones. This has led to bringing 11ty docs into the project for context, a lengthy .cursorrules that attempts to explain that Cursor should not go on at length about how I’m “absolutely right” and should prefer forming a plan and asking me about it, etc. Even so, Cursor will do some strange things like reimplementing existing date functions and whatnot; my little bit of development experience has been helpful to detect odd smells in what Cursor says it is doing and quiz it about whether these things are strictly necessary, noticing duplicate development, recognizing parts of the project that might need updating in response to a change elsewhere and asking about it, etc.

Third, as with one’s own work it has been important to check Cursor’s results, and since a static site generator can produce a lot of files, automated and manual testing are both necessary. Happily, Cursor can form a plan, discuss, and implement test scripts, and I’ve got quite a few of these now, even importing axe-core for some basic accessibility checking of the resulting HTML. I can now run tests on accessibility, content structure, external and internal links, HTML validation, the validity of my RSS feeds, the correctness of my meta tags and other basic SEO concerns, even likely site performance (which in a static site is mainly about file size).

Cursor has also been a big help with documentation. I started with just a plan.md; now I have that pulled-in 11ty documentation and a script to refresh it, a commands.md that reminds me what all the different build, test, and deployment commands do, a notes.md that reminds me how my article frontmatter works, what I’ve been thinking about re color schemes, and how to make a redirect. There’s no sense trying to remember things that you can write down, and Cursor can help with that too. “Cursor, now that we’ve made these changes is there anything that needs to change in plan.md?”

While using Cursor doesn’t magically make me a competent developer, it has allowed me to make much more progress in a handful of weekends than I was doing on my own, and feel more confident in the result (mainly because of all the things I’ve had to correct Cursor on). And it’s fabulous to watch my progress through my plan.md. I’m getting down to the parts of the plan that I was putting off, which is a good sign.

Now I’m inspired to tackle other projects I’ve wished for, like a plain English service for MacOS that helps you find alternatives for the least common words in a selected bit of text. Who knows if that’s the right way to do it, but I can give it a try and see if I like it rather than wondering.

A little bit of what I’ve done for this site, and in what order, can be read in the changelog (generated from Git commits), if you’re into that sort of thing. There’s also a generated list of technologies.

Being an ally means actually physically helping

I realized something a little while ago: for me, being an ally means actually physically helping.

I had long thought about allyship in terms of support, advocacy, speaking up, and sharing privilege – practically a checklist of things we are reminded to do in being an ally. But I never really felt that I was effective in doing these things. How exactly does one share privilege?

I’ve found that unless I put myself in places where I can exercise those things, occasions don’t arise to employ them. That means that if I want to actually be active in being an ally, I’ve got to go to a place and physically help. Be a member of Rainbow Guard for Pride. Be a de-escalator at a protest or a cultural festival. Be on the safety/lookout team for a local ethnic group. Print whistles for community shaming of ICE and CPB. Ferry food donations to a distribution center to help people through the SNAP gap. Etc.

By giving my presence and labor, I can be helpful, demonstrate esteem for the people or cause at hand, and use my position as a cis het white guy, the least vulnerable among us, to actually be an ally, not just think nice thoughts.