<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Grant Norwood on Medium]]></title>
        <description><![CDATA[Stories by Grant Norwood on Medium]]></description>
        <link>https://medium.com/@grantnorwood?source=rss-7ad79dd65634------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*TtBHTeaU-DGLsqBHmgf6QA.png</url>
            <title>Stories by Grant Norwood on Medium</title>
            <link>https://medium.com/@grantnorwood?source=rss-7ad79dd65634------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 17:55:13 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@grantnorwood/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Nullability in GraphQL]]></title>
            <link>https://medium.com/expedia-group-tech/nullability-in-graphql-b8d06fbd8a3c?source=rss-7ad79dd65634------2</link>
            <guid isPermaLink="false">https://medium.com/p/b8d06fbd8a3c</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[nullability]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[schema-design]]></category>
            <dc:creator><![CDATA[Grant Norwood]]></dc:creator>
            <pubDate>Tue, 23 Jul 2019 16:46:21 GMT</pubDate>
            <atom:updated>2019-07-23T16:46:21.299Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Kl-0jt39GIq4cWEFsFD2gg.png" /><figcaption>Image: Grant Norwood</figcaption></figure><h4>Nullability in GraphQL unlocks improvements in resiliency, graceful UI degradation, frictionless user workflows, and other benefits</h4><p>Whether you prefer “schema first” or “resolver first”, GraphQL development should definitely be <strong>“types first”</strong>. One aspect of planning your data types is <strong>nullability</strong>, and this is important to get right. Nullability in GraphQL is different than how we handle null values in other environments, like REST or gRPC APIs. You see, we expect a RESTful endpoint to either return an object, a list, or other piece(s) of data as a whole — or not at all. If a REST GET operation fails, we expect the entire request to have failed — not just a subset of the operation.</p><h3>GraphQL is inherently different</h3><p>However, that’s not how GraphQL rolls. It’s entirely acceptable and likely that <em>most</em> of your data graph will load successfully, <em>except</em> a small part will fail due to the composition of the many micro-services responsible for populating all of that data. When all of the fields in a type are marked as “non-nullable” (using the !), a failure can no longer occur gracefully.</p><blockquote>Said differently, if any one non-nullable field defined in your type is ever null, or its resolver throws an exception, the entire query fails. <em>Not cool.</em></blockquote><h3>Consider this example …</h3><p>We’ve started a new schema for our <a href="http://www.vrbo.com/">Vrbo</a> app, and have defined a VacationRental and its associated types. Notice how everything is non-nullable by default, a common yet problematic approach when creating a new schema:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f723ae4415f80606bdf1159de71f9229/href">https://medium.com/media/f723ae4415f80606bdf1159de71f9229/href</a></iframe><p>Let’s look at some of the problems this can lead to, and how we might better approach this initial schema creation …</p><h3>Nullability is important to users</h3><p><em>Kinda.</em> They don’t care what it is, but it definitely affects their experience. Using nullable fields in your GraphQL projections means that when <em>(not if)</em> one or more parts of a screen fail, the rest of the screen may remain perfectly usable <em>(yay!)</em>. But it’s a real problem if a less-critical portion of your data becomes unavailable due to a database outage, or a hiccup in your network, or a good ol’ act of God, and suddenly your user cannot be successful in achieving whatever one thing was most important to them on that screen.</p><h3>Allow your screen to fail gracefully</h3><p><em>Think about our vacation rental example …</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*aOF6eORehC_JyXkdW6SAqA.jpeg" /><figcaption>Image: Grant Norwood</figcaption></figure><p>If the owner of a vacation rental property is viewing their Property Editor screen, attempting to write an impactful headline and illustrative description for their new property, it’s not important that something small like an Inbox Notification shown in the Top Nav Bar fails. If the Notifications service is down for 20 mins, and the inboxNotifications field returns null, the rest of the query still succeeds and the Owner can accomplish their primary goal on that screen — playfully word-smithing the content that guests will see when viewing their property.</p><p>Let’s update our example to allow inboxNotifications to have a null value, meaning if the Notifications service fails, the property owner can still edit their listing:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/436ac06a0f86095d3a2e8b69c08ec630/href">https://medium.com/media/436ac06a0f86095d3a2e8b69c08ec630/href</a></iframe><p>If your entire query fails, your UI can’t allow your user to have at least some success, or to be shown a specific and helpful message. When the entire query fails, all you can do is tell your user “Something broke, please try again” <em>(even though you and I both know it won’t work when they try again).</em></p><blockquote>Users care that your app is resilient, and nullable fields on your GraphQL types allow portions of your screen to fail gracefully while the rest of the screen remains usable.</blockquote><p><strong>Think of nullable fields as error boundaries, which will likely align with the API service boundaries behind your GraphQL server</strong> 🤔</p><h3>Offer a frictionless user flow</h3><p>If we want to allow a property owner to <strong>incrementally</strong> save their progress while listing their gorgeous home for rent, we can’t require every field to be populated at once. If a user first enters the listing title, then description, then address — and each time the screen auto-saves their progress for a frictionless experience and a saved backup in case their computer and/or network starts acting up — then you must allow those fields to be nullable.</p><p><em>Let’s update our VacationRental type to be more flexible and enable that user experience …</em></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dd562b91736ed1c28fbf429a5d7e6347/href">https://medium.com/media/dd562b91736ed1c28fbf429a5d7e6347/href</a></iframe><p>Now our typedef allows each field within our UI to be saved automatically as a user progresses through their workflow. <em>Neato!</em></p><h3>Describe your domain</h3><p>Nullable fields in GraphQL should be used to accurately describe the business domain rules. For example, a company may require all owners to enter their name, email, and phone so that guests can reach them.</p><p>But perhaps you don’t require every owner to have a twitterHandle, because not everybody twitters. <em>Let’s make that change, too:</em></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b902c9a7c0475f24e0899bf79fe4875e/href">https://medium.com/media/b902c9a7c0475f24e0899bf79fe4875e/href</a></iframe><h3>Facebook’s best practices</h3><p><a href="https://graphql.org/learn/best-practices/#nullability">In the GraphQL docs, the Best Practices page</a> advises you begin defining types using nullable fields, and only later might you decide to indicate specific fields as non-nullable <strong>when such a guarantee can actually be made</strong>. But by default, allowing fields to be nullable improves the resiliency of the larger data graph:</p><blockquote>“… in a GraphQL type system, every field is nullable by default. This is because there are many things which can go awry in a networked service backed by databases and other services. A database could go down, an asynchronous action could fail, an exception could be thrown.”</blockquote><p>Yes, this might result in more null checks throughout your system, but you should probably be doing some of those anyway !</p><p>If you’re working with JavaScript, things will get easier soon. <a href="https://github.com/tc39/proposal-optional-chaining">Optional Chaining is at Stage-2 in TC39</a>, and there’s a <a href="https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining">Babel plugin</a> if you just can’t wait <em>(some languages already have this feature, like </em><a href="https://docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html"><em>Swift</em></a><em>)</em>. And it’s much more painful trying to ensure that never once will any of your field data return null. <em>(Good luck with that, though!)</em></p><h3>But non-nullable is good, too!</h3><p><em>Yup, it sure is!</em> Let’s talk about when it’s a good idea to begin your schema design with non-nullable fields, because I’m definitely not preaching we should “nullable all the things!”</p><h4>SOME TYPES DON’T MAKE SENSE WITHOUT REQUIRED FIELDS</h4><p><em>Let’s look at the </em><em>GeoLocation and </em><em>Notification types in the example …</em></p><p>A GeoLocation makes no sense at all with just a latitude, or just a longitude. And a Notification within your system will <em>always</em> contain a timestamp and a message, because it’s enforced in your nice type-safe backend. The amount of a Price isn’t enough to generate a transaction if you don’t know what currency is to be used.</p><p>There’s no reason to ever allow nulls in those fields, so we’ll leave those marked as non-nullable. This reduces your <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity"><strong>cyclomatic complexity</strong></a>, which is important to the amount of null checks <em>(read: lines of code)</em> you must write in your front-end to avoid errors, as well as the number of unit tests you must write to achieve good test coverage.</p><p><strong>This increased verbosity, complexity and required tests is a great reason to always ask yourself, <em>“Is it worth it to allow this field to actually be null?</em></strong>” 🤷‍♂️</p><h3>Go faster, and go backwards</h3><p>When you’re spinning up a new data graph, your project is probably evolving quickly with a team of people. Leaving GraphQL fields nullable frees you up to iterate faster, be flexible, and allow you to defer decisions about your data until the <a href="https://blog.codinghorror.com/the-last-responsible-moment/">last responsible moment</a>.</p><p>Some of those decisions are harder to ⌘-Z than others. Beginning your data graph with nullable type fields, then later on converting some fields to non-nullable <strong>is backwards-compatible</strong>. However, when you mark those fields as non-nullable from the start, it’s a lot more difficult to make them nullable later on, as there may be code in the wild that calls that data without null checks and your apps could crash.</p><p><em>This might be the opposite of how your input parameters work, but you’re probably still safer to start off with nullable parameters and enforce those required fields in your code if necessary.</em></p><h3>The final schema</h3><p>So after much pondering, we’ve made some important decisions about our schema. Here’s what I had as the first version in my head, is it what you would’ve done?</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/853d6343955388910ed87b409f5e5657/href">https://medium.com/media/853d6343955388910ed87b409f5e5657/href</a></iframe><p>Interested in solving complex, consumer-facing problems like this? <a href="https://lifeatexpedia.com/jobs">Join us</a>, and together, let’s bring the world within reach.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b8d06fbd8a3c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/expedia-group-tech/nullability-in-graphql-b8d06fbd8a3c">Nullability in GraphQL</a> was originally published in <a href="https://medium.com/expedia-group-tech">Expedia Group Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The .1 Release is the Listening Release]]></title>
            <link>https://medium.com/@grantnorwood/the-1-release-is-the-listening-release-17d65d3848c7?source=rss-7ad79dd65634------2</link>
            <guid isPermaLink="false">https://medium.com/p/17d65d3848c7</guid>
            <category><![CDATA[design]]></category>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[ux]]></category>
            <dc:creator><![CDATA[Grant Norwood]]></dc:creator>
            <pubDate>Sat, 28 Nov 2015 20:26:30 GMT</pubDate>
            <atom:updated>2015-12-02T16:59:33.377Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hYzS3gn3auppqE3oZdzofg.jpeg" /></figure><p>Developers love to launch. It’s the culmination of weeks or months of work <em>(if it’s years, you better be building an operating system)</em> and the public is about to see what you’ve created. But it’s far from the end of your big release.</p><p>And if you’re juggling multiple projects, it’s tempting to wipe your hands clean after a site or app launches, and change your full focus to a new project. This is especially true when your team has truly done their best to maintain quality throughout the design and development process. You’ve thought of everything, tested with a small group of trusted users, and you only had so much time booked in the calendar, so you call it done.</p><blockquote>pressLaunchButton();<br>onToNextProject();</blockquote><p>What may be missing from your schedule is the <strong>“.1 release”</strong>.</p><p>A recent launch of an intranet portal is a great example. Our team did a fantastic job of innovating during the design &amp; dev phases, as well as leveraging some cool new interaction methods and technical integrations (new to us anyway!) We estimated our development time reasonably well, and set the expectations with ourselves that we were delivering a 1.0 release, and we’d come back soon to address all of the experiential things that we knew users would have to tolerate for a bit (e.g., slower-than-ideal authentication/authorization on first load) while we focused on a different project with a totally different set of end users.</p><p><em>That was almost 6 months ago.</em></p><p>The problem is that because there was another high-priority project waiting in the queue, we consciously skipped the .1 release of the previous project. But the .1 release is the release where you monitor the application and the experience your users are having, and respond to their needs quickly. The .1 release is where we make good on all those IOUs we made while disclaiming “we must deliver <em>something</em> now, we committed to a date and we’ll get in trouble if we miss it”, and that each of their individual needs will be addressed in the next version. This is all fairly standard and valid, as long as you actually plan the time in your project schedule necessary to listen to your users and improve their experience.</p><p>When we constantly deliver at 100% (or greater), we don’t give ourselves enough buffer. Not just setting aside time to mitigate known and unknown risks throughout a project (the latter is frequently forgotten), but buffer to sit back and listen after a major release. We should have confidence that we couldn’t possibly have gotten everything perfect for every user, so allocating time to ensure that even their smaller needs are addressed before we move on to another project is imperative. The small things may determine whether or not a user finds value in your product, and a healthy user growth curve is supported by happy users.</p><h3>The .1 Release is the “Listening Release”</h3><p>Once you’ve launched that first or other major release, celebrate the win! Get a good night’s sleep. Then come to work and just listen. Certainly we’ve all built multiple feedback loops into our applications, right? We have New Relic analytics for our server performance, exceptions logged to a database for analysis, a feedback form and forums for users to contact us … but why did we build all of that into our app in the first place? We did so to enable us to know more about how our app is doing, and more importantly how our users are doing, so that we could take action where necessary. Listening but failing to follow up with improvements and fixes right away could potentially be worse than not listening at all because you’ve set users’ expectations incorrectly.</p><p>There are very objective reasons for dedicating time and effort to listen to, and fully understand, your users. Such as meeting expectations better, and being more efficient by avoiding rework. <strong>But there’s also an emotional component to the exercise itself — it builds trust with users, and demonstrates a genuine empathy for their needs.</strong></p><h3>Failing to Listen Guarantees You Are Forever Playing Catch-Up</h3><p>Most of us don’t get to set all of our own priorities — they are dictated or influenced by customers, managers, colleagues, holiday shopping seasons, and such. We have multiple projects and products in our workshop, and we constantly switch context to whatever is most important right now. And while there are some environments where that works well, context-switching in software development is expensive in terms of time. The constant drumbeat of “deliver, deliver, deliver” often means that important phases of an application’s life cycle get omitted.</p><p>Think about who’s priorities we’re catering to when the consequences of delivering later versus earlier are greater than the consequences of not delivering the best experience to our users. <em>(Hint: it’s not your users’ priorities you’re optimizing for …)</em></p><p>When we don’t schedule the time in the project plan to follow up with a .1 release, users feel unheard and abandoned. Sometimes for a long time. Yes, you hit your deadline, and you’re on to put out the next fire (because every project is the most important project, right?) However, we’ve only served our own priorities at the expense of ignoring those of our users. And as long as we continue to release without listening, and without following up immediately with a “listening release”, we are guaranteed to always have a growing backlog and worse, a growing number of frustrated users.</p><p><strong>As Ron Swanson said, “Never half-ass two things. Whole-ass one thing.”</strong></p><h3>A Better Experience for Everyone</h3><p>And I do mean everyone! The best way to ensure that what you’ve created is actually improving the lives people (because at our core, makers of all disciplines want to build things that impact people) is to release your best work, then take the time to listen to users, set correct expectations, and address their needs as best as you can. Don’t declare “mission accomplished” and move on before your users are happy. This builds trust with your users, which is a very necessary component to user adoption.</p><p>Knowing the <a href="https://www.pmi.org/learning/pm-network/2014/thinking-beyond-triple-constraint.aspx">triple constraint</a> exists in project management, increasing quality isn’t free. But deciding early on that the definition of success is based on a level of quality and user acceptance and not just the delivery date, and that you will spend the additional time and cost required to make users happy will make building and using your product a much more enjoyable experience for everyone.</p><p>Just remember who you are ultimately designing for, and spend most of your time serving their needs and priorities.</p><p><em>(Featured image courtesy of </em><a href="https://www.flickr.com/photos/rumpleteaser/"><em>Flickr.com/Rumpleteaser</em></a><em>)</em></p><p><em>Originally published at </em><a href="http://grantnorwood.com/2015/11/28/the-listening-release/"><em>grantnorwood.com</em></a><em> on November 28, 2015.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=17d65d3848c7" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>