{"pageProps":{"data":{"posts":[{"__typename":"Post","id":"5fb15e3b0a17d00039ea5bfe","title":"Design to Save People from Themselves","slug":"design-to-save-people-from-themselves","updated_at":"2020-11-15T13:42:06.000-05:00","excerpt":"How software can prevent people from making mistakes, causing permanent damage, or bringing about the collapse of democracy.","feature_image":null,"html":"
This post is a complement to episode 372 of Design Details, Saving People from Themselves.

Last week Divya Tak asked on Twitter \"but what are things that you do to 'save the users from themselves...'\" Marshall Bock and I spent an hour thinking about this question, recorded a podcast with our answers, and now we're publishing the conversation here for longevity.

This list is not exhaustive: there are a million more examples of software saving people from their own mistakes, insecurities, and ignorance – let us know what we missed by filling out the contact form at the bottom of this post!

Persist draft content

Great products work to ensure that people never lose unsaved changes or draft content. There are a few common patterns to do this:

Warn before destruction

This one is straightforward enough, but software should always warn people before taking destructive actions. Deleting or permanently modifying a document by mistake is a horrible feeling. Software, like iOS, guides developers to make destructive actions red, require confirmation (through an action sheet or an alert), and places the destructive confirmation button far away from your thumb (destructive actions always appear at the top of action sheets).

Undo

In interfaces where a user might accidentally trigger some kind of modification, but one that's not necessarily destructive, it's a good idea to provide a control to undo that action. Think: swiping an email to be Archived. Archiving an email is not destructive, but the undo button saves someone a lot of headache of having to dig back through menus to find an email that was accidentally swiped away.

Magic Undo

Sometimes you can provide an undo prompt for anything hasn't actually changed. It's like a fake undo, or a pre-undo. The best example is Gmail's \"email recall\" feature – if you send an email, Gmail doesn't actually send it right away. Instead, it prompts you to undo the send, and only after that prompt disappears does that email get sent.

Content scanning

Have you ever sent an email where you meant to attach a file, but just the act of typing \"see attached\" made you forget to actually attach the thing? Apparently this happened to enough people so that Gmail now looks for key phrases in a draft like \"see attached\" – if the email itself doesn't have an attachment, they will prompt for a confirmation before sending.

Code scanning

Similar to content scanning above, code scanning is a magical feature that prevents people from accidentally publishing passwords or secrets on GitHub. Secret scanning helps developers catch their mistakes before it brings down an entire organization.

Sensible defaults

Also known as convention over configuration: a software design paradigm used by software frameworks that attempts to decrease the number of decisions that a developer using the framework is required to make without necessarily losing flexibility.

Software should be built with sensible defaults to prevent people from having to make unconventional decisions. This is more beginner-friendly, but many experienced users also appreciate it when their tools clearly communicate best practices.

Tap targets

Apple and Google say that tap targets should be a minimum of 44pt and 48pt. That minimum part is important - it's totally fine to go bigger! If you can make a safe assumption about what a user is trying to tap or click, and there are no competing elements around that target, go ahead and make the target as big as possible. See an example of how this should work in Twitter for macOS.

Digital addiction

As of 2018, Americans spend more than 10 hours per day looking at a screen. Social media, algorithmic feeds, push notifications...these are all raw fuel for addictive tendencies, constantly pulling people back to the screen. Good software helps people to manage their time to ensure that it's time well spent. Do Not Disturb, Bedtime reminders, and Instagram's \"all caught up\" module all help nudge people towards better consumption habits.

Duplicate entry points

Software developers like to say \"don't repeat yourself\" as a mantra for simplifying and abstracting code. But in interface design, well-considered repetition can enhance the user experience. For example, imagine an application has settings to manage notification preferences. In a DRY world, the entry point to manage your notification preferences would only appear by navigating to some Settings view, first. But in a user-friendly world, there would be a duplicate entry point in context on the Notifications view itself.

Volume warnings

Companies like Apple have been actively investing in raising awareness about hearing damage and safe volume ranges. Software can help nudge people to turn down their headphones and save their eardrums. My younger self would have appreciated this.

Age-gating, NSFW warnings

On algorithmic feeds, like Twitter, Instagram, Facebook, or Reddit, it's inevitable that at some point something...unsavory...might appear. If you're browsing at work, blurring that content can be a professional life saver. In other cases, providing interstitial warning screens – like this one from Reddit – might prevent people from accidentally opening a link with content they wouldn't want any lurking eyes to see.

Spoiler obfuscation

While it's not part of the official Markdown spec, apps like Reddit and Discord have extended the syntax to allow for a special way to hide spoilers. Please, Twitter...

Rage shake

It's hard to say exactly how good this is, because it's basically impossible to discover. But on iOS, and in many individual applications, there is a \"rage shake\" function that prompts a system activity. On iOS, a shake gesture is the universal trigger for undo. On other apps (I remember encountering this on Facebook's internal beta apps), a quick \"rage shake\" will prompt a bug reporting mechanism, allowing users to vent any frustrations directly to developers.

This bit from Daring Fireball is hilarious, too:

Lastly, here’s an anecdote I heard years ago about how Shake to Undo came to be. Scott Forstall charged the iOS team with devising an interface for Undo — everyone knew the iPhone should have it,1but no one had a good idea how to do it. One engineer joked that they could just make you shake the iPhone to invoke it. Forstall said he loved the idea, and what was proposed as a joke has been with us as the Undo interface ever since.

Preventing the spread of misinformation

Facebook, Twitter, WhatsApp, Instagram, and every other major social platform are building new systems to prevent people from inadvertently spreading misinformation.

A few patterns are emerging:

Twitter does both – not only does a flagged tweet have a contextual link to learn more, but if you click on the retweet button, they show a popover warning that the underlying claim is disputed.

Facebook, Twitter, WhatsApp, and many other apps are now introducing warnings that appear when people share articles without reading them first.

Encouraging civility, reducing toxicity

Instagram has a feature that warns users when they are about to leave toxic comments on a post. This prompt might help people to calm down if they were leaving a comment in the heat of a moment. More generally, prompts like this remind people that there is another human on the other side of that screen, and that our words matter.

Further reading

For more notes about what it means to build great digital products, read Quality Software.

Let us know what we missed in this list! I'll be updating this post over time with new ideas and screenshots.

"},{"__typename":"Post","id":"5fa89bd9c795260039b568c6","title":"True Respect is the Difference","slug":"true-respect-is-the-difference","updated_at":"2020-11-09T00:22:53.000-05:00","excerpt":"True respect is the difference between a fantastic collaborator and an asshole.","feature_image":null,"html":"

Last week I tweeted:

Got told \"this is lame\" about one of my mocks, and you know what? I'm here for that energy. Could've been a much longer \"what do you think about...? did you try...?\" conversation, but sometimes the bluntness is just right.

This response from Hans captured another meaning behind my message:

“this is lame” can be a sign of a bad team, but also of a fantastic team. true respect is the difference.

After reading this response, I started wondering: how many relationships do I have where giving candid feedback happens by default? How many people do I think would give me blunt feedback, if asked? If the ability to give and receive candid feedback is a proxy for respect between peers, I want this number to go up.

This made me wonder: if I am going to be intentional about growing this number over time, what should I continue to do, stop doing, or start doing in the next year?

Three things came to mind:

Ask for bluntness from the right people, at the right time.

Sometimes I've found myself asking for feedback from a peer or manager when I was secretly looking for praise. Fishing for compliments like this is no way to actually improve, so the first step is to stop doing this. If I'm going to ask for feedback, then I want the feedback to be substantial; something that will actually help me to grow and improve a design.

This means asking for feedback from the right people at the right time. The right people are going to be those with expertise in the area where I'm working, or people who I feel have exceptional taste and judgment. The right times are usually in private, after I feel that I've truly exhausted my own personal abilities to make a design as good as possible.

One mistake I've made in the past is asking for feedback too early, essentially looking for someone to co-design. Most of the time, this is lazy. Of course, there's tension between asking for feedback too early and too late: when a project is about to ship, and any real critique is unlikely to have material impact on the design, that feedback goes to waste.

One of the cool things about working with the same people for long periods of time is that you start to understand how they think, and you can anticipate their questions. This is always a good gut check: if I can anticipate a question, and haven't done the work to have a thoughtful answer, it's too early to ask for feedback.

Look for permission to initiate.

If I expect blunt feedback from people I respect, it follows that they might also expect blunt feedback from me (assuming of course that they respect me). This means overcoming my own non-confrontational tendency, and identifying when other people are asking me for something deeper than surface level critique. And when that moment comes, I need to deliver thoughtful, kind feedback so that we can have a productive conversation, and hopefully continue the practice many times in the future.

Praise as candidly as I critique.

It feels really good to get blunt feedback from someone who I respect. But it feels even better to be told that I've done a good job from someone who actually means it. I want my praise to mean just as much to someone else as my critique. Praise should be honest. Trying to make someone feel good with a compliment only relieves pain temporarily, at the cost of being held back from true growth. It's a sign of disrespect.

"},{"__typename":"Post","id":"5f9f478a02b84c0039a9e434","title":"Writing Better Self Reviews","slug":"writing-better-self-reviews","updated_at":"2020-11-01T21:03:05.000-05:00","excerpt":"My tips and strategies for writing effective self reviews.","feature_image":null,"html":"

Writing self reviews can be hard. For a lot of people, talking about themselves and their accomplishments feels a lot like bragging. Or it might just be hard to remember things that happened a few months ago. Or sometimes people are unsure what the expectations are for a review, and don't know what should be included to maximize their growth.

I've been lucky to have had a string of great managers in my career who helped me think more clearly about the self review and gave me tips to write them more effectively. Here are things I've learned that not only make self reviews easier to write, but have also led directly to raises and promotions.

Impact over volume of work

It's so tempting to write a self review that lists every single thing you did during the half. Look at all this stuff! Of course I deserve a promotion and praise and money!

The problem is that – much like building software – each thing added dilutes everything else. Too many small moments muddy the water of your major accomplishments.

Focus on the most impactful work you did (see: most impactful to the business, not to you personally). If you really feel it's necessary, add an appendix of sorts that serves as your vomit-list of all the smaller things, which in aggregate might match the weight of one higher-impact contribution.

Map impact to levels

If your goal is to get a promotion or grow within your organization's career ladder, you should explicitly map your contributions to the level you're operating at and the level where you want to be. Here's a rough outline I've used in the past:

Here's where I think I made the biggest impact this half, meeting or exceeding expectations for {CURRENT LEVEL}:
1. Most significant point of impact
2. Second most significant point of impact
3. Third most significant point of impact
Here's how I think I met expectations for {NEXT LEVEL} consistently throughout the half:
1. Most significant point of impact
2. Second most significant point of impact
3. Third most significant point of impact

Mapping your contributions directly to expectations helps you to understand if your organization actually values your work. But more importantly, by articulating where you are operating at the next level up, it makes it easier to answer the question: do I deserve a promotion?

Not being explicit about how your contributions meet the expectations of your target level just means that your manager will have to do this on your behalf, in their own words.

Bring reviewers along for the ride

I'm a big believer in \"no surprises at review time.\" Any negative or constructive feedback I give or receive should never be new information. I would consider it a failure of organizational culture to be entirely blind-sided by downwards or peer feedback. Mid-cycle reviews, ad hoc feedback, and a regularly scheduled 1:1 with a manager all exist to help people work out problems in the moment, with compassion and kindness.

This \"no surprises\" principle applies to both negative and positive reviews: I never want my manager to be surprised by any significant work I have been doing throughout the review cycle. This increases the likelihood of that manager missing context, not having time to understand the impact of the work, and fumbling a clear explanation of that work during calibration meetings.

Bring your manager along for the ride by proactively sharing your work and contributions throughout the half. No surprises at review time!

Work journaling

It seems safe to assume that at one point or another almost everyone has hit review season and thought to themselves: what the hell did I even do this half? It's okay to do that once, early on in your career. But don't let it happen twice.

I recommend keeping a list of ongoing accomplishments and achievements throughout each half. Write things down as they happen. Your future self will love you. Personally, I have a section in Things called \"Self review notes\" and I just quickly jot down a new to-do item whenever I make some contribution at work.

Then, when it comes time to write my self review I actually tick each item off as \"done\" whenever it gets included. This gives me a clear, chronological list of things that my past-self deemed important, and it makes the writing itself as trivial as expanding to-do items into sentences.

Another strategy here that I have been learning from Marshall Bock on Design Details (episode 363 to be specific) is to maintain a \"work journal.\" This is an ongoing document that includes notes from all of your day-to-day work. I recommend listening to the episode to learn the basics, but one of the best ideas in this practice is to use a short list of verbs to describe your day to day work. For example, participated in or contributed to or shipped.

By doing this, you can simply command + f the document during review time and look up a specific verb to see all the instances where you were doing that kind of work.

Regardless of the tools or system, just keep a note of things as they happen. I recommend reviewing these notes monthly, aggregating items with similar themes, and deleting things that felt important in the moment but didn't have as much impact as you had hoped.

Make manager advocacy easy

Performance reviews don't live in a vacuum. They are compared, calibrated, and discussed across many people and levels of the organization. It takes time, energy, and attention from managers to clearly and concisely communicate your impact to people who may have been less involved in your week-to-week work (like a skip-level manager). Because of this, it's important to make it as easy as humanly possible to help your manager advocate on your behalf.

To do this, it's better to keep your review short. But in that shortness, the actual structure of your review makes a difference. Bullet lists are easier to parse than walls of text. Simplify, simplify, simplify.

I think to myself: \"how would my manager give an elevator pitch to another manager about my contributions this last half?\" In other words, if my manager had to summarize my impact in a sentence or two, to someone who knows nothing about what I did in the past six months, what would that sound like? To make this easier for them, I like to open my self review with a 2-3 paragraph section that describes my themes of impact for the half.

Follow through

Most self reviews will have a section that asks something to the effect of: what will you do to grow in the next half? And you'll fill that out and hit submit and go on with your life.

Those things you said you wanted to improve are now your goalpost for next half. You should review those notes regularly and check in to see if you're on track. If your goals changed, you must ask yourself \"why?\" And if you're falling behind, it's a nice kick in the pants to get back on track.

I always start writing my self reviews by re-reading my previous review. Did I actually do the things I said I was going to do? Did I grow in the ways that I wanted to six months ago? This approach keeps you accountable to yourself, and demonstrates that you are intentional about your growth within the organization.

If you don't follow through here, then you're just bullshitting.

Recap
  1. Only write about the things that had the highest impact on the business. And yes, impacting the culture of an organization counts as impact on the business.
  2. Map your work directly to expectations for the level where you want to be. Make your promotions intentional.
  3. There should be no surprises at review time. Bring your manager along for the ride throughout the half so they have context and clarity about how your work has impact on the business.
  4. Don't wait until the day before your review to scratch together a list of your contributions from the past six months. Keep an ongoing list of your accomplishments, add to it daily, and curate monthly.
  5. Make it ridiculously easy for your manager to advocate for you when you're not in the room. Make the themes of your impact crystal clear, and make your review easy to read.
  6. Follow through on your previous reviews. Fill in your gaps that you identified six months ago. Show intentional commitment to growth by doing the things you said you were going to do.
"},{"__typename":"Post","id":"5dea5ce1295515003754d9e4","title":"Using Ghost as a Headless CMS with Next.js","slug":"using-ghost-headless-cms-next-js-to-create-a-fast-and-simple-blog","updated_at":"2020-10-27T14:25:53.000-04:00","excerpt":"Rebuilding my self-hosted blog with Next.js and Ghost as a headless CMS.","feature_image":"https://overthought.ghost.io/content/images/2019/12/ghost---next-1--1-.png","html":"

I recently rebuilt most of my personal site with the main goal of providing a better surface area for writing. There are dozens of viable technology choices available right now to create a self-hosted blog and I spent way too long, and way too much energy trying to find the perfect one.

Spoiler alert: there is no perfect system. Every solution is a hack. Once I accepted this, I could focus on finding the least-hacky setup that would cover 90% of my needs. Ultimately, I ended up building the following system:

Getting data from Ghost

The Ghost API is pretty solid - the documentation is straightforward, and they even have a guide for working with Next.js.

To start, I added a small API file that can fetch data from Ghost:

import GhostContentAPI from \"@tryghost/content-api\";\n\nconst api = new GhostContentAPI({\n  url: 'https://overthought.ghost.io',\n  key: 'API_KEY',\n  version: \"v3\"\n});\n\nexport async function getPosts() {\n  return await api.posts\n    .browse({\n      limit: \"all\"\n    })\n    .catch(err => {\n      console.error(err);\n    });\n}\n\nexport async function getPostBySlug(slug) {\n  return await api.posts\n    .read({\n      slug\n    })\n    .catch(err => {\n      console.error(err);\n    });\n}

We can then use these API calls to populate data into a page. Here's a simplified version of my src/pages/overthought/index.tsx file:

import * as React from 'react';\nimport Page from '../../components/Page';\nimport OverthoughtGrid from '../../components/OverthoughtGrid'\nimport { getPosts } from '../../data/ghost'\nimport { BlogPost } from '../../types'\n\ninterface Props {\n  posts?: Array<BlogPost>\n}\n\nfunction Overthought({ posts }: Props) {\n  return (\n    <Page>\n      <OverthoughtGrid posts={posts} />\n    </Page>\n  );\n}\n\nOverthought.getInitialProps = async ({ res }) => {\n  if (res) {\n    const cacheAge = 60 * 60 * 12;\n    res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);\n  }\n  const posts = await getPosts();\n  return { posts: posts }\n}\n\nexport default Overthought

In the getInitialProps call, which runs server-side, I decided that caching the entire page for 12 hours at a time was probably safe: I won't be publishing that frequently. This will improve performance if there is any spike in traffic that would otherwise overload the Ghost API.

Client-side caching

It's a bit overkill for now, but one thing that I've been meaning to try is SWR. This package does some cool client-side work to provide data revalidation on refocus, retries on failure, polling, and client-side caching.

One key thing that I wanted to solve for was people navigating between the home page of my site and the /overthought route. These pages both fetch the same posts, so it'd be a waste to require the second fetch to resolve before rendering my list of posts.

Before SWR, I might have reached for a tool like React.useContext to provide some kind of global state wrapper that would keep track of any previously-fetched posts. But Context can get messy, and I hate adding hierarchy to my components.

SWR solves the problem by maintaining a client-side cache of data I've fetched, keyed by the route used for the request. When a user navigates from / to /overthought, SWR will serve stale data from the cache first and then initiate a new request to update that cache with the latest data from the API.

At the end of the day, the same number of network requests are being fired. But the user experience is better: the navigation will feel instant because there's no waiting for a new network request to Ghost to resolve. Here's how our page from above looks with SWR:

import * as React from 'react';\nimport Page from '../../components/Page';\nimport OverthoughtGrid from '../../components/OverthoughtGrid'\nimport { getPosts } from '../../data/ghost'\n\nfunction Overthought({ posts }) {\n  const initialData = props.posts\n  const { data: posts } = useSWR('/api/getPosts', getPosts, { initialData })\n  \n  return (\n    <Page>\n      <OverthoughtGrid posts={posts} />\n    </Page>\n  );\n}\n\nOverthought.getInitialProps = async ({ res }) => {\n  if (res) {\n    const cacheAge = 60 * 60 * 12;\n    res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);\n  }\n  const posts = await getPosts();\n  return { posts: posts }\n}\n\nexport default Overthought

With the two added lines at the top of the function, we instantly get data served from the client-side cache. The cool thing about this setup is that if the user loads a page that is server-side rendered, SWR will receive initialData that was already fetched on the server, again creating the feeling of an instantaneous page load.

Again: this is overkill.

Rendering post content

My one issue  with Ghost is that they don't return a Markdown version of your posts. Instead, they only return a big string containing all of the HTML for your post. Rendering this HTML string can be a pain: Ghost has a lot of custom elements that they use for rich embeds, like videos, that I don't want to be ingesting.

So instead I was able to hack around this by using react-markdown in conjunction with unified, rehype-parse, rehype-remark, and remark-stringify. I found all of this to be a bit of a headache, and is certainly one of the downsides of using Ghost as a content provider. I've reached out to the team to try and start a discussion about returning a raw Markdown field from the posts API.

Here's how the HTML processing works:

import unified from 'unified'\nimport parse from 'rehype-parse'\nimport rehype2remark from 'rehype-remark'\nimport stringify from 'remark-stringify'\nimport Markdown from 'react-markdown';\n\nconst PostBody({ post }) {\n  const md = unified()\n    .use(parse)\n    .use(rehype2remark)\n    .use(stringify)\n    .processSync(post.html)\n    .toString()\n\n  return <Markdown>{md}</Markdown>\n}

Unfortunately I have more work to do to dig into the internals of how the HTML is being parsed - I noticed that it strips out things like alt tags on images, and entire iframes if I use video embeds.

My source files are here if you would like to dig around further - if you happen to know of solutions to these parsing woes, please let me know!

"},{"__typename":"Post","id":"5e63e21fb6a909003848a14d","title":"Product Design Portfolios","slug":"product-design-portfolios","updated_at":"2020-10-12T23:59:38.000-04:00","excerpt":"A living list of useful and inspiring product design portfolios.","feature_image":null,"html":"

I've been maintaining this list of useful and inspiring product design portfolios for a few years. It's awesome to see people sharing their work experiences openly and putting their own personal touch on their website. As the list grew, people told me that it was a useful reference while creating their own portfolio.

I'll be keeping the list up to date over time, so please let me know if you find a broken link or if someone removed their portfolio!

My criteria is loose, but generally:

Here's the list. If I'm missing anyone, please drop me a note at the bottom of this post!

Did I miss someone? Let me know in the form below and I'll keep this post updated 🙏

Update: @chris_mrtn compiled a bunch of these people into a Twitter list.

"}],"episodes":[{"__typename":"Episode","id":"56ed71e3-3d3c-4864-8c03-328b5b1f8fca","description":"This week, we discuss the career paths and tradeoffs for someone who wants to do both design and development. In The Sidebar, we recap the Mac event and share our first impressions of the new iPhones.","legacy_id":null,"long_description":null,"published_at":"2020-11-18T05:00:00-08:00","status":"published","title":"373: Designer or Developer?","token":"w0BtPjE6"},{"__typename":"Episode","id":"67e771ea-75a5-444c-a782-43870778e954","description":"This week, we brainstorm design patterns that help save people from themselves. From stopping the spread of misinformation, to saving eardrums, to screening spoilers, these design ideas are often clever and non-obvious. In the Sidebar, we discuss why radio and checkbox inputs are the way they are, and how to use them well in your designs.","legacy_id":null,"long_description":null,"published_at":"2020-11-11T05:00:00-08:00","status":"published","title":"372: Saving People from Themselves","token":"kyGys20W"},{"__typename":"Episode","id":"8c0e380f-391c-4a09-b325-b2951e42639a","description":"This week, we dig into practical steps for creating a culture of design excellence. In The Sidebar, we share strategies for designing adaptive interfaces that work well on any screen size.","legacy_id":null,"long_description":null,"published_at":"2020-11-04T05:00:00-08:00","status":"published","title":"371: A Culture of Excellence","token":"ssaB2TuT"},{"__typename":"Episode","id":"4fdca077-4562-4da5-911b-ef311258dd32","description":"This week, we discuss the tradeoffs and challenges of designing interfaces for one-handed use. In The Sidebar, we talk about strategies for collaborating effectively with brand and product design.","legacy_id":null,"long_description":null,"published_at":"2020-10-28T05:00:00-07:00","status":"published","title":"370: Designing for One Hand","token":"aUyTuSBj"},{"__typename":"Episode","id":"b59b7bc1-c82f-4228-9b0f-c8ba6dd612f5","description":"This week, we talk about the shallow parts of design culture, where superficial work tends to generate far more attention and praise. We dig into potential solutions for this, too. In The Sidebar, we recap and share our spicy takes on the iPhone 12, iPhone 12 Pro, and HomePod mini.","legacy_id":null,"long_description":null,"published_at":"2020-10-21T05:00:00-07:00","status":"published","title":"369: Shallow Design Culture","token":"DbfCgtd7"}]},"apolloStaticCache":{"Post:5fb15e3b0a17d00039ea5bfe":{"id":"5fb15e3b0a17d00039ea5bfe","__typename":"Post","title":"Design to Save People from Themselves","slug":"design-to-save-people-from-themselves","updated_at":"2020-11-15T13:42:06.000-05:00","excerpt":"How software can prevent people from making mistakes, causing permanent damage, or bringing about the collapse of democracy.","feature_image":null,"html":"
This post is a complement to episode 372 of Design Details, Saving People from Themselves.

Last week Divya Tak asked on Twitter \"but what are things that you do to 'save the users from themselves...'\" Marshall Bock and I spent an hour thinking about this question, recorded a podcast with our answers, and now we're publishing the conversation here for longevity.

This list is not exhaustive: there are a million more examples of software saving people from their own mistakes, insecurities, and ignorance – let us know what we missed by filling out the contact form at the bottom of this post!

Persist draft content

Great products work to ensure that people never lose unsaved changes or draft content. There are a few common patterns to do this:

Warn before destruction

This one is straightforward enough, but software should always warn people before taking destructive actions. Deleting or permanently modifying a document by mistake is a horrible feeling. Software, like iOS, guides developers to make destructive actions red, require confirmation (through an action sheet or an alert), and places the destructive confirmation button far away from your thumb (destructive actions always appear at the top of action sheets).

Undo

In interfaces where a user might accidentally trigger some kind of modification, but one that's not necessarily destructive, it's a good idea to provide a control to undo that action. Think: swiping an email to be Archived. Archiving an email is not destructive, but the undo button saves someone a lot of headache of having to dig back through menus to find an email that was accidentally swiped away.

Magic Undo

Sometimes you can provide an undo prompt for anything hasn't actually changed. It's like a fake undo, or a pre-undo. The best example is Gmail's \"email recall\" feature – if you send an email, Gmail doesn't actually send it right away. Instead, it prompts you to undo the send, and only after that prompt disappears does that email get sent.

Content scanning

Have you ever sent an email where you meant to attach a file, but just the act of typing \"see attached\" made you forget to actually attach the thing? Apparently this happened to enough people so that Gmail now looks for key phrases in a draft like \"see attached\" – if the email itself doesn't have an attachment, they will prompt for a confirmation before sending.

Code scanning

Similar to content scanning above, code scanning is a magical feature that prevents people from accidentally publishing passwords or secrets on GitHub. Secret scanning helps developers catch their mistakes before it brings down an entire organization.

Sensible defaults

Also known as convention over configuration: a software design paradigm used by software frameworks that attempts to decrease the number of decisions that a developer using the framework is required to make without necessarily losing flexibility.

Software should be built with sensible defaults to prevent people from having to make unconventional decisions. This is more beginner-friendly, but many experienced users also appreciate it when their tools clearly communicate best practices.

Tap targets

Apple and Google say that tap targets should be a minimum of 44pt and 48pt. That minimum part is important - it's totally fine to go bigger! If you can make a safe assumption about what a user is trying to tap or click, and there are no competing elements around that target, go ahead and make the target as big as possible. See an example of how this should work in Twitter for macOS.

Digital addiction

As of 2018, Americans spend more than 10 hours per day looking at a screen. Social media, algorithmic feeds, push notifications...these are all raw fuel for addictive tendencies, constantly pulling people back to the screen. Good software helps people to manage their time to ensure that it's time well spent. Do Not Disturb, Bedtime reminders, and Instagram's \"all caught up\" module all help nudge people towards better consumption habits.

Duplicate entry points

Software developers like to say \"don't repeat yourself\" as a mantra for simplifying and abstracting code. But in interface design, well-considered repetition can enhance the user experience. For example, imagine an application has settings to manage notification preferences. In a DRY world, the entry point to manage your notification preferences would only appear by navigating to some Settings view, first. But in a user-friendly world, there would be a duplicate entry point in context on the Notifications view itself.

Volume warnings

Companies like Apple have been actively investing in raising awareness about hearing damage and safe volume ranges. Software can help nudge people to turn down their headphones and save their eardrums. My younger self would have appreciated this.

Age-gating, NSFW warnings

On algorithmic feeds, like Twitter, Instagram, Facebook, or Reddit, it's inevitable that at some point something...unsavory...might appear. If you're browsing at work, blurring that content can be a professional life saver. In other cases, providing interstitial warning screens – like this one from Reddit – might prevent people from accidentally opening a link with content they wouldn't want any lurking eyes to see.

Spoiler obfuscation

While it's not part of the official Markdown spec, apps like Reddit and Discord have extended the syntax to allow for a special way to hide spoilers. Please, Twitter...

Rage shake

It's hard to say exactly how good this is, because it's basically impossible to discover. But on iOS, and in many individual applications, there is a \"rage shake\" function that prompts a system activity. On iOS, a shake gesture is the universal trigger for undo. On other apps (I remember encountering this on Facebook's internal beta apps), a quick \"rage shake\" will prompt a bug reporting mechanism, allowing users to vent any frustrations directly to developers.

This bit from Daring Fireball is hilarious, too:

Lastly, here’s an anecdote I heard years ago about how Shake to Undo came to be. Scott Forstall charged the iOS team with devising an interface for Undo — everyone knew the iPhone should have it,1but no one had a good idea how to do it. One engineer joked that they could just make you shake the iPhone to invoke it. Forstall said he loved the idea, and what was proposed as a joke has been with us as the Undo interface ever since.

Preventing the spread of misinformation

Facebook, Twitter, WhatsApp, Instagram, and every other major social platform are building new systems to prevent people from inadvertently spreading misinformation.

A few patterns are emerging:

Twitter does both – not only does a flagged tweet have a contextual link to learn more, but if you click on the retweet button, they show a popover warning that the underlying claim is disputed.

Facebook, Twitter, WhatsApp, and many other apps are now introducing warnings that appear when people share articles without reading them first.

Encouraging civility, reducing toxicity

Instagram has a feature that warns users when they are about to leave toxic comments on a post. This prompt might help people to calm down if they were leaving a comment in the heat of a moment. More generally, prompts like this remind people that there is another human on the other side of that screen, and that our words matter.

Further reading

For more notes about what it means to build great digital products, read Quality Software.

Let us know what we missed in this list! I'll be updating this post over time with new ideas and screenshots.

"},"Post:5fa89bd9c795260039b568c6":{"id":"5fa89bd9c795260039b568c6","__typename":"Post","title":"True Respect is the Difference","slug":"true-respect-is-the-difference","updated_at":"2020-11-09T00:22:53.000-05:00","excerpt":"True respect is the difference between a fantastic collaborator and an asshole.","feature_image":null,"html":"

Last week I tweeted:

Got told \"this is lame\" about one of my mocks, and you know what? I'm here for that energy. Could've been a much longer \"what do you think about...? did you try...?\" conversation, but sometimes the bluntness is just right.

This response from Hans captured another meaning behind my message:

“this is lame” can be a sign of a bad team, but also of a fantastic team. true respect is the difference.

After reading this response, I started wondering: how many relationships do I have where giving candid feedback happens by default? How many people do I think would give me blunt feedback, if asked? If the ability to give and receive candid feedback is a proxy for respect between peers, I want this number to go up.

This made me wonder: if I am going to be intentional about growing this number over time, what should I continue to do, stop doing, or start doing in the next year?

Three things came to mind:

Ask for bluntness from the right people, at the right time.

Sometimes I've found myself asking for feedback from a peer or manager when I was secretly looking for praise. Fishing for compliments like this is no way to actually improve, so the first step is to stop doing this. If I'm going to ask for feedback, then I want the feedback to be substantial; something that will actually help me to grow and improve a design.

This means asking for feedback from the right people at the right time. The right people are going to be those with expertise in the area where I'm working, or people who I feel have exceptional taste and judgment. The right times are usually in private, after I feel that I've truly exhausted my own personal abilities to make a design as good as possible.

One mistake I've made in the past is asking for feedback too early, essentially looking for someone to co-design. Most of the time, this is lazy. Of course, there's tension between asking for feedback too early and too late: when a project is about to ship, and any real critique is unlikely to have material impact on the design, that feedback goes to waste.

One of the cool things about working with the same people for long periods of time is that you start to understand how they think, and you can anticipate their questions. This is always a good gut check: if I can anticipate a question, and haven't done the work to have a thoughtful answer, it's too early to ask for feedback.

Look for permission to initiate.

If I expect blunt feedback from people I respect, it follows that they might also expect blunt feedback from me (assuming of course that they respect me). This means overcoming my own non-confrontational tendency, and identifying when other people are asking me for something deeper than surface level critique. And when that moment comes, I need to deliver thoughtful, kind feedback so that we can have a productive conversation, and hopefully continue the practice many times in the future.

Praise as candidly as I critique.

It feels really good to get blunt feedback from someone who I respect. But it feels even better to be told that I've done a good job from someone who actually means it. I want my praise to mean just as much to someone else as my critique. Praise should be honest. Trying to make someone feel good with a compliment only relieves pain temporarily, at the cost of being held back from true growth. It's a sign of disrespect.

"},"Post:5f9f478a02b84c0039a9e434":{"id":"5f9f478a02b84c0039a9e434","__typename":"Post","title":"Writing Better Self Reviews","slug":"writing-better-self-reviews","updated_at":"2020-11-01T21:03:05.000-05:00","excerpt":"My tips and strategies for writing effective self reviews.","feature_image":null,"html":"

Writing self reviews can be hard. For a lot of people, talking about themselves and their accomplishments feels a lot like bragging. Or it might just be hard to remember things that happened a few months ago. Or sometimes people are unsure what the expectations are for a review, and don't know what should be included to maximize their growth.

I've been lucky to have had a string of great managers in my career who helped me think more clearly about the self review and gave me tips to write them more effectively. Here are things I've learned that not only make self reviews easier to write, but have also led directly to raises and promotions.

Impact over volume of work

It's so tempting to write a self review that lists every single thing you did during the half. Look at all this stuff! Of course I deserve a promotion and praise and money!

The problem is that – much like building software – each thing added dilutes everything else. Too many small moments muddy the water of your major accomplishments.

Focus on the most impactful work you did (see: most impactful to the business, not to you personally). If you really feel it's necessary, add an appendix of sorts that serves as your vomit-list of all the smaller things, which in aggregate might match the weight of one higher-impact contribution.

Map impact to levels

If your goal is to get a promotion or grow within your organization's career ladder, you should explicitly map your contributions to the level you're operating at and the level where you want to be. Here's a rough outline I've used in the past:

Here's where I think I made the biggest impact this half, meeting or exceeding expectations for {CURRENT LEVEL}:
1. Most significant point of impact
2. Second most significant point of impact
3. Third most significant point of impact
Here's how I think I met expectations for {NEXT LEVEL} consistently throughout the half:
1. Most significant point of impact
2. Second most significant point of impact
3. Third most significant point of impact

Mapping your contributions directly to expectations helps you to understand if your organization actually values your work. But more importantly, by articulating where you are operating at the next level up, it makes it easier to answer the question: do I deserve a promotion?

Not being explicit about how your contributions meet the expectations of your target level just means that your manager will have to do this on your behalf, in their own words.

Bring reviewers along for the ride

I'm a big believer in \"no surprises at review time.\" Any negative or constructive feedback I give or receive should never be new information. I would consider it a failure of organizational culture to be entirely blind-sided by downwards or peer feedback. Mid-cycle reviews, ad hoc feedback, and a regularly scheduled 1:1 with a manager all exist to help people work out problems in the moment, with compassion and kindness.

This \"no surprises\" principle applies to both negative and positive reviews: I never want my manager to be surprised by any significant work I have been doing throughout the review cycle. This increases the likelihood of that manager missing context, not having time to understand the impact of the work, and fumbling a clear explanation of that work during calibration meetings.

Bring your manager along for the ride by proactively sharing your work and contributions throughout the half. No surprises at review time!

Work journaling

It seems safe to assume that at one point or another almost everyone has hit review season and thought to themselves: what the hell did I even do this half? It's okay to do that once, early on in your career. But don't let it happen twice.

I recommend keeping a list of ongoing accomplishments and achievements throughout each half. Write things down as they happen. Your future self will love you. Personally, I have a section in Things called \"Self review notes\" and I just quickly jot down a new to-do item whenever I make some contribution at work.

Then, when it comes time to write my self review I actually tick each item off as \"done\" whenever it gets included. This gives me a clear, chronological list of things that my past-self deemed important, and it makes the writing itself as trivial as expanding to-do items into sentences.

Another strategy here that I have been learning from Marshall Bock on Design Details (episode 363 to be specific) is to maintain a \"work journal.\" This is an ongoing document that includes notes from all of your day-to-day work. I recommend listening to the episode to learn the basics, but one of the best ideas in this practice is to use a short list of verbs to describe your day to day work. For example, participated in or contributed to or shipped.

By doing this, you can simply command + f the document during review time and look up a specific verb to see all the instances where you were doing that kind of work.

Regardless of the tools or system, just keep a note of things as they happen. I recommend reviewing these notes monthly, aggregating items with similar themes, and deleting things that felt important in the moment but didn't have as much impact as you had hoped.

Make manager advocacy easy

Performance reviews don't live in a vacuum. They are compared, calibrated, and discussed across many people and levels of the organization. It takes time, energy, and attention from managers to clearly and concisely communicate your impact to people who may have been less involved in your week-to-week work (like a skip-level manager). Because of this, it's important to make it as easy as humanly possible to help your manager advocate on your behalf.

To do this, it's better to keep your review short. But in that shortness, the actual structure of your review makes a difference. Bullet lists are easier to parse than walls of text. Simplify, simplify, simplify.

I think to myself: \"how would my manager give an elevator pitch to another manager about my contributions this last half?\" In other words, if my manager had to summarize my impact in a sentence or two, to someone who knows nothing about what I did in the past six months, what would that sound like? To make this easier for them, I like to open my self review with a 2-3 paragraph section that describes my themes of impact for the half.

Follow through

Most self reviews will have a section that asks something to the effect of: what will you do to grow in the next half? And you'll fill that out and hit submit and go on with your life.

Those things you said you wanted to improve are now your goalpost for next half. You should review those notes regularly and check in to see if you're on track. If your goals changed, you must ask yourself \"why?\" And if you're falling behind, it's a nice kick in the pants to get back on track.

I always start writing my self reviews by re-reading my previous review. Did I actually do the things I said I was going to do? Did I grow in the ways that I wanted to six months ago? This approach keeps you accountable to yourself, and demonstrates that you are intentional about your growth within the organization.

If you don't follow through here, then you're just bullshitting.

Recap
  1. Only write about the things that had the highest impact on the business. And yes, impacting the culture of an organization counts as impact on the business.
  2. Map your work directly to expectations for the level where you want to be. Make your promotions intentional.
  3. There should be no surprises at review time. Bring your manager along for the ride throughout the half so they have context and clarity about how your work has impact on the business.
  4. Don't wait until the day before your review to scratch together a list of your contributions from the past six months. Keep an ongoing list of your accomplishments, add to it daily, and curate monthly.
  5. Make it ridiculously easy for your manager to advocate for you when you're not in the room. Make the themes of your impact crystal clear, and make your review easy to read.
  6. Follow through on your previous reviews. Fill in your gaps that you identified six months ago. Show intentional commitment to growth by doing the things you said you were going to do.
"},"Post:5dea5ce1295515003754d9e4":{"id":"5dea5ce1295515003754d9e4","__typename":"Post","title":"Using Ghost as a Headless CMS with Next.js","slug":"using-ghost-headless-cms-next-js-to-create-a-fast-and-simple-blog","updated_at":"2020-10-27T14:25:53.000-04:00","excerpt":"Rebuilding my self-hosted blog with Next.js and Ghost as a headless CMS.","feature_image":"https://overthought.ghost.io/content/images/2019/12/ghost---next-1--1-.png","html":"

I recently rebuilt most of my personal site with the main goal of providing a better surface area for writing. There are dozens of viable technology choices available right now to create a self-hosted blog and I spent way too long, and way too much energy trying to find the perfect one.

Spoiler alert: there is no perfect system. Every solution is a hack. Once I accepted this, I could focus on finding the least-hacky setup that would cover 90% of my needs. Ultimately, I ended up building the following system:

Getting data from Ghost

The Ghost API is pretty solid - the documentation is straightforward, and they even have a guide for working with Next.js.

To start, I added a small API file that can fetch data from Ghost:

import GhostContentAPI from \"@tryghost/content-api\";\n\nconst api = new GhostContentAPI({\n  url: 'https://overthought.ghost.io',\n  key: 'API_KEY',\n  version: \"v3\"\n});\n\nexport async function getPosts() {\n  return await api.posts\n    .browse({\n      limit: \"all\"\n    })\n    .catch(err => {\n      console.error(err);\n    });\n}\n\nexport async function getPostBySlug(slug) {\n  return await api.posts\n    .read({\n      slug\n    })\n    .catch(err => {\n      console.error(err);\n    });\n}

We can then use these API calls to populate data into a page. Here's a simplified version of my src/pages/overthought/index.tsx file:

import * as React from 'react';\nimport Page from '../../components/Page';\nimport OverthoughtGrid from '../../components/OverthoughtGrid'\nimport { getPosts } from '../../data/ghost'\nimport { BlogPost } from '../../types'\n\ninterface Props {\n  posts?: Array<BlogPost>\n}\n\nfunction Overthought({ posts }: Props) {\n  return (\n    <Page>\n      <OverthoughtGrid posts={posts} />\n    </Page>\n  );\n}\n\nOverthought.getInitialProps = async ({ res }) => {\n  if (res) {\n    const cacheAge = 60 * 60 * 12;\n    res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);\n  }\n  const posts = await getPosts();\n  return { posts: posts }\n}\n\nexport default Overthought

In the getInitialProps call, which runs server-side, I decided that caching the entire page for 12 hours at a time was probably safe: I won't be publishing that frequently. This will improve performance if there is any spike in traffic that would otherwise overload the Ghost API.

Client-side caching

It's a bit overkill for now, but one thing that I've been meaning to try is SWR. This package does some cool client-side work to provide data revalidation on refocus, retries on failure, polling, and client-side caching.

One key thing that I wanted to solve for was people navigating between the home page of my site and the /overthought route. These pages both fetch the same posts, so it'd be a waste to require the second fetch to resolve before rendering my list of posts.

Before SWR, I might have reached for a tool like React.useContext to provide some kind of global state wrapper that would keep track of any previously-fetched posts. But Context can get messy, and I hate adding hierarchy to my components.

SWR solves the problem by maintaining a client-side cache of data I've fetched, keyed by the route used for the request. When a user navigates from / to /overthought, SWR will serve stale data from the cache first and then initiate a new request to update that cache with the latest data from the API.

At the end of the day, the same number of network requests are being fired. But the user experience is better: the navigation will feel instant because there's no waiting for a new network request to Ghost to resolve. Here's how our page from above looks with SWR:

import * as React from 'react';\nimport Page from '../../components/Page';\nimport OverthoughtGrid from '../../components/OverthoughtGrid'\nimport { getPosts } from '../../data/ghost'\n\nfunction Overthought({ posts }) {\n  const initialData = props.posts\n  const { data: posts } = useSWR('/api/getPosts', getPosts, { initialData })\n  \n  return (\n    <Page>\n      <OverthoughtGrid posts={posts} />\n    </Page>\n  );\n}\n\nOverthought.getInitialProps = async ({ res }) => {\n  if (res) {\n    const cacheAge = 60 * 60 * 12;\n    res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);\n  }\n  const posts = await getPosts();\n  return { posts: posts }\n}\n\nexport default Overthought

With the two added lines at the top of the function, we instantly get data served from the client-side cache. The cool thing about this setup is that if the user loads a page that is server-side rendered, SWR will receive initialData that was already fetched on the server, again creating the feeling of an instantaneous page load.

Again: this is overkill.

Rendering post content

My one issue  with Ghost is that they don't return a Markdown version of your posts. Instead, they only return a big string containing all of the HTML for your post. Rendering this HTML string can be a pain: Ghost has a lot of custom elements that they use for rich embeds, like videos, that I don't want to be ingesting.

So instead I was able to hack around this by using react-markdown in conjunction with unified, rehype-parse, rehype-remark, and remark-stringify. I found all of this to be a bit of a headache, and is certainly one of the downsides of using Ghost as a content provider. I've reached out to the team to try and start a discussion about returning a raw Markdown field from the posts API.

Here's how the HTML processing works:

import unified from 'unified'\nimport parse from 'rehype-parse'\nimport rehype2remark from 'rehype-remark'\nimport stringify from 'remark-stringify'\nimport Markdown from 'react-markdown';\n\nconst PostBody({ post }) {\n  const md = unified()\n    .use(parse)\n    .use(rehype2remark)\n    .use(stringify)\n    .processSync(post.html)\n    .toString()\n\n  return <Markdown>{md}</Markdown>\n}

Unfortunately I have more work to do to dig into the internals of how the HTML is being parsed - I noticed that it strips out things like alt tags on images, and entire iframes if I use video embeds.

My source files are here if you would like to dig around further - if you happen to know of solutions to these parsing woes, please let me know!

"},"Post:5e63e21fb6a909003848a14d":{"id":"5e63e21fb6a909003848a14d","__typename":"Post","title":"Product Design Portfolios","slug":"product-design-portfolios","updated_at":"2020-10-12T23:59:38.000-04:00","excerpt":"A living list of useful and inspiring product design portfolios.","feature_image":null,"html":"

I've been maintaining this list of useful and inspiring product design portfolios for a few years. It's awesome to see people sharing their work experiences openly and putting their own personal touch on their website. As the list grew, people told me that it was a useful reference while creating their own portfolio.

I'll be keeping the list up to date over time, so please let me know if you find a broken link or if someone removed their portfolio!

My criteria is loose, but generally:

Here's the list. If I'm missing anyone, please drop me a note at the bottom of this post!

Did I miss someone? Let me know in the form below and I'll keep this post updated 🙏

Update: @chris_mrtn compiled a bunch of these people into a Twitter list.

"},"Episode:56ed71e3-3d3c-4864-8c03-328b5b1f8fca":{"id":"56ed71e3-3d3c-4864-8c03-328b5b1f8fca","__typename":"Episode","description":"This week, we discuss the career paths and tradeoffs for someone who wants to do both design and development. In The Sidebar, we recap the Mac event and share our first impressions of the new iPhones.","legacy_id":null,"long_description":null,"published_at":"2020-11-18T05:00:00-08:00","status":"published","title":"373: Designer or Developer?","token":"w0BtPjE6"},"Episode:67e771ea-75a5-444c-a782-43870778e954":{"id":"67e771ea-75a5-444c-a782-43870778e954","__typename":"Episode","description":"This week, we brainstorm design patterns that help save people from themselves. From stopping the spread of misinformation, to saving eardrums, to screening spoilers, these design ideas are often clever and non-obvious. In the Sidebar, we discuss why radio and checkbox inputs are the way they are, and how to use them well in your designs.","legacy_id":null,"long_description":null,"published_at":"2020-11-11T05:00:00-08:00","status":"published","title":"372: Saving People from Themselves","token":"kyGys20W"},"Episode:8c0e380f-391c-4a09-b325-b2951e42639a":{"id":"8c0e380f-391c-4a09-b325-b2951e42639a","__typename":"Episode","description":"This week, we dig into practical steps for creating a culture of design excellence. In The Sidebar, we share strategies for designing adaptive interfaces that work well on any screen size.","legacy_id":null,"long_description":null,"published_at":"2020-11-04T05:00:00-08:00","status":"published","title":"371: A Culture of Excellence","token":"ssaB2TuT"},"Episode:4fdca077-4562-4da5-911b-ef311258dd32":{"id":"4fdca077-4562-4da5-911b-ef311258dd32","__typename":"Episode","description":"This week, we discuss the tradeoffs and challenges of designing interfaces for one-handed use. In The Sidebar, we talk about strategies for collaborating effectively with brand and product design.","legacy_id":null,"long_description":null,"published_at":"2020-10-28T05:00:00-07:00","status":"published","title":"370: Designing for One Hand","token":"aUyTuSBj"},"Episode:b59b7bc1-c82f-4228-9b0f-c8ba6dd612f5":{"id":"b59b7bc1-c82f-4228-9b0f-c8ba6dd612f5","__typename":"Episode","description":"This week, we talk about the shallow parts of design culture, where superficial work tends to generate far more attention and praise. We dig into potential solutions for this, too. In The Sidebar, we recap and share our spicy takes on the iPhone 12, iPhone 12 Pro, and HomePod mini.","legacy_id":null,"long_description":null,"published_at":"2020-10-21T05:00:00-07:00","status":"published","title":"369: Shallow Design Culture","token":"DbfCgtd7"},"ROOT_QUERY":{"__typename":"Query","posts({\"first\":5})":[{"__ref":"Post:5fb15e3b0a17d00039ea5bfe"},{"__ref":"Post:5fa89bd9c795260039b568c6"},{"__ref":"Post:5f9f478a02b84c0039a9e434"},{"__ref":"Post:5dea5ce1295515003754d9e4"},{"__ref":"Post:5e63e21fb6a909003848a14d"}],"episodes":[{"__ref":"Episode:56ed71e3-3d3c-4864-8c03-328b5b1f8fca"},{"__ref":"Episode:67e771ea-75a5-444c-a782-43870778e954"},{"__ref":"Episode:8c0e380f-391c-4a09-b325-b2951e42639a"},{"__ref":"Episode:4fdca077-4562-4da5-911b-ef311258dd32"},{"__ref":"Episode:b59b7bc1-c82f-4228-9b0f-c8ba6dd612f5"}]}},"summaries":[{"title":"NeuBible","slug":"neubible-ios","tint":"#ee3f49","firstDetail":{"description":"This is one of the better reading experiences I've seen in an app. I'd argue that the left and right margins are a *tad* too large, but otherwise the vertical rhythm of the entire app is seamless. I love the snap-to-chapter interaction whenever you scroll past the current section; it feels great to use and has enough rubber-band tension to make it super obvious that you've transitioned to a new chapter.","title":"Reading","media":["https://player.vimeo.com/external/167672855.hd.mp4?s=6a61e147b1a5f57183bb396c65d0abab81000bf2&profile_id=174"]},"detailsCount":14},{"title":"Shorts","slug":"shorts-ios","tint":"#fda052","firstDetail":{"description":"See, once you get past the notifications request I can finally start to parse out what this app is and what kind of value it provides. \"Follow people's camera rolls\" sounds interesting, if not a bit on the extreme side of messaging. How will it work? Will I be automatically sharing my camera roll if I sign up?\r\n\r\nI'm a bit hesitant, but continue on through signup.\r\n\r\nAs far as visuals go, Shorts has killed it. But that was no surprise once I realized the [Highlight](http://highlig.ht/) team is behind this product. Clean and simple with a bright and inviting color palette - nicely done.","title":"Sign up","media":["https://player.vimeo.com/external/160549086.hd.mp4?s=24feda10316ef4b66ed8c5d8b418e15d55e0903f&profile_id=113"]},"detailsCount":16},{"title":"Stripe","slug":"stripe-dashboard-ios","tint":"#2289ca","firstDetail":{"description":"Microinteractions like these add value to the entire user experience. Rather than being jostled around with static view changes, Stripe helps introduce people to their dashboard with motion. Animation also buys Stripe time to load data in the background while preserving an experience that feels snappy and responsive. ","title":"Login","media":["https://player.vimeo.com/external/157887682.hd.mp4?s=4c3661c90aa158f993985c4c85767b8ca91c755f&profile_id=167"]},"detailsCount":14},{"title":"Quartz","slug":"quartz-ios","tint":"#1d1d1d","firstDetail":{"description":"Nicely done, Quartz: teach users how to use the app by having them actually complete the functions themselves. It’s clever and helps users build momentum in the onboarding experience.\r\n\r\nIt has become standard user experience practice to tell people that you’re going to ask them for notification permission before the popup appears. Quartz handles this nicely by explaining why notifications are useful. Opting in or out is totally fair game, but that emoji in the confirmation option is oh-so enticing.","title":"Teaching","media":["https://player.vimeo.com/external/157882203.hd.mp4?s=f481ea76419df041aeeb241fbbaf091596971851&profile_id=113"]},"detailsCount":11}]},"__N_SSG":true}