Dev Diary #2 — How I built Ambie in 6 hours

Daniel
6 min readFeb 15, 2021

--

On October 31st, I embarked on a personal hackathon starting at 12pm. My goal was to build a soothing sounds app that is simple, beautiful, and well integrated into my Surface Go 2. Six hours later, I built the minimum viable product for Ambie, a modern Windows app that plays white noise noise and nature sounds to help you be healthier, happier, and more relaxed.

How did Ambie come out relatively polished after just 6 hours of coding? Well, I spent 3 weeks designing it before writing code.

An image of Ambie White Noise app.

Over the rest of this article, I describe my 6-step approach and thought process in designing Ambie. These steps are also the same ones I use for new features. Through this approach, I’m able to implement features rapidly, my code’s architecture is cleaner, and the resulting user experience is polished. And at the end of the day, UX is the most important aspect of my apps. Without further ado, here is my software development process.

1) UX flows

My first step for any new app or feature is to define the user experience that I want to build. With Ambie, I had an idea, but how will this idea look or feel when a customer interacts with the product? This was the first UX flow that I created:

  1. Launch app. User sees a collection of sounds.
  2. User clicks a thunder sound. Sound plays.

As you can see, the UX flow is extremely simple. In fact, it seems trivial. Why bother writing this? Well, consider this: what’s the UX when playing a sound from a browser?

  1. Launch browser.
  2. Search “thunderstorm ambience”.
  3. Scroll past the ads.
  4. Click first link. Web page loads.
  5. Watch ad.
  6. Sound plays.

Which UX flow is faster? Which is more pleasant? The process of writing down your UX flows helps me focus on the customer’s perspective. Specifically, it helps me codify what interactions I want to provide to the customer. My goal with Ambie was to reduce the number of interactions required, and I feel I achieved that. Yes, there are other ways to bring the browser UX down to one step and remove ads, but when it comes to default experiences, I think that Ambie is simpler.

2) Prototype

My next step is to find parts in the UX flow where the engineering work may require more research. For example, before Ambie, I’ve never worked with sound files in UWP apps. So, a prototype or proof of concept was needed to ensure that I am able to actually play a sound file. Following some great UWP documentation, I learned how to

  • play a sound
  • play multiple sounds simultaneously
  • change sound volume
  • play sound under lock screen
  • play sounds when minimized

Once again, for many folks, this prototype seems trivial. But remember, the most important part of app is the user experience. Prototyping ensures that I can achieve the UX that I’m are planning. If a UX is unachievable, then I need to make changes earlier in the process to avoid wasting time.

If there are no engineering unknowns for an app or a feature, then no prototyping is needed and I would skip to the next step.

3) UI sketch

With the UX defined and prototypes built, the next step was to sketch a UI that implements the desired UX flow. So I drew the following wire frames using OneNote on my Surface Go 2.

Initial UI sketches for Ambie.

Recall that my UX flow requires that the user sees a collection of sounds immediately on app launch. Thus, I drew a grid of tiles that represent each sound. I’m not a designer, so I won’t pretend my design is aesthetically pleasing. However, I was confident that this UI implements the desired UX flow. The design can be 80% of the way there*, and then iterated and improved over time, but the UX needs to be as polished as it can be from the start.

(*) — This is in the context of me being an indie developer. If I were in a team, then the design should be as polished as it can be from the start as well.

4) Code flow

Next comes an interesting step. For each step of the UX flow, I write down what happens under the hood. Below is an example for the “Launch app” step:

  1. Launch app. User sees collection of sounds.
  2. App retrieves list of pre-installed sounds from data.json
  3. List of sounds from data.json is used to create SoundViewModels
  4. SoundViewModels are added to ObservableCollection in MainPageViewModel.

The code flow written in italics below the UX flow lists the implementation required to achieve that first step. Here I am designing the flow of logic that enables the UX we desire.

This step has been essential in bridging my engineering brain to my customer-obsessed brain. It reminds me of the UX that the code needs to achieve. Also, this step helps me identify patterns in the code. Can the code be reused elsewhere? If so, can we de-duplicate or abstract the code? Or perhaps I already have functions that can help here? Additionally, understanding code flow helps with the next step.

5) Code design

Once the code flow is identified, I tend to dive deeper and understand where these functions will live. Perhaps they’re all inside the same class. Or maybe half are in one class, and the other half will be added to an existing interface.

An image showing code design applied to my code flows.

In the above image, you’ll see a handwritten UX flow for downloading a sound. This list was also expanded to show the code flow. Lastly, the classes where pieces of the code will live were written in green on the left of the image. With this approach, I was quickly able to draw the lines between classes and their responsibilities. This is essential for the Separation of Concerns principle.

6) Code

The next step in the process is to start writing code. We have the UI, we have the UX flow, and we have the code design. Having all this, coding the app or the feature is smooth sailing. Of course, there will be bugs, and of course new unknowns will be found. In those times, I always make sure that I keep testing my UX flow.

If the flow has to change, then I take a step back and re-assess. Given any newly found limitations, how can we re-optimize the UX flow? Throughout my process, I constantly re-evaluate everything. It’s a rapid feedback loop that optimizes UX above all else.

In conclusion

I guess the biggest take away here is that I lied. Ambie wasn’t built in 6 hours. Yes, it was coded in 6 hours, but 21 days of thinking, refining, and research were required in order for that 6 hours to go smoothly. This approach has served my extremely well in the later features that were added to Ambie. The Azure-powered online catalogue was implemented in 12 hours. The sound mix feature was completed in 16 hours. And the screensaver feature was built in 14 hours. And perhaps the second biggest takeaway here is that UX is the most important feature of all, so every step of the process should optimize for it.

If you have a different approach, I would love to hear what you do. This approach is one that I empirically arrived at, and by no means do I believe it’s an optimal approach. It worked for me, and here’s hoping it works for some others. And if you have other ideas, I would love to learn from you too.

Links

Ambie is open source on GitHub and downloadable from the store.

--

--

Daniel
Daniel

Written by Daniel

I’m a software engineer at Microsoft, and I build Windows apps. I created Nightingale REST client. My stories are personal & not Microsoft’s.

No responses yet