This post is part of the Two Years at Gusto: Everything But Code series. The remaining parts are:
- Goal-driven is a losing mindset. Everything is an evolving process.
- Knowing what needs to be done
- When you are most helpless, you are most empowered
I have been working on the Payments Engineering team for about eight months. Since the projects we work on are either backend-heavy or mostly used by internal teams, engineers on the team wear product manager hats a lot. That means I have lots of opportunities to work with different stakeholders to figure out project requirements, prioritize projects and features, and deal with unknowns. I'm extremely grateful for this opportunity. It helps me to step out of the engineer zone and see the bigger picture. It changed how I approach writing software.
I used to care a lot about contracts and deliverables. I thought making it crystal clear how the software should behave under different scenarios is the key. I thought as long as all parties involved are on the same page about the deliverables, everyone would be happy when the software is finished. This was mostly the case when I worked as a full-stack engineer on the previous team where well-defined specs were handed down by product managers. But when I need to talk to the end customers myself to figure out what they want, having a clear contract is not enough.
The following three tweets from Dave Thomas perfectly sum up what I learned. (Feel free to skip the tweets Dave replied to and only read Dave's tweets.)
1. Negotiation good, contracts bad.
"the better we get at contacts the better we get at code" is true at the lowest levels, but not when software is up at the human level.
People don't know what they want, often until they see what they thought they wanted and realize it's wrong. Negotiation good, contracts bad.
— Dave Thomas (@pragdave) June 20, 2018
"the better we get at contacts the better we get at code" used to be what I believed in. I put a lot of efforts into getting a clear and well-defined contract in the early stage of the development process. During implementation, it's common to realize either we miss some use cases or some of our original assumptions no longer hold. As a result, we need to change the original contract. When that happens, I would secretly think it's because, in the contract design phase, I didn't do a good job of examining all assumptions and specing out all edge cases. I would try to learn the lesson and do a better job next time.
I later realized I was too obsessed with having the perfect contract. The overhead of coming up with a well-defined contract that covers all the cases is costly and might not be worth it. As Dave put it perfectly: "People don't know what they want, often until they see what they thought they wanted and realize it's wrong." Nothing beats showing the software and letting customers to play with it. A 30-page-long well-written-out google doc won't be nearly as effective as a half-baked MVP. Figuring out the real requirements as we go is an inevitable process. It's better to come up with a good-enough contract, get started early, get early feedback, and iterate quickly.
"Negotiation good, contracts bad." A customer will tell you a thousand things she wants. Instead of saying yes to all of them, it's better to negotiate with the customer. Always ask questions like: "do you really need that?", "how do you plan to use this feature?", "will it still does the job if we change the feature this way?" It might sound like you are pushing back the customer and testing her boundary. In fact, you are. These negotiations help both you and the customer uncover the true underlying core requirements. They also help you understand where the customer is coming from.
2. Influence as you deliver.
I'm not talking about mistakes here (although I also believe they are inevitable). I'm taking about +change+.
Delivering what is asked for is almost invariably disappointing. The goal is to deliver what it wanted. And that's a moving target, influenced as you deliver.
— Dave Thomas (@pragdave) June 20, 2018
"Delivering what is asked for is almost invariably disappointing." This sentence resonates with me a lot. When you deliver what is asked for, what normally follows is the customer saying: "oh...actually....now I think about it...". Again, people don't know what they want.
"that's a moving target, influenced as you deliver." I used to think the software's behavior is totally defined by customers. I didn't think I could or should have any influence about it because I'm not the person that uses it. Later I realized that as an engineer, someone who actually implements the software, I have my say in how the software should work. I should help shape the software.
3. An ongoing negotiation with reality.
Sometimes, even better, is to realize there is no "truth", just an ongoing negotiation with reality. The more perspectives you can explore, the simpler you can make the terms.
No one is ever "right" in a world of change.
— Dave Thomas (@pragdave) January 29, 2018
This last tweet is not about working with customers but with other engineers. I, too, fell into the trap of thinking "there's the truth and we can find it out". Over the past few months, I had many lengthy tech discussions. Every time, I walked away feeling myself getting closer to reality, not the "truth". When I understand other engineers' perspectives, I could see why they made such proposals. Reality is never ideal. The codebase is never perfect. Time is always limited. The technologies you choose never have everything you need. Often times we have different proposals not because some of us are wrong, but because we focus on different parts of reality. It's about meeting the constraints imposed by reality. It's "an ongoing negotiation with reality."
 In our case, because we were building internal tools, my customers were coworkers from other teams.  I later realized I misread the tweet. What Dave originally meant was what the customers' want is a moving target that gets influenced over time. But I misread it as what the customers' want is a moving target and we have the power to influence it over time. ?? Well, my point remains: engineers shouldn't just be implementers of a software but also the designers of it.