This is a (heavily) abridged version of an internal talk I gave at Unity in Copenhagen in December 2018 about User-Oriented Development. I’m sharing it here because I believe the learnings are useful outside of internal tools and outside of Unity.
Hello. Long time no . . . . write? ¯\_(ツ)_/¯
I’ve spent the last year working on a new internal project at Unity called Flight Control. For the purpose of this blog post, the details of what this application is and how it works aren’t super relevant, but at a high level, it’s a web application that aggregates data and information from a wide variety of internal and external applications and services. It then allows users to build up public and private dashboards that give them simple shortcuts to things that need to be done (pull requests that need to be reviewed, bugs that need to be fixed, etc) as well as data and metrics about our development organization and product, all in one place. In general, you could think of it as a flexible data and information aggregation and visualization application. Or something like that. The application is written in TypeScript and React and uses PostgreSQL. The main development was actually done by an external development team, but was driven by myself, with support and help from our internal data warehouse team and some others. This presented some logistical challenges but also actually had some benefits I’ll talk about later.
I tried to focus on a very user-oriented approach with this project, and now that the product has been developed and established, I’d like to share a few key points of that journey. There is a lot of stuff that I won’t cover in this post (like KPIs and metrics, details of our project management, etc) simply because there is just too much content from the talk for a single blog post. We’ll be focusing instead on what user-oriented development really means, our development approach (and how we worked successfully with an outsourced development team), and our key quality efforts. Finally, we’ll sum up with a set of key takeaways that I hope you’ll find useful.
What Does it Mean to be User-Oriented?
What does it really mean to be user-oriented when leading a software project? There are some different tools or methodologies you can use when thinking about this, but the one I tried to keep in mind was the concept of what we call User-Driven Development. User-Driven Development isn’t a particular methodology or way of working, but it’s a paradigm that can be used to guide the focus and working-style of a development team.
“The goal is to optimize the product around how users can, want, or need to use the product, rather than forcing the users to change their behavior to accommodate the product.”Wikipedia
Now this is a bit tricky because often, when you’re developing software, you do have a particular goal. The project I’ve been working on has a goal of gently exposing developers to more data and metrics than they would normally come across in their existing workflows. Figuring out a way to stay user-oriented without sacrificing any larger goals you have is tricky and a fine line, but I find that it helped me a lot to keep this User-Driven Development paradigm in mind.
So what this meant is reality was that I had a recurring mantra throughout the year that helped focus me:
“If we don’t make something that users want to use, then there is no point in any of this.”Na’Tosha’s Mantra
Our users are the top priority, always.
Now, this doesn’t necessarily mean that a user request is always right. They often don’t have the bigger picture or know what is in progress or everything that is going on, but it’s still always important to understand the motivation, because I could often still take a lot from the motivation, even if the exact request didn’t make sense.
3 Key Approaches to User-Driven Development
- Research. Research. Research.
- Design First, Not Last.
- Tight Feedback Loop.
The first important thing we did was a lot of user research before starting any development work. I identified a variety of different user demographics, interviewed them one-by-one to understand their problems, motivations, and what I would need to create to add enough value to gain them as a user. I also did some larger surveys (to our entire development team of several hundred people) to gain a better understanding of user motivations and was better able to predict impact and user behavior.
The second thing we did was to focus on the design and user experience from the beginning (before writing any code). We worked with a designer to create mockups of the site and design the UX flow first, and then used that to scope our development (instead of first inviting the designer in at the end of the development process to simply review what has already been done). This doesn’t mean that a fair number of things didn’t change, but it helped a lot to get us all on the same page and keep the user experience at the forefront of our minds.
The third thing we did was establish and maintain a tight feedback loop between our users (developers at Unity) and myself (wearing a lot of hats as Product Owner, Product Manager, and Technical Director). This allowed users to give direct and immediate feedback and me to prioritize our work and efforts so that we were continuously delivering changes and improvements based on their feedback. In order to enhance this feedback loop and keep a high-level of engagement with our early adopters and testers, we focused on short iteration cycles (2-week sprints with a deployment to production at the end of each sprint). As a result of this tight feedback loop, I continuously adapted the overall scope of what we were trying to deliver to better serve our users. But this didn’t just mean adding things to the scope, it also meant taking things away and letting go of earlier ideas as they became less important or didn’t make sense any longer.
Development Approach: The Practicalities
Since we were working with an outsourcing partner, we had a couple of challenges in front of us. The first was that we were not colocated, so we needed a good way of planning and setting expectations with each other. The second was that, as a result of being external, rather than internal to Unity, the members of our development team would usually not be able to connect the same dots that someone from inside the company, having a much bigger picture of who we are and how we work and having much more context about what we’re doing, would be able to. This meant that I needed to connect those dots for them.
This all led to us taking a more structured approach to our planning and tracking than I might have if I were working exclusively with an internal team. We used Jira for project planning (I know, I know, I can hear your respective shudders reverberate through the ether). Mostly it was used to maintain a backlog (which I kept stack-ranked at all times) and for sprint planning (we worked in two-week sprints with a demo and planning session at the end/beginning of each sprint and a mid-sprint demo/sync-up in addition to our daily conversations via Slack).
One thing to note was that in order to get off to a good start with a high level of development velocity, I pushed very hard for us to deliver something fast. I wanted something up on the screen as soon as possible, and then we could iterate from there. What I didn’t want to have happen was for part of the team to go off and spend three months in isolation working on some component.
It’s also worth taking a few moments to talk about some of the different quality-based initiatives we had. Of course we had the usual things of code review and manual testing (the QA engineer was embedded in the development team and tested every change as it was deployed and I typically tested most things a second time myself). But beyond this, I think we had three big components of our push for quality:
- Codebase as a Deliverable
- 20% Time on Technical Debt
- 100% Test Coverage
The first thing was that when we set out, I tried to frame the scope of what we were doing so that we thought of our codebase itself as a deliverable. This meant a focus on robustness, maintainability, and fitness of purpose. In the end, we wanted to not only end up with a good application that has gained traction and serves its users well, but also with a codebase that we are proud of and that will serve us well into the future.
The second initiative was that we prioritized spending 20% of our time on technical debt. Some people claim that new codebases don’t have technical debt, but that’s not true. It starts to build from the first time you have to make a change or implementation that you didn’t account for in the very beginning. There is nothing wrong with that, but it was important to me that we stay on top of this from the beginning. At one point in the middle of the project, after a particularly large feature was developed, we event spent an entire two-week sprint only on technical debt.
And the third thing was our test coverage. We set an expectation from the beginning of 100% test coverage. As we didn’t choose to do TDD (simply preference of most of the developers), our test coverage did sometimes lag but it has always been high and for recent months it has been 100% (on both the frontend and backend) and has been maintained at that level since then.
In the end, there are what I think are seven key takeaways from this journey.
- Outsourcing can work just fine.
- User-Oriented Software Development means being close to users.
- Get something up on the screen as soon as you can. Then iterate.
- Clear expectations are key.
- Stay flexible.
- Don’t just add. Trim.
- No Sacred Cows.
Outsourcing software development projects is often a recipe for wasting time and money. I don’t think this is because the model is inherently broken. I think it is because the projects still need to be driven by someone on the customer side with the vision and understanding of both the problem being solved and the complexities of the solution. In some ways, I think it can be an advantage because the development team is able to be isolated and focused.
It kind of goes without saying (or does it?), but user-oriented software development means being close to users. There needs to be a tight feedback loop, and the vision needs to be user-driven. With internal tooling it’s easier, because you are already close to your developers (but you still need to engage with them, discuss with them, and solicit their feedback). But this can also work with external customers, if you have a quality, well-staffed product team engaging with your users and that same product team is empowered to drive the vision and scope of what you are developing.
Time is so easily wasted in the beginning. Getting something concrete and up on the screen as fast as possible in the beginning is a great motivator for keeping everyone on the same page within the team and pushing a solution out to users sooner rather than later.
Making sure expectations are clear avoids confusion, disappointment, and wasted time. This includes setting your users’ expectations (what can they expect, when can they expect it), your developers’ expectations (what should they do, when should they have it done by, what do they do if something doesn’t go according to plan), and your management’s’ expectations (what are we planning to deliver, what are our goals and how are we measuring them, what resources will we use).
Stay flexible. When you are letting your users drive your product, you have to adapt to what they are telling you. Plan the near future in great detail but be flexible on the long term.
Don’t just add. Trim. There is generally a fixed amount of time you’ve set aside to complete a project (for us, it was a bit under one year). In order to stay within this timeline, it’s important to try and remove as much as you add. The easy part is adding. The hard part (but more important part, I think) is trimming.
There can be no sacred cows. Once again, your users, if you’ve engaged with them and built up a good relationship with them, will guide you and tell you what needs to be done. Let them take the reins.