Writing Recipes in Grocery

Grocery first launched with a major improvement to how grocery lists are automatically sorted. The app remembers the order that items are checked off and maintains that order the next time you shop. That's a major improvement over manual sorting, and over beacon-based sorting systems that rely too heavily on the user's location inside of a building and are only available at a handful of stores.

Grocery 2.0 represents a major improvement to how recipes are displayed on iPhones. The app lets users optimize their recipes by placing the ingredients next to the steps they're used in. That's a major improvement over traditional recipe apps and websites that structure a recipe as a block of ingredients and a block of steps. The screen isn't big enough to show the entire list of ingredients alongside all of the steps, and so you end up scrolling back and forth between steps and ingredients to see how much of something you need to add for the step you're working on. It's very inefficient and it's also easy to get lost and forget a step or ingredient. It's not a great cooking experience.

Markdown is what we're using to make this possible. Our recipe format uses a subset of markdown to represent key components of a recipe. When users create recipes in Grocery, we're adding each ingredient, step, header, and note as a separate line to a markdown text file in the order they specify. We've found that to be all the flexibility required to write very intuitive and easy to follow recipes that work really well when displayed on iPhone!

Of course, that flexibility also allows users to structure their recipes in Grocery the traditional way, with a block of ingredients and a block of steps. Indeed, if you try to copy a recipe from a website into Grocery that's essentially what you'll end up with. Optimizing the recipe into sections with their associated ingredients and steps takes a little bit of work, but I think it results in a much nicer recipe that's more fun to cook with.

Before Grocery 2.0 launched I went through all of my recipes that I had saved and added them to Grocery. I had recipes saved in other apps, bookmarked, sent to me in emails, and saved as photos from family recipe books. I went through each one and optimized it for our new format. The result is a personal recipe book that I hope to keep forever. That feels like a realistic goal when each recipe stored as a markdown file that can be opened by any text editor!

One example of a recipe I added is my mom's Fudge recipe. This is a recipe I remember helping her make for years and something I never want to forget. The original recipe was handwritten on a piece of paper. As expected, all of the ingredients are at the top and the steps are at the bottom because they all fit on one piece of paper. But they won't all fit on one iPhone screen so we need to figure out what order to arrange everything in while adding the recipe to Grocery.

Original fudge recipe

Original fudge recipe

Making Fudge starts with melting together the butter, sugar, and evaporated milk, so that's the first section in the recipe. Those three ingredients are the first things in the recipe, followed by a step that describes what to do and includes a 5 minute timer.

Fudge Recipe in Grocery

Fudge Recipe in Grocery

I was actually home with my mom while adding this recipe, and we remembered that Fudge requires heating the mixture to a specific temperature, but we couldn't remember what that temperature was. After looking it up and adding to the recipe we also decided to add a note to the recipe with a link to where we found that temperature! Now we'll have that as reference if we forget again.

The next steps are mixing in the chocolate, marshmallow cream, and vanilla, followed by nuts if desired. I added each of these to the recipe as ingredients or steps, specifying the amounts for each ingredient. The result is a recipe for making delicious Fudge that's easy to follow on an iPhone!

Checked off ingredients and steps for making fudge

Checked off ingredients and steps for making fudge

Grocery's recipe view includes a few other features to help make sure you'll never forget an ingredient or a step. Tapping on an ingredient or step while cooking checks off that cell in the viewer, marking it as completed. That state is preserved until the recipe is finished cooking so you can go browse other recipes or quit the app and still come back to the recipe later.

Efficiency with cooking paired with efficiency for shopping makes for an amazing cooking experience. I've always loved cooking but working on Grocery and adding these recipes has made me more passionate about it than ever. I hope you try it out and let us know how you like the recipes you create!

A Recipe for Building Grocery 2.0

The story of Grocery 2.0 begins around Christmas of 2017 with a family recipe book.

Grocery 2.0

Grocery 2.0

Ryan and I were back home with our families looking up recipes and planning holiday meals. After picking a recipe to make you typically add the ingredients to your grocery list and go shopping. We both wanted to have our recipes in Grocery to make adding those sets of ingredients easier.

I think it's important that this realization happened with family recipes because family recipes are very special. To many people, they’re as special as family photos: passed down generation to generation. If we added recipes to Grocery it would need be a great recipe feature that we could trust with those recipes. We set out to do just that and started design in January of 2018.

The obvious next step after design would have been to hit File -> New View Controller in Xcode and start adding a recipe screen to Grocery. Instead, we created an entirely new Xcode project to iterate quickly on our recipe concept. Our goal was to prove that our design worked and bring what we learned back to Grocery and quickly ship our recipe feature.

We eventually did bring that recipe feature back to Grocery and we’re excited to be shipping it in the app today! But along the way, we also re-wrote virtually all of Grocery’s UI in a way that greatly improves the consistency of elements throughout the app, as well as how code is structured for re-use across screens.

One way to look at it: Version 1.0 was basically our prototype. Version 2.0 is the real deal.

That probably sounds weird if you've already been using 1.0 and love it. We love it too! But for multiple technical and user experience reasons I can safely say that 2.0 is a huge improvement, not only to the experience of using Grocery but also to its technical future for many releases to come.


What’s the deal with a new Xcode project?

I initially resisted adding recipes to Grocery because I was in love with the idea that Grocery is just a simple shopping list. Building recipes seemed incredibly complicated. You need a list to view all your recipes, a recipe viewer for cooking and selecting ingredients, and an editor to create new recipes. You need a place to safely store all of the recipes a user adds, with all of their section headers, ingredients, steps, notes, timers, and photos.

Using a new Xcode project gave us space to work through design and technical hurdles without worrying about breaking Grocery. Once we had the new project we started attacking all of the problems involved with building recipes:

1. Using Markdown as a storage system for recipes

Our entire concept for recipes hinged around using markdown to improve flexibility for displaying recipe content. We wanted our recipes to stand the test of time with an open document format that supports interleaved ingredients and steps.

Testing this theory in the new Xcode project proved that a basic UI for creating recipe-focused markdown files was easy to use for adding recipes. ✅You can read more about the recipe markdown format we arrived at on GitHub.

2. iCloud Drive

Recipes need to be shareable across devices and with friends and family members. But we weren’t sure how well recipes sync between devices if we stored our recipe markdown files in iCloud Drive.

We tested this feature by adding support for reloading a recipe in real time as changes are made on another device, which actually works VERY well! Syncing is surprisingly quick.

3. How to support multi-line text in list cells

Multi-line text has always been a challenging problem because every cell in your list could have a different height.

Grocery 1.0 supports Dynamic Type, which requires some variation in the height of each cell, but we still limited the length of items in the list to a single line. That would never have worked for recipes that usually include long steps that span several sentences.

So instead of a standard table view, we built the recipe screen as a collection view and worked through all of the details to get multi-line text working. Our solution worked really well for recipes, and we even made the solution re-usable so that we could use it in other screens like the recipe list and ingredients list.

4. Themes

We'd been wanting to introduce different app theme colors for a long time. Because why not?

Themes!

Themes!

Building new UI components from scratch in the new project seemed like the perfect time to try it! We ended up with a very clean solution using a notification system that lets each component style itself for the selected theme. We even used Swift enums for all of the theme options!

We had assumed that there would be a new system dark mode setting in iOS 12 that we'd be well on our way to supporting, but that only debuted on the Mac. We'll be ready if that ships in iOS 13 though!


What else did we get from a new project?

Using a new Xcode project to develop recipes helped us solve a lot of problems quickly, but we actually got a lot more out of it than we could have predicted.

We eventually realized that our new Xcode project had essentially become a component-based layout system for building lists that fit our app's style. A component is just a collection view cell with enum-driven customization options like:

  • Title font style

  • Note font style

  • Left thumbnail image

  • Right thumbnail image

  • Full size image

  • Background visible or invisible

  • Attributed text (e.g. for timers and links)

  • Checkmark visible or invisible (e.g. for grocery list items)

  • Disclosure indicator visible or invisible

Example of most of the types of cell configurations that Grocery supports

Example of most of the types of cell configurations that Grocery supports

All of these cells are actually the same type of component-based collection view cell

All of these cells are actually the same type of component-based collection view cell

Each component supports theming and multi-line text for all of its labels right out of the box. Multi-line support also extends to images which are automatically sized to fit the width of the screen with their aspect ratio intact. The components were exactly what we needed to build a flexible recipe layout system, but also worked great for building any other screen we wanted to.


The recipe feature works! Now what?

Our original plan called for iterating quickly on recipes in a new Xcode project before bringing the recipe feature code back into the Grocery project. In my head that essentially meant moving some files from one project to another and linking them together to present the new recipe screens.

There still wasn’t anything wrong with that plan. Grocery was still working well, and we wouldn’t have to make any changes to Grocery before inserting the new recipes feature. There was essentially zero risk to Grocery by going this route. Why would we consider doing anything else?

The other option was to go nuclear and make some major code changes to Grocery itself, while moving the recipes from the new Xcode project back into the main Grocery project. There were a few reasons why this seemed like a great idea:

  • We were way more excited about the UI system we had created in the new project than we were about the UI we had created in Grocery. The code was a lot nicer to work with, and the components fully reflected our entire visual style for the app.

  • By this point we had committed to shipping new app themes alongside recipes, and our component-based layout system already supported theming.

  • We'd been fine tuning the marginal layout in the prototype and it simply felt nicer and more consistent than some of the layout in Grocery. We were building every new screen with these components, and so all of the screens benefited from those improvements.

  • The original Grocery project essentially used different table view cells for each screen. The Grocery List and Quick Add screens had different cells to accommodate one having a checkmark selection and one having a circle selection. There were different cells for settings too, and for lists and stores. This of course caused plenty of issues any time we decided to tweak our layout spacing in the app...which led to us not doing that very often. You never want brittle code to be a reason to avoid change, and our original layout code was too brittle for our liking.


Plot twist

Instead of just moving recipes back into Grocery and calling it a day, we decided to re-build the existing Grocery UI using the new component-based layout system without changing Grocery’s existing model layer.

Grocery List + Recipes

Grocery List + Recipes

We still loved Grocery's internal model and controller layers. The interaction with Reminders, our internal sorting algorithm, Apple Watch, and the Realm database that we use for sorting were all very solid and abstracted out into their own classes.


The Merge

Besides support for themes, we also knew that two of the screens in Grocery needed to be overhauled before our next major version anyway: Stores & Lists, and Settings.

Stores & Lists:

Confusion about the difference between Stores and Lists and how to have items associated with a specific Store was easily the largest source of customer feedback from Grocery 1.0. We'd been brainstorming solutions to that almost as long as we'd been working on recipes!

The solution we arrived at was to merge Stores & Lists into one feature called Stores, and give each Store an assigned Reminders List. That gives users the flexibility to configure Stores however they want to: with a shared list for multiple stores, or a unique list for each store.

New Stores:

The new Stores feature was different enough from the original that it really needed a brand new UI no matter what. The original store/list selection screen just didn’t make sense for the new feature.

Building the new screens with the component-based layout system was incredibly fast! They were easy to build because the components handle all of the layout. The data source for each screen is essentially the a-la-carte counter at a restaurant:

"I'll take three cells with images on the left, titles, and notes on the right; a section header with some top spacing; two cells with some text and images on the right; one cell with two lines of note text; and two cells with tinted titles that make them look like buttons."

Settings:

We re-built settings in the same manner, and that only took a weekend to finish. Because the logic behind most of these screens is relatively minimal, handling all of the layout through shared components cuts out most of the work for adding new screens.

Of course, this component-based layout system only works within the constraints of what our shared components can be configured to do. Adding an entirely new "type" of component still means work. But knowing which components exist and how they can be customized is also really helpful from a design perspective because you have a better sense of what your palate looks like while designing a new screen. If you use those components in the design, you know it's going to be easy to build. It's really a tide that lifts all ships.


The Grocery List Refactor

Grocery is still a pretty simple app. When you exclude the Recipes, Stores, and Settings screens that we already re-built...the only thing left to rebuild is the list screen itself.

I have to admit, the list screen was a little embarrassing to behold. It was actually still called ViewController.swift from when I first created the Grocery Xcode project in January of 2017!

ViewController.swift wasn't quite as massive a view controller as it could have been, in part because of how much logic Grocery had abstracted out into classes that could be shared with the Apple Watch app. But it was still cluttered and disorganized and largely incompatible with the multi-line layout and theming features we were adding in 2.0.

The new list screen is infinitely nicer and actually has a real name: GroceryListViewController.swift!

GroceryListViewController + Extensions

GroceryListViewController + Extensions

Developing the new GroceryListViewController was an incredible lesson in refactoring that I want to describe for you here. This is what the process looked like:

The simple stuff:

Some pieces of the original ViewController had an obvious home in the new GroceryListViewController. If a method is simple and important, just putting it into a more organized place in the new GroceryListViewController or one of its extensions was all that was needed. I saw those pieces as low hanging fruit and tried to move all of them first.

Anything I moved to the new GroceryListViewController I also deleted from the old ViewController.

More complex parts:

Certainly some parts of the original ViewController weren’t needed anymore, or could be better replaced by newer components we’d been developing alongside recipes. After clearing out the low hanging fruit I started combing through the remaining methods following this pattern:

  • Select a method in the old ViewController.

  • Figure out what it's doing.

  • Write a new method in GroceryListViewController that implements the essential features of the old method, generally using newer support systems.

  • Delete the old method from the old ViewController.

As the ViewController file shrank, other files related to the new GroceryListViewController grew. The refactor would be complete when ViewController.swift was empty and could be deleted from the Xcode project.

Drag and Drop:

The most care was needed around features like Drag and Drop. Grocery's original table-view-based drag and drop was incompatible with the new iOS 11 Drag and Drop that supports dropping items from other apps. That sort of refactor required saving the underlying logic of what to do when an item is dropped while supporting a new type of user interaction.

Gaining support for features like iOS 11’s Drag and Drop was yet-another reason that I'm glad we decided to give the grocery list screen a do-over. Eventually the last method was removed from the old ViewController.swift and the file was deleted from the Xcode project. Refactor complete!

Once the refactor was finished, every screen in the Grocery project worked the same way. Having one way of doing things makes the app easier to maintain because there's less context switching across features, and less surface area for bugs to pop up. That by itself can be a very valid reason to perform a major refactoring effort if it means unifying the way core functionality in your app works!


Grocery list, recipes, and back again

A friend at work asked an important philosophical question recently: if you replace every plank on a ship is it still the same ship? Grocery still feels like the same app to me. Sorting the list and adding items still works the same way. Settings carry over to 2.0, with the addition of a few new ones. Quick Add works the same way. But using the app with recipes and themes is so much nicer as a user, and the code base is easier to work with as a developer. I'm not sure if it's truly the same ship or not, but I do know it's a ship I love using and working on!

We're really excited for people to try the new version and hope that you enjoy it. Grocery is free to download and available on the App Store!

Grocery Version 1.1 Includes Quick Add and Usability Improvements

The reception Grocery has received from users since launching has been great. Several of the reviews really capture why we wanted to make the app:

Couldn't have said it better ourselves, and in that spirit we've been working on some meaningful improvements to the app while staying true to the simple design and focused purpose.

Grocery 1.1 featuring an improved list layout and Quick Add

Grocery 1.1 featuring an improved list layout and Quick Add

The main grocery list interface has received lots of attention. When we released Grocery the title and notes fields were aligned horizontally, which limited the maximum length of titles that could fit on most phones. Stacking the fields vertically removes that limitation and improves readability. It also frees up space on the right side for persistent drag handles to quickly re-order items manually. Grocery learns the order that you shop for items pretty quickly, but it's still helpful to be able to move an item into place if you already know where it should go.

We're also introducing a new feature that we call Quick Add. This feature uses your shopping history to help you remember items you shop for frequently and quickly add them to your list. Quick Add makes suggestions based on how often you shop for repeated items. If you buy Eggs every 6 days, and it's been 5 days since your last trip to the store, then you would expect to see Eggs on your Grocery list. Quick Add learns to recognize those patterns and make adding those items to your list faster.

Grocery 1.1 includes many other general usability improvements:

  • Use custom URL Schemes to open Grocery and add items
  • Improvements to Apple Watch Complication and Snapshot reliability
  • Support for Handoff from Apple Watch to iPhone
  • Alexa can add items to your Grocery list. Check the FAQ for setup instructions.
  • We made a handy text-selection-menu shortcut to "Clean Up" a title by moving extra text besides the title into the notes field.
  • A much requested "Share this app" button to simplify sharing the app with friends and family :)
  • Emoji now correctly appear in the title and notes fields
  • Keyboard shortcuts for iPad
  • Performance improvements for manual re-ordering
  • The number of items in your list are visible at the top of the list
  • Grocery automatically scrolls to reveal the position of new items after they're added to your list.

If you haven't gone for a trip to the store with Grocery yet, give it a try. We think it could be exactly what you need too, but if it's not please reach out and let us know!

Introducing Grocery - An Opinionated Shopping List App for iPhone and Apple Watch

I'm excited to introduce Grocery, a new app that Ryan Considine and I built specifically for grocery shopping with the goal of making trips to the store more efficient. We started the project with a question — what if our app knew the path we took through a store, and how would it use that to make the trip more efficient? What we are launching is a simple shopping list with a focused interface that includes a lot of intelligence to always keep your list sorted in the order that you shop.

Grocery for iPhone

Grocery for iPhone

Smart Sorting

Sorting a grocery list is no small task. There's no end to the variety of different ways that people shop. Paper lists are still very common, and people have different ways of manually sorting their lists. Grocery store layouts are almost as varied as individual people's shopping behavior — even among the same chain of stores. Some stores have tried to solve this problem with technologies like geolocation and beacons, but those are expensive to install, unreliable to use, and just haven’t caught on.

We wanted to build something that would be easy and reliable for everyone to use, regardless of store location or shopping habits. Our first step was to create our own intelligent sorting algorithm that can learn from an individual's shopping behavior. This is a new approach that we haven't seen applied before, but we chose to pursue it because it doesn't require hardware or analytics, or even a user's location to build a custom sorting order.

The algorithm we built learns from each trip you make to the store and sorts based on the order you shop for items and check them off your list. All of this analysis is taking place on the user's phone and stored locally. We aren't doing any machine learning in the cloud — not just for privacy reasons, but because there's no need. Everyone shops differently, and we don't need to learn from someone else's behavior to build a better sorting order for you.

Let's say you make a trip to the store for a few essentials, in this case:

  • Eggs
  • Milk
  • Avocados

You move through the produce section of the store first, and this was the order that you picked up the items and checked them off your list:

  • Avocados
  • Eggs
  • Milk

From now on, Grocery knows that Avocados come before Eggs and Milk. The next time you go to the store and only need to visit the produce section, but added a few new items to your list:

  • Kale
  • Carrots
  • Onions
  • Bell Peppers
  • Avocados

After this trip to the store, Grocery knows how to sort all of these items relative to each other, and because you previously shopped for Avocados, it also knows that these items all come before Eggs and Milk. If your next trip to the store is for Kale and Eggs, Grocery will know which item comes first and sort your list accordingly.

 

Apple Watch

Grocery for Apple Watch

Grocery for Apple Watch

Efficiency in the store is our number one goal for Grocery, and an even more efficient place for the app is on the Apple Watch. We learned early on that the Apple Watch was a great device to use at the grocery store because it keeps your hands free to hold items or push a shopping cart.

We wanted the Apple Watch experience for Grocery to be the best possible. To that end we actually built the Apple Watch UI before we started on the iPhone. We spent a lot of time optimizing it to be as fast as possible - which is key for third party watch apps.

Always having your Grocery list in sorted order is the key to an efficient and effortless user experience on the watch. Because your list is in order, the item you just put in the cart that you’re looking to check off is visible immediately after raising your wrist without your needing to scroll to find it.

Raise your wrist, tap the item to check it off, look at the next item on the list, and lower your wrist. It’s a very quick interaction that makes shopping with the Apple Watch feel easy and efficient.

 

Adding Items

We also wanted adding items to your list to be as simple and fast as possible. The iPhone UI for adding items is optimized around speed and efficiency. The text field for adding an item and associated notes is always present at the bottom of the screen, within easy reach. Tapping the + button after entering an item keeps the keyboard up, ready to enter more items. And we built our own autocomplete system that populates from your personal history of purchased items, making repeat entries fast and easy.

You can also add items to the list on your Apple Watch, via dictation or scribble, or by picking a past item to add back to your list. We've all been in places where using our watch to do something is simpler than taking our phone out, and we wanted to make sure Grocery supported that use case.

But we didn't stop there. You can also add items to your Grocery list from the Mac, iPad, iCloud, and Siri! And even, via IFTTT, from Alexa. That's because Grocery is built on top of the iOS Reminders database, which supports shared lists on iCloud. When you start using Grocery, we prompt you to create a new list called "Grocery" (which you can change if you want to), that can be edited from any device with the Reminders app, or access to iCloud.com.

Support for Siri is something we've really grown attached to. Even the phrasing is simple with the default list name — "Add Eggs to my Grocery List", and items show up immediately after they're added. Voice assistants like Siri and Alexa work great in kitchen settings, and adding items to your shopping list that way is a great example of why.

And finally, because we're supporting iCloud Reminders lists, you can also share your list with a partner or roommate, and they can add items to your shared list from Grocery or from the Reminders app. You'll each see the items the other added in your list - but each person will still have a unique sorting order based on the order in which each person shops for items.

 

Conclusion

Grocery is launching today as a free app that includes Google app install ads, with an optional in-app purchase to remove ads and support future development of Grocery. We love using the app and are excited to introduce it. We hope you enjoy it!