This post was originally published in ACM Queue.
It all started with a bug.
Customers were complaining that their information was out of date on the website. They would make an update and for some reason their changes weren’t being reflected right away. Caching seemed like the obvious problem, but once we starting diving into the details we realized it was a much bigger issue.
In this case the back-end team managing the APIs and data didn’t see eye-to-eye with the front-end team consuming the data. The back-end team designed the APIs the way they thought the data should be queried – one that was optimized for the way they had designed the schema. The challenge was that when front-end team wrote the interface the API seemed clunky to them – there were too many parameters and they had to make too many calls (which negatively impacted their mobile experience where browsers can’t handle as many concurrent requests), so they made the decision to cache part of the data locally.
The teams didn’t work together. They didn’t take the time to understand the needs of the other team and the end result was a weird caching bug that affected the end user.
Now you might be thinking this could never happen on your team, but the reality is that when you have a lot of different people working on a problem they can all have different ideas on the best solution. And when you don’t have a team that works well together it can hurt your software design (and its maintainability, scalability, performance, etc.).
Most software systems are comprised of parts and pieces that come together to perform a larger function. Those parts and pieces can be thought out and planned, and work together in a beautiful orchestra, or they can be designed by individuals where each one is as unique as the person who created it. The challenge is that if you want your software to last, uniformity and predictability is a good thing – unique snowflakes are not.
One of the challenges when you manage is a software team is balancing the knowledge levels across your staff. In an ideal world, every employee would know enough to do their job well, but the reality in larger software teams is that you always have someone getting up to speed on something (a new technology, a way of building software, or even the way your systems work). When someone doesn’t know something well enough to do a great job they have a knowledge gap – and these are pretty common.
The challenge is that when you are building software and moving fast, people don’t always have enough time to learn everything they need to bridge their gaps. So they make assumptions or concessions that can impact the effectiveness of your software. This can be someone choosing a new technology that hasn’t been road tested enough in the wild. One of the common places this happens is between teams or disciplines; for example, someone creating a band-aid in one area of the system, because the underlying issue is just too complex to diagnose and fix.
Everyday people are making decisions with imperfect knowledge, and so the real question is how can you improve the knowledge gaps and leverage your team to make better decisions.
There are a few strategies that can help your team work better and help you create better software.
- Define how you will work together. Whether you are creating an API, or consuming someone else’s data, having a clearly defined contract is the first step to a good working relationship. When you work with another service it is important to understand the guardrails and best practices for consuming that service. For example, you should establish the payload maximums, and discuss the frequency and usage guidelines. If for some reason the existing API doesn’t meet your needs, then instead of just working around it, talk about why it isn’t working and collaboratively figure out the best way to solve the problem (whether it would be updating the API, or leveraging a caching strategy). They key here is communication.
- Decide how you will test the whole system. One of the most important things is that you think about how you will truly test the end-to-end functionality of a system. Having tests that test you parts of the system (like the back-end APIs), but not the end customer experience can result in uncaught errors or issues (such as with my opening example with the caching). The challenge then becomes who will own these tests? And who will run these tests and be responsible for handling failures? You may not want tests for every scenario, but certainly the most important ones are worth having.
- When bugs happen, work together to solve them. When there are problems, try to avoid solutions that only mask the underlying issue. Instead, work together to try and figure out what the real cause of the problem is and then together make a decision on the best way to address it going forward. This way everyone can learn more about how the systems work and any band-aids will be made well informed by everyone involved.
- Use versioning. When you have another team consuming something you created (an API, a library, a package) versioning is the smartest way to be able to make updates and keep everyone on the same page with those changes. There is nothing worse than relying on something and having it change underneath you. The author may think the changes are minor or innocuous, but sometimes those changes can have unintended consequences upstream. By starting with versions it is easy to keep everyone in check and predictably manage their dependencies.
- Creating coding standards. Following standards can be really helpful when it comes to code maintenance. When you depend on someone else and have access to that source code, being able to look at it and know what you are looking at, can give you an edge in understanding, debugging and integration. Similarly having things like a style guide where styles are inherited and reused throughout the code can help make sure that your user interfaces look consistent – even when different teams throughout your company develop them.
- Do code reviews. One of the best ways to bridge knowledge gaps on your team is to encourage sharing among team members. When someone else reviews and gives feedback they learn the code too. This is a great way to spread knowledge across your team.
Of course the real key to great software architecture for a system developed by lots of different people is to have great communication. You want to everyone to be able to openly talk to everyone else, ask questions and share their ideas. This means creating a culture where people are open, and have a sense of ownership – even for parts of the system they didn’t write.