If people are frustrated by your current software, read this

We’ve all been there — ready to tear our hair out because we can’t accomplish a simple task using a website or app. As software designers and developers, we follow these principles to help prevent frustration and give users what they need.
Illustration of frustrated people


Many of us have been beaten down by bad experiences with software. We have been overwhelmed, confused, lost, frustrated, and downright angry at times, and most of that comes from a mismatch between our expectations and reality. We expect a digital tool to help us, not slow us down, or make accomplishing a task even harder (which it often does).

The Pixo team can help you uncover these pain points with your current software or process, and collaborate with you to build a better experience. To do this, we combine user experience research and design with full stack engineering to form a cross-functional product team.

We then follow these four principles to design and develop software people actually want to use: 

1: Talk to real people who will actually use the product.

There really is no substitute for getting into the field, observing folks in action, and asking questions to better understand their process. This is not marketing or market research — we’re not asking people what they want in a new product, or if they would buy something. We’re focused on how they solve problems and under what conditions so we can design software that is immediately familiar and makes sense to them.

Creating a user interface that seems ‘obvious’ and intuitive is incredibly hard to pull off. You can create an app with the required core functionality, but if you introduce a non-standard navigational element, or don’t add labels where they should be, or forget about status and error messages, it negatively affects the entire experience.

Real-life observation saves time

A good example of this is when we were working with a steel mill to create a custom packing and shipping app to run on a rugged handheld scanner. Their existing app, among many other issues, didn’t have a network status message. So every time they turned on their electric arc furnace, it interrupted the wifi signal, and the app would briefly stop working. Their workers then went all the way back to the main office to get a replacement device. So just by building in a simple and informative network status notification in the new app, we have saved them a significant amount of time. 

Not talking to users can cost you

A common alternative to talking with real users is to only test prototypes with internal audiences. Product teams cite many reasons for doing this: 

  • They are under time pressure and believe this will save time. 
  • They have budget pressures.
  • They are actively discouraged from talking to customers, because some companies are uncomfortable showing in-process work or prototypes to external audiences.

What companies don’t acknowledge (and most aren’t even aware of) is the true cost of getting things wrong. A recent study by the Consortium for Information & Software Quality (CISQ) estimated that the cost of bad UX alone is ~$75 billion per year.

If you build software from an inside-out approach by starting with an internal only vision of how things should work, and not from a user-first, context aware, outside-in approach, the final product will have a much higher likelihood of failure. At the very least, you likely spent time on features that will rarely or never get used.


2: Test ideas before development.

Testing out initial ideas before beginning development can reduce risks and protect your budget by shifting costly and hard-to-change decisions to later in the process. At the beginning of a project, we know very little about what the final product should be and how we are going to build it. All we have is excitement and ambition, and maybe a big mandate to deliver. Regardless, these powerful drivers can push us to make decisions before we have enough information to do so. Using low or lower cost methods to test our assumptions can, and often does, reduce overall project risk.  

Cost compared to alternatives
Products typically become more limiting and costly to change the further into development you are.

So, what does this look like practically? 

So, what does this look like practically? 

Research and prototyping informs decisions

For one of our clients, we developed a working prototype of an application to test out how the market would respond to a completely new product line. This was a 40-year-old manufacturing company that made OEM components for light vehicle manufacturers. They were moving from a manually actuated product to a computer-based product. An important segment of this market included dealers and repair shops who would have to learn how to tune and troubleshoot in a new way.

Based on the research we conducted, the company decided to deviate from their original plan. If this product proves successful, they will likely need something more than the prototype-level app they are currently using, but it’s allowing them to learn about this new market so they can make better product decisions down the road.

3: Design systems for flexibility.

If you’ve invested a ton of time developing something new to exact specifications, the idea of future flexibility sounds like a “nice to have.” Software can be very difficult and expensive to change later, as I just mentioned — but inevitably, you will want to make changes later as your business grows and the needs of your users change. So we design and develop with flexibility in mind.

When we talk about flexibility at Pixo, we are referring to a number of related methodologies. One of them is behavior driven development, which you can read about here. Another is my favorite: test driven development, or TDD.

TDD keeps software soft

Pixo engineers have a mantra: “keep software soft.” Test driven development  is one of the ways we do that. At a high-level, TDD specifies that before you write new code, you write a test to determine if your code behaves the way you want it to. 

So, you write a test — “does this thing do this other thing?” — and at first, the answer is no, because that code isn’t written yet. Then, you write the code until the test passes.

There are two things I really appreciate about this:

  1. Engineers end up writing less code using this method, and
  2. When we make changes, we can run the tests and see if this new code broke any of the old code. 

It’s that second point that becomes really important over time, because it allows our engineers to make changes no matter how complex the code may get. 

The reason I appreciate this is because I often hear something like this from new clients: “The developer I am using was amazing in the beginning; they were pumping out new features. But now, a year or two later, everything takes forever, even the smallest change! I think we have their B team.”

Your developer may have a B team, but that’s probably not the main source of what’s frustrating you. What’s likely happening is that your code is now complex and has lots of dependencies, so making changes — however small they may seem — has the potential to break something. But, how can they know? Sometimes it’s obvious, and the dev team can make a quick correction. But sometimes it’s not, and they get a call from you wondering why this other thing stopped working all of a sudden. With TDD, our engineers can quickly confirm that all the existing tests passed, so they can confidently make updates without disrupting the whole system.

The result: You have room to grow

We’ve worked with a company for a number of years on a software platform that allows them to display surface condition reports for every segment, or every airport runway, for an entire state (so that means lots of data). The product team requests improvements and changes all the time, and they recently merged with a company that uses a van packed with all manner of sensors to automate a large portion of street condition assessment for cities. Their code has become quite complex over the years, and yet, we are able to productively make changes to the code base without fear, which makes the client and our team quite happy.

4: Build systems iteratively.

When we say build iteratively, we mean pushing some small part of a larger system live, testing with real users, and updating that smaller part of the system based on feedback before running that cycle on other parts of the system. This allows the time and space to ensure we don’t prioritize big parts of the system that won’t get used, or would need significant modification, to meet users’ needs. 

We can also use this approach with existing or legacy systems. For many organizations, a wholesale replacement of a custom system is impractical. We’ve been supporting a legacy system for a client for several years, and we recently convinced them to update some parts of the system so they could take advantage of an off-the-shelf piece of software. We were able to separate parts of their system just enough that we could work one small segment of their system independently (it wasn’t pretty, but it works!).

If we build systems that are designed for change, and separate major functions from each other, we can build or replace parts of the system independently.

So, why do we think all this is important? 

Because bad software is still out there. The Consortium for Information & Software Quality (CISQ) reported in 2020 that the software project failure rate (that is, projects that are canceled before they ever get completed) has been steady at ~19% for over a decade, and 47% of projects are challenged in execution (meaning over budget, behind schedule, and produce low quality deliverables). This means only one third of software projects are fully successful.  The underlying causes are varied, but they do acknowledge that “most projects fail due to non-technical reasons” and that companies must create an environment we people are “seeking and acting on answers to the following questions” (among others):

  • Who are my customers?
  • What are their real needs?

Ultimately, the goal of a software project isn’t to decide which features to include, it’s to ensure your new software makes a real impact on your organizational goals and can adapt over time as those goals evolve. By integrating UX and engineering on our projects, the Pixo team and our clients can take advantage of the high-value feedback and learning that comes from watching people interact with iterative versions of the software we create. This approach means we only build features that users actually need, and those features match your users’ context and expectations.

Got a project idea you want to explore? Get in touch.