Over the last year I've been working on a live data prototype team tasked with finding a repeatable process to sufficiently reduce risk in new design and product ideas. Over time, we've found certain projects that are too complex for paper prototypes or even live code that uses mocked data. We can engage with a small engineering team, but that has problems. For starters, it's tempting for engineers to do what they do best: write great code. That's great when you're marching towards a shippable product, but severely slows things down when you're still trying to figure out what to build.
We wanted to experiment by building a small team that cares more about speed than quality. Does focusing solely on the defined problems and hypotheses, ignoring code quality and design polish, reach the correct solution faster? If so, does that result in great product being shipped faster?
We're still answering the question of whether final product is shipped faster. However, we've arrived at a set of patterns and anti-patterns that have had great results in sufficiently reducing risk enough to be confident in the proposed solution.
These patterns speed up the prototyping process, validate hypotheses efficiently and cheaply, and accurately determine the minimum interactions necessary for new product features. These patterns focus on early stage prototypes of product designs. These patterns likely won't apply to late stage prototypes or to prototypes that are intended to validate engineering solutions, as opposed to design solutions.
Value speed over quality
In early stage prototyping, it's more important to get to the correct design and required interactions as efficiently and cheaply as possible than it is to have code that is well designed, well performing, and readable. A design prototype should never be used to validate an engineering implementation. As such, ensuring performance at scale for a prototype is not priority. Further, a prototype can be ugly and buggy as long as the workflow being tested is usable.
To drive this point home, the motto that hands on our wall is "Write bad code fast."
This is not to say that well engineered products are not important. However, it's important to prove what needs to be built for the first release before it is actually built.
Domain specific applications
Focusing on testing solely the highest risk items is critical in early stage prototyping. Sometimes in order to maintain hyper focus, it's encouraged to build an application to test an idea in isolation from the application the idea is intended for. For example, during one project where we were working on a filtering language, we needed a way to rapidly develop a user friendly language that would cover all the types of queries users needed. We also needed to develop an interface for entering queries. Instead of prototyping the feature in the product it was intended for, which would have taken considerable time, a smaller inventory application was built in three days. When testing, we appeared as to be testing the inventory application, but in reality it was how the users interacted with the filtering interface that we were focused on. Building a small application greatly reduced the time necessary to iterate on the design.
Follow the evidence
The goal of design prototyping to is to sufficiently reduce risk for a design idea as quickly as possible. Since building is expensive, even when you care far less about code quality, it's important to only build prototypes that have evidence they're necessary and correct. Building a product or feature without the evidence of necessity is not a design strategy, it's a product strategy, and it's a bad one. While trying multiple designs is highly encouraged, each design must have evidence it may successfully solve a real, documented problem.
Evidence should come directly from users when possible. For example, it can be obtained from discovery interviews or usability tests.
RITE (Rapid Iterative Testing and Evaluation)
RITE is a philosophy that testing should be continuous, rapid, and result in immediate changes. RITE encourages continuous testing of in-flight development. It values evaluation immediately after learning from each test. This is in contrast to designing an implemented to a certain point, then conducting multiple tests of the design (without changes in between tests), taking the cumulative results of the tests and making necessary changes. RITE promotes steady iterative changes over a short amount of time.
While it may sound like RITE promotes reacting to superficial data, early stage prototyping ends up finding the low hanging fruit in solutions. Putting a functional early design in front of a user often results in revealing the otherwise obvious, as opposed to nuanced interactions that require complex analysis of large amounts of user data.
Since design overhauls are difficult when using RITE, it's important to have a stopping point to allow time for redesigns, if necessary. This opens the door for design inspiration without waiting around for inspiration to hit.
As soon as the prototype can complete a single happy path, it should be tested as soon as possible. Even if the design isn't done being implemented, it's critical to get early feedback as soon as possible. The ideal cadence is three tests every week.
The natural instinct when designing products is to build out what you believe to be minimally necessary and reduce as you learn. Further, when you're not sure about is needed for a user to accomplish a task, it's natural to take a stab at a solution and test it, hoping to learn more from the test.
The proper response to both of these instincts is omission, not creation. Forcing a user to attempt a task you've purposefully omitted the affordance to accomplish causes the user performing the test stress and pain. By intentionally causing pain, they will more openly talk about what they expect to find and how the expect to accomplish the given task. This not only provides less biased insight into their expectations, but also provides the necessary evidence for the next step in design.
Good design is always apparent after the fact, but never before. It's important to show where a design started and the different paths taken, including the failed ones. Failed designs are particularly important to show. It's important for Engineering and Product to understand why the design being proposed is necessary and why it should be engineered over other designs that are perhaps easier to build. Defensibility provides credibility to proposed design.
Anticipating user needs
Anticipating user needs at first glance sounds like it should be a pattern, not an anti-pattern. However, it's important to resist capturing all the different ideas you could implement and test. Only capture the needs you have evidence for. Capturing what you think users will need is making up user needs rather than learning them. If a user need truly is necessary, it will become apparent through following the evidence. And purposeful constraints.
Peer code review
Since design prototyping values speed over code quality, every moment not spent building a tool to validate a hypothesis is wasted. Therefore, any time spent reviewing code is wasted time. Further, since all code is disposable as soon as the hypothesis is validated, the maintainability, readability, and robustness of the code is irrelevant.
Code branching promotes working on a piece of the codebase in isolation until it's ready to be used by the rest of the team or test pilots. It does not promote moving quickly. It is recommended that prototype projects never fork nor branch the code base. Everyone commits to a single central repository to a single master branch. Further, it is encouraged that everyone push their changes at a rapid pace even if the work is incomplete.