Our public roadmap is something our customers and community have come to love about Front. It’s something we’ve had from the early years, and it’s visible evidence of our commitment to ship high quality work quickly and reliably.
As we’ve scaled to serve more than 6,000 customers, some with thousands of users, we’re proud that we’ve maintained that commitment even today. When I think about what’s helped us keep these standards, I believe it has a lot to do with our values.
Front has built a vibrant company culture around a set of core values—and for engineers specifically, these values reflect in our everyday work. Below are the 5 principles that guide our development at Front and drive us to live our values of transparency, high standards, low ego, collaboration, and care.
1. Optimize for trust
Engineering involves making calculated trade-offs, and implementing good design means that everyone can understand what these trade-offs are. If they’re unclear, it can hurt trust in our team, both externally and internally from other departments in the company.
When you need to make a technical decision: what will be the least surprising?
Even if the rest of the team doesn’t necessarily get all the technical details, how can we give them a mental model of our trade-offs?
We don’t always have to move quickly, but we always have to move predictably.
Plan for the future, do not anticipate it
When picking a solution, plan for future improvements, but do not build them. Sometimes, we are completely wrong about customer expectations, and we don’t want to invest time in something we didn’t even need.
Pick trade-offs that are understandable by everyone
If we have to give larger estimates because simple feature requests break previous assumptions, it will surprise everyone else. The danger is that no one will feel entitled to bring it up, and it will damage trust over time.
Code should break in predictable ways
Many pieces of software we ship to production will break unexpectedly. If this happens without any useful information on why it happened, it will be harder to troubleshoot and will make it more frustrating to everyone.
Frame technical debt as visible improvement (when possible)
Tech debt is the implied cost when development teams choose a limited solution to create something now, instead of using a more thorough approach that would take longer. By that definition, tech debt isn’t relevant outside of engineering: that’s why it tends to be abandoned. Of course, we won’t be successful if we accumulate too much of it, and sometimes, we need to stop what we’re doing to address it.
However, there are plenty of cases where we can organize roadmaps in a way that we can fix tech debt along the way. This helps reduce our backlog: if you care about something, you can usually find a way to sell it to the rest of the team so we fix it sooner.
2. Choose simple solutions
It’s harder to debug code than to write code. Do not optimize speed of development if it compromises ease of debugging—if we do, we’ll end up spending more time on code maintenance.
Do not cut corners
When a new engineer joins a team (especially junior engineers), they sometimes want to prove themselves. It’s a natural human feeling, but it can cause people to cut corners to show that they work faster than everyone else: it leads to bad pull requests that actually derail the roadmap.
That’s why we try to give each new employee what we call a “first mission”: a self-contained project that will keep them busy for a few weeks. It’s a way for them to learn about our stack and build confidence without directly comparing themselves to the rest of the team.
Do not take risks without good reasons
Engineers can have a natural tendency to artificially make problems bigger: it’s more satisfying to build a complex system. At Front, we are happy to work on basic problems when we can, and it usually turns out that we underestimated them anyway.
How it works in practice: When building counters, the little numbers that track how many emails are in your inbox, we realized we couldn’t build it reliably without Redis, an open-source database. Since it’s another component that can fail, we didn’t take the decision to add it to our stack lightly.
3. Be predictable
Programming is a complex undertaking. We always deal with unknowns, and it’s impossible to account for every risk. That being said, everyone is in the same situations, and the company cannot operate without deadlines. Progressing as an engineer means being able to put deadlines on more complex projects. Of course, this requires experience, but we’ve found that it actually requires mostly discipline.
We’ve always thought that engineering is a very creative undertaking. Historically, we’ve operated with very simple specs that provided a lot of headspace to decide things during implementation. As we get bigger, we are moving towards more detailed specs, but as engineers, we are still ultimately responsible for what we ship. Ask why throughout the entire process—having a full understanding of what’s happening from the start is critical for getting work done in a timely manner.
Break down projects into elementary tasks
Start every project by writing a “dev diary” with your assessment, and ask your teammates to review it. It can be as simple as your own to do list in a Google Doc.
In your dev diary, include questions as they come up so you can document the choices you are making. If you need to hand the project to someone else, or if someone needs to test it, they’ll be able to understand the trade-offs you chose by referencing your notes.
Finally, think about how your project will be deployed. Some of our tables contain billions of records (yes, billions!). If they need to be migrated, it can take several days. Breaking it down will make this process simpler.
De-risk dangerous tasks first
Start projects by building small proof of concepts for what you think is the most dangerous:
If you need to integrate with a 3rd party API, don’t assume that the doc is accurate: test it.
If your feature relies on an animation to be delightful: check if it’s fast enough.
Replay the flow in your head to make sure that there’s not something missing in the spec.
If you don’t know how customers will use a feature, try to think of acceptable limitations.
How it works in practice: Before releasing FrontChat, we had no idea of how much traffic it would receive. As a design goal, we defined that the chat infrastructure should be completely isolated from the rest of Front: if we made a mistake, only chat will be affected, which is a much lower risk.
Show results early
Another way of reducing risks is to ship parts of a feature and use feature flags. Having intermediate milestones will also hold you accountable and make you realize if you missed something. It’s also a great way to keep a good pace and feel like you’re making progress quickly.
Be able to demo it in front of the whole team
Use it as a hidden feature on our app
Use it everywhere in our app
Closed beta with select customers
Since we quickly got to a point where everyone could see for themselves that Front Chat was almost ready, we all felt more confident and less pressure while executing the project.
4. Write (clever) tests
Tests are a key element of a healthy culture: new engineers should not be afraid of experimenting. When something breaks, we should increase our coverage, not blame individuals. It’s also necessary for making continuous deployments safe.
Never break something twice
When something breaks in production, one of our best strategies to prevent it from happening again is to write a new test case. We want to make sure we catch the same bug in the future before it gets to production.
Don’t test for the sake of testing
While we strive for extensive test coverage, maintaining a test suite has a cost that needs to be balanced against the number of problems it prevents. Target things that are likely to break. Pick scenarios from likely incidents. When covering a new component, a good starting point is to put structure in the tests so that adding future cases won’t be widely more complex than fixing bugs. Then engineers are not tempted to fix without adding a test.
5. Be humble
Low ego is a core company value that we want to find in everyone, not just engineers. Because it’s sometimes hard to find in talented engineers, it has allowed us to be underestimated by some of our competitors when it comes to building our product.
Have empathy with customers
We take pride in keeping Front as stable as we possibly can. A large part of the bug reports we get are not technically problems with Front. Rather, they’re problems with other systems connecting to Front. However, it doesn’t mean that there isn’t something we can improve. We also need to remember that not all users bother to report bugs. When we’re talking to customers, we want to remember this and never jump to the conclusion that Front is always working exactly as we expect.
How it works in practice: A customer once told me that their analytics were wrong: “The average response time is incorrect—2 minutes is way too high.” I quickly checked the database, and it seemed correct. It later turned out that they were supporting operations in real-time over SMS. What they expected was 5-10 seconds. Since I assumed that it was over email, the initial report was very surprising.
At Front, we practice Radical Candor. Always remember:
Giving feedback is as uncomfortable as receiving it. The person giving you feedback is doing you a big favor.
First, say “thank you.” Do not try to give an explanation or defend yourself. Consider the feedback for as long as you need (give it time to marinate over several days). Then if needed, open up a healthy conversation around it to get clarity on both sides. The most important thing is to constantly improve as a group.
Think of future engineers
Our most important contributor probably hasn’t joined the team yet. Try to stick to simple, common constructs. If you think we should move to a more modern pattern, bring it up with everyone so we can think of a plan to introduce it everywhere at once. We also want to make it as easy as possible for engineers to contribute to a part of the code they’re not familiar with.
How it works in practice:
Some programmers use
!!xto cast a variable to a boolean. At Front, we always use
Boolean(x)because it’s easier to understand.
It’s still possible to install and run the entire Front stack in a few minutes.
If you see something, say something
Whenever we’ve encountered any major issues, we can usually look back and see that there were signals in advance that we ignored. We make an effort to emphasize that speaking up or asking a question about something you’ve noticed is always encouraged. We’d rather you raise a red flag, and you’ll never be criticized for doing so.
How it works in practice: We once had an issue that caused delayed messages to be sent twice. Some of us had experienced the issue, but chose to dismiss it as a fluke. It turned out to be a very bad decision: sending messages twice makes our customers look unprofessional and damages trust in our product. By speaking up at the first moment you realize there’s a potential problem, we can catch smaller issues before they become real problems.
Join Engineering at Front
This is our attempt at putting words to our engineering approach. It’s what’s guided us to where we are today and what inspires us as we move forward. Of course, it’s a work in progress, and as we grow and bring diverse perspectives to the team, we’ll keep questioning and evolving it.
We are a strong technical team with alumni from Google, Facebook, Twitter, Dropbox, Box, Airbnb, and other top brands. We’re scaling rapidly with a wide range of challenges: we run more than 100 services on over 10,000 Kubernetes pods at peak traffic, manage over 1PB of email data, and have customers with thousands of users collaborating in real time, totaling 1 billion WebSocket events per day. Company culture and employee happiness are a top priority for us; we recently made LinkedIn’s Top 50 Startups list, and you can check out our employee reviews on Glassdoor.
Interested in learning more? Check out frontapp.com/jobs.
Written by Laurent Perrin
Originally Published: 9 October 2020