Is there any secret of making the team stronger?
Starting from 2014, the Codementor team grows from then one-person to a thirty-ish one. Although thirty is far from a large number, intending to move as fast as possible as a team, we’ve been facing different kinds of challenges at each stage. In hindsight, we didn’t come up with the standard ways of making decisions in the first place. Instead, the ideas emerge and shape themselves when we work, communicate, and struggle together.
After reviewing and sorting out our ways of doing things, in this post, we are going to share what we have tried and the idea behind them to improve ourselves. One of the essential ideas is: Almost all the things, including concepts and processes, are dynamic. The external conditions are always changing: Some processes you feel awesome might start to become annoying next month. There will never be any “best” solution. The point is to review ourselves frequently and always look for better solutions.
Before we start
Looking back, having a common idea of “what the most important thing is” is essential when solving a problem. For Codementor, the “thing” is to do things with quality and speed at the same time. As a startup, we think the only weapon for us is speed. We want to deliver products to our users as fast as possible to turn assumptions into knowledge. But at the same time, we all know good things take time to build. Moving too fast can drag ourselves in the future. So “doing things with quality and speed at the same time” boils down to a question: How can we move as fast as we want without sacrificing the quality? Of course, every team has its own “the most import thing.” No matter what that is, finding it as a team is the essential first step.
After defining the “most important thing,” the next question would be: How do we achieve it? For Codementor, we think the critical point is People. And the People things are highly correlated with Hiring. In other words, if you hire right, you can likely do it right.
But how do you know if you are hiring right? For us, we define two kinds of traits for people:
The first kind is the ones that are easy to change: Things like knowing how to program in a specific language or familiarity with using a framework. These traits can be changed relatively easily: Even if I can’t answer the question: What is the purpose of the database index? (But actually, I can :p ) it’s not that hard for me to learn it tomorrow with the assistance of Google.
The second kind is the ones that not easy to change: Things like personal values and the ways of communication. As the saying goes, “A leopard can’t change its spots.” In our hiring process, we define the second kind of traits we are looking for and use those to find our ideal future team members. So far, that kind of traits for us are:
1) Like our product:
Like our product: The passion for our product one of the things we care about the most. The idea is that everyone should be doing the things he or she loves. Life is just too short to be spent on the things you don’t like. We are spending one third, if not more, of our life on our job. We can’t think of any reason for people to work on something he or she doesn’t like every day. Putting it positively, we believe every team member plays an essential role in building the product. If the team members like the product, they will have many ideas to make the product better.
2) Like the things he or she will be doing:
The idea is similar to the one above. We view it from a different angle here. Take the Dev team as an example. Engineers will be spending most of their time writing, reviewing, and discussing code. We are looking for the ones who enjoy doing these.
3) Like our team and our team likes you:
It would be painful to get alone with someone you dislike for eight hours every day. Usually, people call this Culture Fit. We feel the term is too loaded under this context, so we define it as the following:
3.1 Care about similar things as we do: For us, the thing we care about the most is to strike a balance between development speed and code quality. It may not be easy to find a qualitative measure for this. But usually, we can tell from the back and forth during the interview.
3.2 Can do “rational and fierce debates”: Whether it is programming, process, or product, we find it so difficult to do it “just right” in the first place. Instead, the right decisions take iterations from trial-and-error to be “modified” as the right one suitable for each situation. During the process, one critical step is that team members have to keep challenging each other to distill the right solution. That’s why we expect our future team members this way. In plain language, we need to be able to challenge each other critically without any one of us getting mad.
Experiments, Experiments, Experiments
In addition to People, another point we find essential is the habit of conducting experiments on almost everything. Looking back, some right decisions we made on products, processes, and technologies were the results of tests.
Build the environment and process for experiments:
The typical flow of experimenting would be: - Define the problem - Define the hypothesis and design the experiment - Experiment and see if the result is the same as expected - If not, find the underlying cause
At Codementor, we experiment on almost everything. From building a new product, adopting pair programming, to exploring a new programming language. Paralleled to the experiments, we also want to keep our product line progressing as usual. Here is when precisely defining the problem and scope, clearly assessing the results become significant. Such steps are easier said than done. But according to our own experiences, it gets better with practicing.
Take Arc, one of our main products, as an example. Back then, some of our users wanted to outsource their cases rather than learning how to do it via our 1:1 live mentoring platform. We tested our hypothesis by sending them questionnaires, matching them manually before we built anything. After countless iterations, we released the product. (Of course, there were way more failed cases we didn’t mention in this post :p ) By experimenting, we can know whether an approach works or not without guessing. And from failed experiments, we can usually learn more.
Improve ourselves every day - Disseminate the knowledge
If we improve by 1 percent every day, we become (1.01)³⁶⁵ = 37.78 times better after one year.
Each team member may be good at different kinds of things. If we can find a way to disseminate the knowledge from each team member efficiently, the team can grow in a highly leveraged way! And if each team member improves, the overall productivity of the organization grows. The effect of learning is something we feel particularly strongly after our team size increases. We’ve tried several ways to do it, here are some we would like to share:
Weekly Dev Sharing
Started from January 2017, we’ve been doing Dev Sharing every week. Developers share technical related topics during the lunchtime. It may be the book we’re reading recently, some blog posts we find fantastic, tricky bugs we encounter, or some fightings with the legacy code. We document all of these in a publicly accessible place. The topic ranges from the lightweight ones such as “unit-test 101”, to some tough ones such as “Dynamo DB” or “Google Cloud Composer,” to non-technical ones like “Design Thinking,” “Design Language” (yes, they were shared by developers.)
So far, we still feel it enjoyable. As audiences, we can get a broad picture of a topic or a problem to solve quickly. As the sharer, we became more mindful of our leanings and problem-solving.
Before every single branch gets merged, it must go through the code-review by one or two colleagues. Through such a process, we familiarize ourselves with the whole codebase. If the reviewers feel there is something that can be changed or redesigned, she can discuss it with the author on the spot. The entire process is an excellent opportunity for learning mutually.
Post-mortem (learning review)
After each significant outage (such thing happens, you know,) we record the events, steps we take in detail, including at what time who did what and why. The purpose of it is not to find someone to blame on but to construct a process so that we won’t get into this trouble next time, even if we are as careless as this time. , Also, we find it essential to document the things above in a way that everyone can consume the content easily. The document becomes a shared and accumulated resource growing with the team. And new team members can learn from past experiences.
Speed up the feedback loop
As developers, we all know that speeding up our feedback loop brings us tons of advantages. It allows us to fix the errors on the spot and prevents us from working in the wrong direction for too long. Take coding as an example. After writing a small piece of code, if we know it is not doing what we expect immediately, we can fix it quite quickly with little effort. And we can enter the next “knowing result -> fix errors” iteration smoothly. On the other hand, if it takes longer to know the result, the iteration becomes inefficient. Aside from wasting time on the waiting, we are likely to make the same mistake during the waiting. The next iteration gets slower due to the errors.
Programming techniques such as TDD, CI/CD are aiming to speed up the iterations. Parallel to that, development processes also iterate themselves by the “knowing results -> fix errors” cycle. Compared with the programming ones, the cost brought by “process error” is way more substantial. It may be some redundant communication or the need for a new way to document. Such mistakes take longer to fix, which amplifies the importance of the feedback loop.
At Arc, we tackle this by defining a process to collect feedback periodically and efficiently. There is a similar process called Retrospective in Scrum. (I’m far from an expert of Scrum, so correct me if I’m wrong.) But since we are not running official Scrum, we do it monthly and call it Process Review.
Each month, all developers gather to discuss whether there is any way to improve our processes. The reasons behind that are: - All the processes are dynamic over time. A process serving us well last month might start to be problematic now. - It’s always possible to become better.
And for “process” we mean:
- Development Speed
- Easy to Release
- Code Quality
- Feeling valuable for the things we build
- Feeling supportive within the team
In large, all the processes boil down to a question: Is there any way to better streamline our development? Doing that on a timely basis allows us to discover problems before they become out of control. Although we don’t always have solutions to the issues we find, experiments get us closer.
It is pretty much about how we treat “improvement” and what we’ve done to achieve it. For us, the first step to becoming better is to realize that we are not good enough, and believe that we can keep improving as a team. It is far from an easy thing. But with an environment welcoming to mistakes, we can keep approaching it gradually by keep trying.