How is prototyping different?

Usually interactive projects involve one or all of the following creative talent:

  • User experience (UX) designer
  • Visual designer
  • Front end developer
  • Back end developer
  • Quality assurance engineer

A traditional project lifecycle looks something like this:

  1. The user experience designer expresses user flows and wireframes which represent the final product. After your approval...
  2. The visual designer processes the wireframes into mockups which capture the client's desired visual aesthetic ("look and feel"). After your approval...
  3. The front-end developer begins building the mockups into HTML, CSS, and JavaScript, which drive the user's experience in the browser. They'll also inform the back end developer of what API will be required. After your approval...
  4. The back-end developer builds the API while the front-end developer integrates.
  5. If you're lucky, a QA engineer tries frantically to break things and reports what they find to the developers for fixing.

And if you're really lucky you'll have nothing but praises to sing about the your product and everyone can go home early.

Except that never happens.

What really happens is that you notice things. Things you didn't notice when all you were working from were some black-and-white sketches. You realize a button's text is confusing, so you ask if it can be changed. Your supervisor informs you that the product needs to work differently.

If only you could have shown your supervisor sooner.

If only you could have seen your product in its early stages to collaborate on its success, instead of leaving it to the mercy of an agency.

That's the problem prototyping solves. Prototyping is when you build a product iteratively, collaboratively, and with as little upfront design as possible.

It puts experimentation above specification, and outcomes above delivery. It implores developers to become product- and design-focused instead of just playing an adult game of paint-by-numbers.

Your average developer builds software according to a design specification.

Developers who prototype design software to achieve outcomes through experimentation.

A new paradigm

As programming tools have increased in capability, developer productivity has increased with it. It's now not unfathomable that a solo developer execute both the design and implementation of a small- to medium-sized digital product.

Composable user interface libraries like React mean we rely less and less upon visual designers to inform the first versions of our products, because it's trivial to iterate on visual aesthetics in the midst of a product build.

And technologies like hot reloading of stylesheets mean that a developer fluent in CSS can rapidly design a gorgeous user interface without ever consulting a visual designer.

Paradigm shifts like this one have occurred throughout the course of software development history. Agile development killed the idea that you could build software successfully with rigid upfront specification, but its methodology speaks very little about user experience and what role developers play in shaping it.

I believe we're now going through another transformation: The realization that developers, if up to the task, can play a unique role in driving the user experience conversation. And that role can be so profound that it changes the entire process of product development.

Now, I don't want to make any wild claims that visual designers are unnecessary or that all developers should start focusing on user experience. After all, we need specialists in all sorts of disciplines, and big projects will always require the leadership of a visual designer to create cohesion and establish identity. But I do think that as product managers, entrepreneurs, and anyone who buys professional software services realize the potential in granting product leadership to their developers, we're going to see a shift in methodology.

And too, as developers begin to recognize the value they can bring to a product by becoming more involved in the user's perception, experience, and value, they too will embrace this subtle but powerful change.

The power of simultaneity

A non-technical user experience designer can offer only so much in terms of real value to end users. They can demonstrate a concept, but not execute it for analysis.

A non-technical visual designer can produce a new identity for an interface, but relies upon the whims of a paint-by-numbers developer to bring that concept to customers in the product.

A design-focused, user-focused developer can execute all of this simultaneously. They're able to conceptualize a visual identity, produce a working prototype of an interface concept, and give it to real end users to test their hypothesis.

By putting your developers in the design seat, you reduce the communication feedback loop that inevitably occurs between designers and developers. This new autonomy produces design decisions which both serve the user and consider technical challenges.

What is prototyping?

Spencer Butte, Eugene, Oregon

You have an idea for a new online product offering. Maybe you already have a thriving business and you want to reach more customers with an interactive experience. Or maybe you're a budding entrepreneur who has a fresh idea to take to market.

What's the first thing that you should do? Maybe you should brainstorm a compelling and memorable name. Then go register a domain name. Hire a designer to create a logo. Sketch some wireframes. Hire a developer. Build the app.

These all sound like reasonable starting points. And they're all things thriving product businesses have done, so it's natural you'd follow this progression.

But none of these activities involve the reason you're building your product in the first place: your customers.

Your customers aren't going to come to you because of your name. They're not going to pay you because you have a sweet logo. And they don't care about your app.

Your customers only care about one thing: That their life is improved because your product is in their lives.

It's fair to say then that your customers care about outcomes. They care that, after using your product, they feel better, have more money, or are otherwise more satisfied than before using your product.

An outcomes-oriented approach

Instead of focusing on deliverables like mockups, technology, and a snazzy marketing page, what if you focused on the outcomes your customers will experience? What if you spent time answering questions like...

  • Who am I serving?
  • What problem am I solving for them?
  • What makes me better than the competition?

The answers to these questions might involve technology or visual design, if you decide those things are necessary to helping your customers solve their problem. But they certainly aren't the core reason your customers want what you've got. You've got to identify why they came to you in the first place. How do they think? What annoys them? How can you alleviate their existential suffering... or at least make their lives marginally easier?

When you know who you're serving, you're able to learn from them about what they want. And when you know the problem you're solving and how your solution is unique, you won't dilute your message and scope.

If you're actually solving someone's problem, they won't care if your branding isn't perfect. They won't mind if your site looks terrible on mobile, so long as they don't need to use the site on mobile. And even if they do: As long as they're getting value from your product, they'll be willing to wait.

That's the essence of prototyping: Building a working version of a product idea that provides real value to real human people, and putting everything else off until after you've done that.

Your objective is to confirm or refute your product's value hypothesis by conducting experiments which simulate aspects of your product idea—not to hold off "launching" your product until a "public release."

That doesn't mean you won't eventually choose a marketable name. It doesn't mean you're going to skimp on any aspect of your product for good. It just means you recognize that the thing your product must do in order to be viable is provide someone somewhere with real value.

If you're doing that, you have a successful product. If you're not, you just have a bunch of code and images and text chasing a fantasy.

The prototyping process

I've spent my career leading the early stages of digital products. Here's the process I use to reduce cost and encourage experimentation when taking a new product to market:

1. Identify the problem you're solving, and for whom

Clearly define the problem your new product alleges to solve, and the specific segment of the market who has the problem.

My favorite exercise for defining your problem and target market is the Fool-Proof Positioning Statement by Dan Janal:

The Fool-Proof Positioning Statement is a two-sentence message that tells people what your product is and how they will benefit. The second sentence tells people why your product is different than others. Here's an example: David Letterman is a talk show host who entertains baby boomers so they can feel good before they go to bed. Unlike other talk show hosts, he performs a Top Ten List.

A positioning statement identifies the following elements:

  • Category of product
  • Primary audience
  • Primary benefits
  • Competing products
  • Primary difference or uniqueness

Take for example, a positioning statement for Formbot, my SaaS for sending webform submissions to Slack and email:

Formbot is an online service that helps developers of static sites receive feedback from their visitors without setting up a server. Unlike other form services, Formbot connects to Slack.

I had the idea for Formbot because I had a real and annoying problem: I love building websites with static site generators, but I didn't want to have to set up a server just to receive form feedback from my visitors.

Once you've identified your primary audience, identify real people within that audience who have the problem you want to solve. Get their assurance that they would gladly pay money to have the problem solved. Forge relationships with them. Ask them how your competitors' product could be better. Listen.

2. Identify desired outcomes from using your product

Now that you have a handle on the problem and the audience for whom you're solving it, it's time to identify how you're going to solve their problem.

Do your users want a fully-automated solution, or one with an interface that affords more customizability?

What are your audience's success outcomes? If your audience gets nothing else out of using your product, what is the one thing with which they need to leave in order to continue using the product?

Organize your product's hypothetical features into user stories. These are a special type of device for thinking about a product's features in terms of their outcomes instead of their deliverables. Each well-written user story identifies a persona, action, and outcome for a given software feature:

As a Formbot user, I want to connect my Slack account so that I can receive potential sales leads in Slack.

  • As a...: the persona who has a stake in using the product
  • I want to...: the action they're going to perform to reach a desired outcome
  • so that...: the valuable outcome the product grants them

Note that the action for each user story needn't be explicit. You don't need to explain that your user should press the "Create Message" button; just explain that they're going to send a message and why that's important. For instance, here's an example of a user story that's too bound to deliverables and has no real business outcome:

As a user, I want to click the "Create Message" button to open the Create Message dialog so that I can send a message to my clients.

Instead, focus on the outcome of the action as it relates to the user:

As a user, I want to send a message to my clients so that I can follow up with them and make more sales.

In doing so, you decouple implementation from your outcomes. When you engage a developer to build the first version of your product, you'll be measuring success not by whether there's a button that reads "Create Message" (irrelevant to your business), but by whether your users can effectively reach their clients (relevant to your business).

3. Determine the most valuable feature of the solution

Of all the user stories you wrote, which one offers the most value to your users? If you were stranded on a desert island and your developer could only build one feature (yes this is a terrible analogy), which feature would you have them build?

Do your prospective users from step 1 feel the same way? Would they start using your product if you could deliver them that one feature?

Formbot started out as a single feature with hardly any user interface. It was barebones, but it did one thing exceptionally well. So it attracted a small but loyal userbase. As a result, I was able to capture user feedback and better understand why users were satisfied and why they weren't. This informed further development and further feedback collection.

You might think you need features that most products have, like email alerts or two-factor authentication. But when you force yourself to think in terms of delivering value to real human people you are actually talking to right now, you find ways to help them without a ton of expensive engineering work.

Again: That's not to say email alerts and two-factor authentication aren't valuable. They're both immensely valuable and you should build them. They might even be inseparable from your most valuable feature, and you might need to build them in order to satisfy your users. But strive to build the least product possible to deliver the most value. Usually that's less than you think.

4. Build and deliver that feature to your audience

Now that you know the featureset that will deliver the most value to your users, it's time to build it.

It's not time to create wireframes. Nor is it time to hire a designer. These are both actions that result in deliverables, like wireframes and mockups. We're prototyping, so we don't want deliverables. We want outcomes.

The first iteration of your product probably won't be pretty. But it'll solve a real problem that your identified real human users need solved. So it doesn't need to be pretty. It needs to work. And for that, you need a developer.

Developers are a dime a dozen. Most developers focus on deliverables. They build the features you want built in the way you specify. They paint by numbers.

What you want is a developer who focuses on outcomes. Remember the user stories you wrote in step 2? You know how I told you to make sure they specify your desired outcomes, as opposed to the path for getting there? You want to find a developer who thinks like that. Someone who sees the road ahead of your business and can steer your product accordingly.

Instead of asking how? like most developers, you want to find a developer who asks why? Instead of estimating how long it'll take to deliver "your app," you want to find a partner who can estimate how long it'll take to validate your business.

Here's a secret truth about software development no one wants you to know: You're never done. Your product will always have bugs, unimplemented features, or things you don't like. It's a fact of the business.

Developers don't want you to know this because they make their money on deliverables. For them to be done with a project is for all the deliverables to be completed. But by this definition of completeness, no project is ever finished.

But you're not going to focus on deliverables. You're going to focus on outcomes. You know that by focusing on deliverables, you can't clearly say whether you've achieved your desired outcome. Having a product with a gorgeous user interface that doesn't have any users is a sure way to go broke. But having a product with an ugly interface that helps 1,000 people achieve a desired outcome means you've proven your hypothesis. The gorgeous interface will come later.

5. Assess the value delivered

You've built your first feature. Your users are now able to walk through one workflow from start to finish. It's not pretty, but it works. Now it's time to see how your audience responds.

Because of how little you've actually built, you might feel ashamed to share this with your audience. But ask yourself this: How would you feel if you made it "perfect", shared it with your audience, and discovered it didn't help them?

And what about the best case scenario? What if your one feature helps your audience in ways you didn't think it could? If that happens, then congratulations! You've validated your product idea. And you did it without spending all your money on vanity deliverables like branding, visual design, and SEO marketing.

6. Refocus your efforts accordingly

If your first feature was a hit, then you're probably feeling encouraged and want to press on. If your audience didn't respond the way you hoped, then you're probably a bit discouraged and might feel like giving up.

Whatever happened, you can rest assured that because you reduced your deliverables to only those things that help you validate whether you can deliver your users the outcomes they desire, 100% of your investment was in pursuit of providing your users with a valuable experience.

You didn't spend lavishly on a hip domain name.

You didn't hire an expensive visual designer.

And hopefully, your sunk cost is low enough that you have the emotional wherewithal to be able to walk away unscathed.

Or, you can choose to regroup and reposition your product. Because you didn't lock yourself into a specific featureset with lavish marketing and polish, you can conduct another experiment. You can continue this process indefinitely until you find something that sticks.

That's the beauty of prototyping. That's why I focus on outcomes. And that's how to build a product people will actually use.

Read on: How is prototyping different?

How long will it take for you to deliver my MVP application?

Ah, the age-old question that eludes anyone who wants to build custom software: How long is this going to take and what will it cost me?

I've been on the receiving end of this question numerous times. And until now, I always butchered the answer. Because in order to properly assess cost when we're building software, it's inadequate to assess the cost of building the software you think your business needs. Instead, a great consultant will analyze your business's unique situation and recommend a path resulting in business outcomes that don't strain your budget and get you to market faster.

Ask yourself: What is the value you hope to deliver to your users? Can you deliver a small part of that value with less effort than you’re envisioning presently, and get it to market faster? Are you operating with invalid assumptions about how your users will behave and what they'll expect?

Imagine you go to a software vendor and tell them "I want to build a car!" They give you a specification for building a car and tell you it'll cost $50,000. You cringe at the price, but go forward with it, because you need to build the car.

A great consultant will ask you why you want to build a car. "Because I want to get across town!" you'll say. And then they'll ask you if a bicycle for $500 will get the job done.

When vetting a consultant to take on your MVP project, it's critical to ensure they possess both the hard skills required to build a working application and the experience to know when what you’re asking them to build isn’t in your best interest.

You're trying to find a consultant who will find the simplest solution to your problem, as opposed to building what you tell them. Building the thing is the easy part. The hard part is defining the thing to build that produces the outcome you desire at the lowest cost.

Rather than building a wireframe specification and handing it to a developer to implement as you've specified, you'd be better off to seek a consultant who can unpack your business, analyze its core needs in the context of technology, and then deliver to you working software week after week.

If you're non-technical, you're probably not in a place to understand the technical consequences of what you want to build. When your ideas are placed under that scrutiny, you might change course because there's a more expedient way you didn't see before.

Are your rituals serving you?

We knowledge workers love rituals. We're always seeking ways to reduce friction, increase productivity, and increase visibility. There's Agile, XP, Kanban, Pair Programming, and now even Mob Programming. There's an entire industry within an industry devoted to teaching others how to apply these principles.

Some teams hold a daily standup. Most hold some form of an iteration planning meeting. And some apply points-based estimations during their planning meetings.

Both standups and estimation have value, depending on your team. If you have a dedicated project manager who scopes the next sprint's work, they might benefit from points-based estimations because they can measure how much progress to expect next. And if you work on a team building a high-touch customer-oriented product, you might benefit from a daily standup to keep your non-technical stakeholders in the loop.

But I've been on too many teams who did one or both of these rituals even though they didn't provide any tangible value. And in many cases, the maturity of modern network tools has rendered these rituals all but obsolete.

Are your daily standups redundant?

Before the likes of GitHub pull requests, it was difficult to, at a glance, see what your teammates were spending their time on. If they had a question, the daily standup served as a space for making inquiries without feeling like you were interrupting their day.

But now that GitHub pull requests enable a one-click view of ongoing efforts by your team and a vehicle through which questions can be asked and answered on our own time, the daily standup is a relic of a less connected past.

And even if you do commit to a daily standup, does it necessarily need to be a synchronous meeting where everyone is present at the same time? I've worked on a team with a #standup Slack channel. We each post our daily standup in the room. Everyone can read up on what the rest of the team is doing that day and whether they're blocked. And no one has to interrupt their workflow to do it.

Ask yourself: Do you get much or any value from your standup, or is it just another mindless ritual?

Are your estimations meaningless?

Stakeholders want to know how much their software is going to cost. This is a reality with which every software developer must contend. But another reality is that software estimation is a losing game.

We can try, to the best of our ability, to assess a software problem and estimate how long it will take to come up with a solution. Armed with an understanding of a fixed software problem, estimating the time to build a solution is actually relatively easy. But software problems are rarely understood correctly ahead of time, and are rarely ever fixed.

Most software problems are complex enough that they require further inquiry after beginning development. There might be a variable we didn't consider during estimation. We might have misunderstood the original problem and gotten that feedback from the customer halfway into development. When was the last time you developed a piece of software without asking for clarification from your customer in the midst of development?

And even if you're fortunate enough to understand a problem thoroughly enough to implement it to the customer's desires the first time, there's a good chance they'll change their mind about it in the middle of development. Maybe they think of a better way. Or maybe business conditions have changed and it makes more sense to do things differently. Whatever the reason, requirements change. And when requirements change, you can kiss your original estimate's accuracy goodbye.

Okay, then what do we do instead?

Estimation and daily standups attempt to solve a real problem: Making sure everyone involved in your project is held accountable and are aware of the changing conditions of your project.

If your team reports that they find value in these activities, then keep doing them.

But if you really consider the opportunity cost of continuing to live by these rituals, you might find their cost outweighs their benefit.

Does interrupting everyone's flow during ongoing high-value development work to hold a daily standup have a net benefit to your team's productivity and happiness? Or would the team be better informed by committing to reviewing open pull requests and tickets once per day on their own time?

Are your estimations providing your product owner with valuable insight into what progress they should expect in the coming months, or are your estimates so skewed from reality that they're meaningless?

Do you own your rituals, or do your rituals own you?

Only build the bare minimum

Founders ought to be a bit less ambitious.

When you bring software to the marketplace, you're competing for attention in a cruel world. Where you focus your resources matters immensely. Because complexity in software is a multipler, new features built today will cost time, effort and money tomorrow.

That's why it's critical to build the tiniest product you can first. The sooner your application is humming along in a real person's hands, the sooner they're going to tell you all the reasons they love or hate it.

Feedback from real users as early as possible is the most valuable asset to your team. When the only user feedback comes from an insulated CEO or project manager, it's likely the feedback received, while well-meaning, is going to be at least a few degrees away from the needs of your users.

Complexity is a multiplier

If there were one sort of interaction I wish I could take back from all my time as a software consultant, it would be every time I nodded my head at a client when they asked me to add one more feature, knowing full well that its addition would be costly and that the client should place their assumptions about its benefit under more scrutiny.

Considering my title of Digital Product Consultant, you'd think I was up to the task. But a point I think deserves being driven home is how we consultants are paid to increase revenue and decrease cost, even though sometimes we act as though we're paid to follow directions.

The fact is, someone who pays money for custom software isn't necessarily going to be aware of the ongoing costs of maintaining a specific software feature. And these costs, depending on the architecture of a given system and its dependencies, can balloon exponentially. That's because added complexity to a software product multiplies cost.

When your application has a single button that, when pressed, shows a predetermined text string on-screen, you've built a simple program. When you make the button show a bit of randomly selected text from a list when pressed, you've built a slightly more complex program.

With each new feature we add to a software program, the resulting complexity increases. It's easy to assume the increase in complexity (and therefore, the inversely correlated decrease in ease of understanding) is a linear progression. But each feature actually increases complexity exponentially.

This means that for each new feature, it's likely you're going to multiply—not add to—the overall cost of maintaining your software.

Therefore, it's prudent to consider the long-term ramifications of implementing a feature. The real cost center is not in its implementation, but in its continued support. How does the new feature play with existing ones? What happens if we later want to remove it? How will our users react?

What are some ways consultants can help their clients better understand the ramifications new features could have on their ongoing maintenance costs? And what are some ways you can protect yourself if you've hired a consultant but are unsure whether you next feature request will balloon into a Great Expensive Ball of Doom?

Is it additive or foundational?

Does the new feature sit beside or on top of other features in a way that doesn't stand to negatively impact other parts of the application? Is the feature orthogonal, meaning it neither creates nor propagates side effects to other parts of your application? If so, the chances are lower that implementing and shipping the feature will result in regressions or service outages. This is what I call an additive feature.

But if your feature involves widespread changes to fundamental components of your application that are in production, mission-critical, and costly should they malfunction, then you're implementing a fundamental feature. In this case, you ought to spend more time analyizing the costs and benefits of building it.

Performing a cost benefit analysis

If you've identified that your new feature will likely have an impact on existing mission-critical infrastructure, you'll want to do a bit of analysis before you give the thumbs-up to have it built.

List the potential externalities that could arise when shipping the new feature. Could it disrupt orders from being processed? Is there a chance that users won't be able to sign in for a brief period of maintenance time? Will you need to perform an intensive migration on your database that could cause downtime and/or integrity concerns?

List each of these and attempt to quantify the best and worst case scenario you can imagine, in terms of the costs to the business.

For instance, if you think there's a chance you could see some downtime to your sales pipeline for 10 minutes up to 1 hour, and on a typical day you see $24,000 in sales, you stand to lose up to $1,000 in sales as a result of implementing the feature. You'll also want to account for the opportunity cost associated with the hours (or days) your team spends resolving the regression.

In addition to the lost dollar value, you should also consider intangible costs like costs to your brand's value, customer perception, and team morale. While these costs are not necessarily measurable, they have a profound effect on your business over time.

When you spend the extra time coming to terms with the potential externalities of implementing a new feature, you'll increase the reliability of your product and reduce stress resulting from outages. While new features stand to make your product more valuable and stand out among your competition, carefully considering how they will affect your existing featureset can save you time, money, and headaches.

The real formula for marketing success

We read books that purport to uncover the techiques that will propel us to greatness. Some say how to get more followers on social media. Others say to quit social media entirely. Some advocate sending emails to influencers. Others say you should speak to an existing audience instead of trying to create your own.

But really, all of the so-called gurus want the same thing you do. They want success. They want a following. They want admiration. They want business.

There's nothing wrong with following the advice of marketing gurus. But in my experience, success in the marketplace comes down to one factor: Whether or not you add value to someone else's life.

Every single time I've found success in my career, it had little or nothing to do with my Twitter feed, drip marketing campaigns, or my email subscribers. These are all amazing tools when used properly. But at the end of the day, publishing clickbait articles with little substance or value is a waste of your time and the time of your fellow Internet citizens.

I think that instead of spending our time hacking human attention, we ought to be asking ourselves what we can do to truly help and engage others. It's the more difficult path, for sure. But I think it's the only one which ultimately results in lasting, fruitful business relationships.

Learning Elm

Elm is "a delightful language for reliable webapps."— or so its homepage says. Today, I'm going to dive in head-first to find out what all the fuss is about.

For those of you unacquainted, here are some of Elm's purported features, straight from its homepage:

  • Compiles to JavaScript: The language targets JavaScript specifically
  • No runtime exceptions: Instead of producing runtime exceptions, Elm uses type inference to detect problems during compilation.
  • Great performance: Like React, Elm uses a virtual DOM designed for simplicity and speed.

Sounds cool. Let's fire it up then, shall we?

Installing Elm

If you're on a Mac like I am, Elm has a Mac installer available here. The current stable version is 0.18. The '0' at the beginning doesn't give me much confidence in using Elm in production, but if Pivotal is doing it then maybe it's worth a try?

After completing, the installer tells us:

A bunch of useful programs were just placed in /usr/local/bin/

Installing the Vim plugin

Since I use Vim, I'm going to go ahead and install the elm.vim plugin:

  $ cd ~/.vim/bundle
  $ git clone

Easy enough.

Hello World

When learning a new language, there are two benchmarks of expertise: Hello World and Todo.

Elm appears to be no exception. Let's follow this Hello World tutorial on the site.

Create a project folder

First we create a new folder for our Hello World application. I called mine hello-elm:

  $ mkdir hello-elm

Install packages

It looks like first we need to install the package elm-lang/html. Why that's not installed by default I'm hopeful will be revealed later on...

  $ elm package install elm-lang/html
  Some new packages are needed. Here is the upgrade plan.

        elm-lang/core 5.1.1
        elm-lang/html 2.0.0
        elm-lang/virtual-dom 2.0.4

 Do you approve of this plan? [Y/n]

Ooh, do I approve? I feel like a boss. Yeah, I approve.

Starting downloads...

  ● elm-lang/virtual-dom 2.0.4
  ● elm-lang/html 2.0.0
  ● elm-lang/core 5.1.1

Packages configured successfully!

First impressions of package management: Elm is pretty freaking mature for a 0.18 release! Would be nice to see NPM/Yarn-style progress bars, but so far this feels solid.

The elm package install command seems to have created the following stuff in the directory:


Write some code

Okay, now we're going to create our first Elm module. Exciting. Here's mine:

module Hello exposing (..)

import Html exposing (text)

main =
    text "Hello"

I put that in Hello.elm. Right now it's not clear to me whether that should be in the elm-stuff directory or in the root directory. I put it in the root.

Now we run elm reactor:

  $ elm reactor

Interesting. So it looks like Elm has a sort of "dashboard" view of your files, packages, and dependencies. Clicking on our Hello.elm file takes us to our application, which at this point is just the text "Hello" in the top-left corner of the page.

Some thoughts about what I've seen so far:

  1. There's a module named Html. The fact that Elm treats the DOM as a first-class concept as opposed to relying on class-like abstractions as in standard JavaScript is a welcome change as we move toward functional UI paradigms.
  2. The compile time for a Hello World application seemed awfully long. I'm not sure if it was just a fluke on my machine, but it took 2-3 seconds before my app loaded. I could understand if we had a complex application, but this is Hello World...

Okay, let's keep going...

Rendering complex markup

So far, it looks like we can render text using the text function. I'm digging around in the documentation and found an examples page. I poked around a few of these until I found an example of rendering an unordered list.

It looks like Elm's composition syntax is Lisp-ish, but not Lisp:

import Html exposing (li, text, ul)
import Html.Attributes exposing (class)

main =
  ul [class "carbonated-beverages"]
    [ li [] [text "La Croix"]
    , li [] [text "Zevia"]
    , li [] [text "Pepsi"]

Some observations here:

  1. Because Elm is functional, even attributes need be imported. Whereas in ES6, we need only import a module in order to gain access to all its getters and setters, Elm requires explicitly importing things like class in order to use them.
  2. It is a welcome change to see a main function that returns a DOM tree. In React, there's a bunch of boilerplate to attach a component to the DOM. In Elm, all of that boilerplate is baked into the language.
  3. The slow compile time appears to have been a fluke. This new example compiled almost instantly.

A word about Elm's architecture

It looks like Elm has its own application architecture that it lovingly calls the ... Elm Architecture.

It consists of:

  • Model: the state of the application
  • Update: a way to update the state of the application
  • View: the resulting view of your state as HTML (or XML, or SVG)

From what I can tell, these roughly correspond to React/Redux concepts thusly:

  • Elm's Model layer is equivalent to Redux's store
  • Elm's Update layer is equivalent to Redux's actions
  • Elm's View layer is equivalent to React itself

These analogies are made even more convincing when you consider the fact every value in Elm is immutable, just like Redux when used with Immutable.js, and that the Elm Architecture makes use of the one-way data flow paradigm made famous by Facebook's Flux.

Responding to user input

Okay, so we've produced a Hello World example and then rendered some slightly more complex markup. That's fine, but how does Elm deal with user input? Let's try creating an example where clicking a button renders the text "Hello Elm" below the button.

According to Lucas Reis's blog, Elm supplies a function Html.App.program which automatically routes an application for the Elm Architecture:

Elm apps use a centralized state pattern, which I've written about in this blog. It's a simple "loop" described as such:

Model > View > Update > Model > View > ...

First you describe a model of your app. It is the skeleton, the data you need to render the application.

The view is then a function of the model. It takes the data and renders it.

After rendering, the application "waits" for user interaction or any other event. When that happens, it triggers the update function. The update function is a function that receives the old model and data of the event, and returns a new model. This model is then rendered, and the loop continues.

Evidently, there's a simpler version of this function supplied with Elm called beginnerProgram. I couldn't find a decent explanation anywhere for what this function does that the regular program doesn't (or vice versa). If you know, please leave a comment!

Here's the full text of the user input example I just created:

import Html exposing (Html, button, div, text, p)
import Html.Events exposing (onClick)

type alias Model =

model : Model
model = ""

type Msg = ShowGreeting

update : Msg -> Model -> Model
update msg model =
    case msg of
        ShowGreeting ->
            "Hello Elm"

view : Model -> Html Msg
view model =
    div [ ]
        [ button
            [ onClick ShowGreeting ]
            [ text "Click Me" ]
        , p [ ] [ text model ]

main =
        { model = model
        , view = view
        , update = update

Let's walk through this line by line together.

First, we import some HTML functions we'll use to render our markup and listen to the button for clicks:

import Html exposing (Html, button, div, text, p)
import Html.Events exposing (onClick)

Then we'll create a new type called Model which is an alias for a string:

type alias Model =

Next, we'll create an instance of the Model type called model and initialize it to an empty string literal:

model : Model
model = ""

Then, we'll set up our update function. This confused me at first, so maybe my explanation will help you if you come from the Redux universe.

The update function in Elm works essentially like reducers in Redux. It takes a message (an action in Redux-speak) and the model (the state in Redux-speak) and returns a newly mutated model.

Except Elm is much more suited to this paradigm for the following reasons:

  1. Elm's union types make the usage of symbolic enumerations like user actions checkable at compile time instead of relying on runtime checks.
  2. Because Elm data is always immutable, state reduction doesn't require clunky external libraries like Immutable.js.

So our update function takes a msg (in this case, only the value ShowGreeting), and returns a new model state based on whatever msg it received:

type Msg = ShowGreeting

update : Msg -> Model -> Model
update msg model =
    case msg of
        ShowGreeting ->
            "Hello Elm"

Okay, now that we've defined how our model will change in response to user actions, let's define the view. Again, Elm comes to the rescue by allowing us to pass the model directly into the view function. No complex binding a la Redux containers!

view : Model -> Html Msg
view model =
    div [ ]
        [ button
            [ onClick ShowGreeting ]
            [ text "Click Me" ]
        , p [ ] [ text model ]

Notice how we're passing model to the text function inside the p tag. When we boot the application, the model's value will be an empty string, but as soon as we click the button, we fire the ShowGreeting message and the model changes to the string "Hello Elm".

Finally, we glue everything together via the beginnerProgram function:

main =
        { model = model
        , view = view
        , update = update

My impressions

All in all, I was pretty impressed with Elm after playing with it for an hour or so. While it's clear the framework has a ways to go in terms of documentation and external library support, its philosophy removes a lot of the boilerplate that plagues modern JavaScript tooling. In addition, it takes concepts like immutability, functional programming, one-way data flow, and type safety which are must-haves in today's JavaScript development world, and makes them first-class members of the language.

Would I use Elm in a production project yet? I'm not sure if I'd subject my clients' businesses to that risk just yet. While it's impressive, the idea of relying on a small community for support on complex topics like JavaScript interoperability would make me a bit cautious. But I'll definitely consider Elm the next time I build a personal project.

How to befriend uncertainty

Yesterday I found out my biggest client will no longer need my services in a couple months.

The last 24 hours have been a bit of a whirlwind of emotions. Part of me is excited. Another part is scared. I have other sources of income and a savings. But I'm still unsure of what I'll be doing in three months' time.

The funny thing is, I've wanted to go off on my own for some time now. I've been frustrated with the monotony of working on one project for years at a time. But now that I'm faced with it, I'm scared and uncomfortable. Why is it that we're so comfortable being unhappy?

Most of us are constantly chasing certainty. We work jobs we may not enjoy so we're certain we'll have food to eat when we get home. We buy health insurance so we're certain we'll be cared for when we're ill. And we invest for the future so we're certain we won't be out in the cold during old age.

But what is certainty, really? You can't see it. You can't reach out and touch it. Maintaining certainty about tomorrow feels good today, but tomorrow it's gone, leaving us hoping for certainty the next day.

And in the face of complete certainty, we're miserable. We become bored. To know that each day will be the same as the last is the definition of a boring existence.

But there's another way. Instead of seeking certainty day to day, we can befriend uncertainty. We can invite it to sit in our corner with us and share its perspective. After all, just think of the things that wouldn't be possible if we had perfect certainty:


When we embark on an adventure—whether it's down the street to the cafe to write or to another country for a month of backpacking—the allure of doing it is that we don't know exactly what will happen. We might have a plan or itinerary, but our reason for adventuring is to see the unseen and to take a chance on something new.

Framing each uncertain moment as an adventure can help to ease the struggle of seeking certainty in an uncertain situation. And too, it can help grant meaning to ordinary everyday activities which may have seemed monotonous when framed as such.


In love, we're entering into the most profound uncertainty. We commit our hearts and minds and energy to one person. Expecting nothing in return and knowing it will end in heartbreak or death, we proceed to give ourselves to another person.

No one ever entered into a romantic relationship knowing how it would turn out.


I'm not sure there was ever once a passionate artist, businessperson, politician, or writer who knew for certain at the start of their endeavor that their efforts would be meaningful and worthwhile in the end.

The reason people do great things is because of this uncertainty—not in spite of it. We are drawn to the idea that we might achieve what others think to be impossible.

The vicious circle

In modern life we're caught in a vicious circle.

We work long hours at jobs we don't really like because we believe it will result in a better future. Our days are spent in pursuit of a tomorrow that will be oh-so-bright if we just keep our heads down and keep working for it. But then, when tomorrow finally comes, we're befuddled at how inadequate the present suddenly feels. And so we seek yet again for a brighter future, working more and more, until the day we die.

And most of the time, the bright future we're after isn't one where our basic needs are met so that we may pursue some higher artistic calling. No, our hypothetical future has shiny cars and gadgets and a big house and daycare and expensive cocktails and luxurious clothing. It's one where we don't have to deal with life's tedium and we can come and go as we please. It's a future where all our problems are solved and we can finally start living.

It's a future that will never come. It will never come because it cannot exist.

It cannot exist because even when all of life's tedium has been eradicated, more tedium emerges: the tedium of boredom.

Left with nothing to push up against, we create new problems. We continue the habit of looking outward for our gratification. And so, we suffer once more.

It's tempting, but futile to seek a hypothetical future with no problems. Because the nature of a life without problems is problematic itself.

Instead, we might strive to accept life's problems without judgment. To take each passing moment as a blessing, because this moment is the only thing we really have anyway.