At Sqreen, our company has evolved and changed a lot since we began this journey. Our frontend team is no exception, and as a member of that team, I wanted to take a moment to do a frontend team retrospective and reflect on how we’ve scaled, the mistakes and improvements we’ve made, and generally share what we’ve learned. I hope that this post may help you if you’re undertaking a similar journey.
In this post, I’ll explore what we did wrong, right, and how we tackle our weaknesses.
In the beginning: the birth of the codebase
About four years ago, our engineering team decided to move from Meteor to React due to our need for a more dynamic and interactive frontend dashboard.
We knew we had to move away from Meteor, but still, the decision wasn’t easy. Both our and the market’s expertise on the subject was sparse at the time. We took the leap anyway, and somehow managed to quickly bootstrap a small frontend team over the next year with 2 engineers that had little-to-no previous experience on the frontend side of things.
After we made the switch, the codebase grew and evolved extremely fast in all directions. At the time, it felt like we were doing something wrong. Rapid expansion by its nature feels disorganized and loose, which feels like you’ve got to be making mistakes. However, everything is situational. With the benefit of hindsight, today we understand that it was actually a strength given the context of where we were as a company and a team.
Although this may seem paradoxical to say, rapidly expanding the codebase allowed us to quickly bootstrap features in the matter of a day or week. Our focus at the time was product and nothing but the product. We had to iterate on the product and find what worked best for our customers.
The trade-off we made by moving so quickly was initial polish. The feature completeness within our product took a hit, but our customer base at the time was very understanding since they knew the stage we were at as a company.
However, after 2 years our customer base grew and started to (rightfully) lose their tolerance for the lack of polish and some of the bugs.
Finally, we started to reach a tipping point where we were simply not confident in shipping code. We even started to have about 5 to 10 important/critical issues in production per week. The degree to which we operated in the “move fast and break things” zone was starting to be too much for our stage and needs.
It was now the time to shift our process and habits and start to build towards a much healthier development lifecycle. Easy as can be, right?
Our learnings in retrospect:
It wouldn’t be much of a frontend team retrospective if we didn’t reflect on our learnings! When we look at the past with our current knowledge, it’s easy to see that we could have definitely improved quite a lot of things. Yet even with hindsight, we are sure we did the right things overall. By focusing more on quick iterations at the expense of polish, our product managed to evolve as much as we needed to and our business was able to grow. When you’re at such an early stage, activity and progress need to take precedence over polish and perfection. The cost of walking back failed experiments is much lower than the cost of not doing anything when you’re at an early stage.
So how do you shift towards a healthier development lifecycle?
Let’s continue our frontend team retrospective: the year is 2017. We knew we were in troubled waters if we continued operating in the way we had over the past few years. We had to shift our direction towards a much healthier development lifecycle, otherwise our customers would be too strongly impacted. However, knowing you have to adjust and actually making that adjustment are two different things. Here’s how we approached it.
The first thing we did before changing our direction was to take stock and recognize exactly where we were at the time. This meant asking ourselves what was causing trouble, what were our weaknesses, and what were we doing well.
Our weaknesses back in 2017
Upon review, we categorized what our key weaknesses were.
We kept repeating the same mistakes
This one was fairly simple, we simply kept repeating the same technical and human mistakes. Without any kind of process in place to formally address mistakes, we weren’t learning from them on an organizational level. We had no guarantees that our releases were clear of any issues, even ones that we’ve encountered in the past. We had no guarantees that our knowledge could be easily shared or discovered by anyone.
No clear direction on where the code will be in 6 months
Because we had little-to-no vision on where we wanted to be in the coming months, we grew the codebase widely in all directions. We looked at our challenges as isolated issues, with questions like “what if we use this lib to do that?” or “what if we use this abstraction to refactor this?” Each decision may have been good for the isolated issue, but didn’t fit into our broader needs as a technical organization. This blindness and lack of direction made it so our codebase grew harder and harder to maintain and evolve.
Not enough frontend expertise
We were able to intelligently challenge our engineering practices, yet it was harder to correctly challenge our frontend expertise. Should we use one abstraction or the other? What are the pros and cons of CSS in JS in our codebase? How do you write performant React code?
The good part was that we were actually asking the questions. The bad part was that we were missing the internal experience and expertise to be able to answer them!
The mindset and culture
At this time, we weren’t a team. Not in the sense that we would define a team today. We were working on the same projects, but we didn’t have much collaboration. This also meant that we weren’t able to scale as a team, both in terms of numbers and mindset.
Our strengths back in 2017
Despite these weaknesses, we knew we were strong in other areas, and we needed to make sure not to lose those strengths in the process of evolving our approach. That meant that we needed to take stock of our strengths as well.
Our team was product-driven
We all believe in our mission of securing the web. We also use Sqreen on our side projects, so we are all focused on creating the best possible product to achieve our mission. This is as true today as it was a few years ago.
A common question we asked ourselves is “is what I am working on contributing to this mission, and is it done properly so our users can also use it?”
Short development and iteration cycles
We are used to iterating a lot and quickly. We can ship multiple features within the week even if it would involve the whole team. We do not fear going back to a blank slate and retrying something that failed in a different manner.
Strong engineering spirit
Even if at the time we were not well-versed in frontend best practices, we were all engineers who were looking to improve together and to bring out the best of us so we can ship the best possible product for our users. Having the right spirit and attitude can go a long way.
Now that we had a clearer picture of our weaknesses and strengths, it was easier for us to decide what to aim for and what we had to change.
Recovering and implementing a change in our development processes
We decided to capitalize on one of our strengths to start working out our issues: we knew how to iterate quickly. We are able to quickly try new ideas, stick with them if they worked, and stop those that did not.
One of our first steps was to institute a weekly meeting to share the codebase improvements, ideas, and struggles from the past week. Having consistent team-wide check-ins helped us:
- Learn from our mistakes
- Share our knowledge
- Outline the current issues we had that could break today and tomorrow, and plan improvements ahead of time
Weeklies are prepared beforehand, listing any ideas and topics, and then tackled during a 30-minute meeting.
Here’s our current weekly outline:
- Any blockers? Anything you might need help with from someone else?
- Any components or knowledge you want to share with the team?
- Any topics you wish to discuss?
- Any actions resulting from this weekly?
This short meeting was the support structure for our iterations. It helped us understand our weaknesses and lay out actions on how to tackle them.
Now that we were sharing and communicating more often, we started to quickly learn from our mistakes and found ways to make sure they wouldn’t happen again.
Our team mindset
We also wanted to focus on the attitude that we would have as a team. We believe that being intentional about your attitude as a team is crucial for making any changes stick. Here is the list of our philosophies for our team that we came up with at the time:
- Customer-impacting issue are and will always be our priority
- Everyone has the same voice, no matter if you are 1 week in the company or 10 years.
- No one is blamed for screw ups. It’s never someone’s fault if something broke; the issue lies in the processes/toolchains that allowed it to happen.
- Be able to question yourself and change any existing process if needed
From this point, we were starting to learn from our mistakes, collaborate more than ever, and do so all under a very positive mindset. This helped us to grow both technically and collaboratively. Our next step then was to improve our velocity.
Using automation at the service of the developer
As we started to raise the overall level of our performance and teamwork, we also started to bet a lot on automation to keep, and even raise, our team velocity.
In order to keep improving our velocity, we adopted these two mottos:
- Automate as much as we can
- Make the developer experience as smooth as possible
How have these mottos translated to today in terms of tools and practices?
- ESLint, Prettier, and stylelint run by our IDE and pre-commit hooks
- We can simply focus on the code itself only. No worries regarding formatting or if the practices are followed or not.
- Extensive cache and optimization settings on webpack to improve as much as possible build and HMR times
- We highly value the developer experience. If the Hot Module Reloading is too long or buggy, we try our best to fix/improve it
- On every commit, unit test and e2e test run by the CI
- We want the developer to run a test only if needed and delegate them to the CI as much as possible
- Parallelized CI steps to improve performance and error reporting speed
- Granular automatic checks on PR + reviews
- When pushing a PR, it’s ok to have broken test. Yet the GitHub status helps us quickly know what tests are failing
- Master is always on prod and easy to rollback using Netlify
- Automatic error reporting using Sentry
This set of processes means that we have a pretty big toolchain. Between webpack, Jest, ESLint, Prettier, stylelint, PostCSS, Puppeteer, and Jenkins, it can easily get overwhelming.
Yet we try to make it so everyone gets involved in our toolchain environment to make sure we avoid any single point of failure!
Now it started to all come together. We were learning from our mistakes, we started to see where the codebase was heading, we all shared a great mindset, and finally, we had many tools to help us code in peace. Yet we were still lacking something: learning from others. At this point, we had spent two years in total with almost no changes to the frontend team. It was time to get out of our comfort zone and start being challenged by others.
Never stop iterating: meeting other people
At Sqreen, we value learning from others. While people within your company often have a lot to teach you, you run the risk of getting into a bubble. You can learn quite a lot from external people as well, With that in mind, we have implemented these practices:
- We meet with other engineers from French tech-centric companies
- We travel and meet with other engineers from SF companies
- We ask companies with particularly strong frontend teams to help us improve our codebase
- We started recruiting. This was and is an amazing opportunity to learn from others’ experiences as well
All these different inputs help us grow on many different levels, both human and technical.
Today and tomorrow
Today in 2019, we’ve reached a pretty solid state on our frontend development lifecycle.
We’ve reduced important/critical production bugs from upwards of 10 a week to a few a year.
We are very proud of the team we have built and we happily work together every day toward the same objective.
Yet we still follow this philosophy of questioning ourselves and thinking about how to improve the team. With that in mind, we can share with you what we are working on today.
One of our strengths back when we started out was being product-driven. Today, however, that alone is not enough for the quality of the product that we want to ship. We are now aiming to have an approach that is both product and data-driven.
Our current weakness now can be stated as such:
- When we develop a feature, we have no clear indication of how it impacts the user
What this means is that the feedback loop between shipping a feature and how it’s received and deployed by users is too long. It depends on the context, but by mastering this we will be able to make the right decision based on data rather than guts. We’ll be able to answer questions like “has my feature positively impacted the user?” or “should I improve or even roll back this feature?”
Diving into that would be another article in and of itself, but it’s central to the way we want to do things moving forward.
As we’ve taken a look back into our frontend team’s history, we’ve explored our ups and downs. However despite accumulating technical debt, our product kept moving forward, and that was the most important thing to us given the stage we were in as a company.
Then, as we grew and our product started to get impacted by our technical debt, we knew it was time to shift direction. By taking an honest stock of our strengths and weaknesses, we were able to take positive steps forward to help steer us in the right direction.
Hopefully what we shared with you here in this frontend team retrospective will come in handy to you one day!
If you’ve ever gone through something similar or relevant, don’t hesitate to share your stories with us. After all, learning from others is one of our central philosophies for improvement! And if you’re interested in joining us on this journey, we are hiring!