This post lists the key insights from this article, by the head of frontend engineering at Wix, Shahar Talmi.
In Wix they try to leave the assholes outside the door. They believe that 10x engineers are not only people that can produce 10x faster than most people, even more, those are people that can make a whole team 10x better by having a positive influence on anyone that they work with.
Many people spend a big part of their career in becoming what they think of as a decent engineer. It means you are a good coder, can solve problems and fluent in how to use the tools that are at your disposal such as IDE, debugger, services and frameworks. This article tries to describe what Wix Engineering believes makes a decent engineer into a 10x engineer.
One of the most important capabilities of an engineer is being able to work independently. In a nutshell, this means to always know what you need to do and rarely be in a situation where you wait for someone to tell you what to do. It doesn’t mean that you are able to do everything on your own, it just means that you know how to unblock yourself and how to unblock others on your team in a clean way that creates minimal technical debt. For example, if you get blocked by some issue, you will find a solution for it, whether it is by getting assistance from your peers or solving it on your own. Independent engineers have the ability to take a project from idea to production through all of its phases. They are able to define what are the things they require in order to be able to accomplish a task and they know when to raise a flag if they need assistance.
The most difficult thing you see less experienced engineers struggling with is being able to take a big task and break it down to smaller steps. This is important not only in order to be able to estimate how long something takes, it is also a critical part of building high quality software. Planning correctly means the developer can release initial version of the product as early as possible and start getting feedback sooner. Planning correctly means you have a design of the system early and you have a good picture of what you are going to do before you jump into the water. Planning correctly means that there are no big surprises that break your design while you develop. A good engineer should be able to break down a task, define the design and phases of release, and provide design documents and estimations to show his plan.
This is a hard one. Even the strongest engineers many times have place to grow when it comes to humility. It means not to be in love with your own solutions. To be able to listen and accept other people’s solutions. To assume the best of your peers and when you see something that appears like a mistake, try to understand the reasoning behind it. Open things for discussion. Let people suggest their own solutions. Share your ideas and never worry about getting credit for them. It is more important that everyone will feel comfortable with an idea and feel it was a team effort than everyone knowing that it was your idea. Be honest. Give people credit. Never be afraid to say that you were wrong or to acknowledge someone else is right. People respect people who can change their opinion.
It might sound trivial, but most people don’t understand that the best way to make progress is to build on top of prior work. Less experienced engineers always have the bad habit of thinking that the best way for them to move fast is to ignore everything that already exists and start again. Good engineers will always thoroughly look up, learn, ask about and understand all of the existing solutions already available. Even if existing solution is lacking, they will try to see how to improve it before they decide to replace it. They will never dismiss an existing solution without looking deeply into it and without speaking with the owner of the existing solution.
5. Infrastructure mindset
As described above, reusing prior work can have a huge impact on people. This means that engineers should always be on the lookout to see if they have an opportunity to create something reusable. The easiest thing to do when you have such an opportunity is to ignore it. Making reusable things always cost the “maker” more than making it not reusable, so many short sighted people ignore the benefits they and other teams will reap down the road. A good developer will identify the opportunities to create reusable things, know how to make them reusable in the best way, and invest the effort in doing so.
6. Master your domain
The only way to come up with good solutions is to thoroughly understand the product you are working on. Good engineers not only have a deep understanding of the product they develop. They also understand all of the use cases, understand the motivation for the product and can easily have meaningful conversation with the product manager, challenge decisions and offer alternatives. They know what are the important features and what are the less important things and know how to prioritize according to it and offer workarounds when needed. This is important not only for the product you work on, but also for any product you integrate with.
Good developers must have healthy curiosity which extends way beyond the boundaries of their domain. This is especially true for learning how the underlying technologies actually work, but it is just as important to understand the products that other teams are working on, their architecture and how they connect as a complete system. Having this wider context can be priceless when solving complex problems and a source of inspiration.
8. No boundaries
We often see that the source of bad solutions and bad architecture is rooted in people being afraid to change things that are outside the boundaries of their box. Client developer will tend to solve things on the client, even if it is better to solve it on the server. Application developer will tend to solve the problem locally even if solution belongs in the platform or in the infrastructure. The reason for this is simple. It is easier not to create discussion with a different team, it is easier to treat the world beyond your reach as a black box, it is easier to deal with the devil you know. But good engineers must know that they are part of one big system and that no part of the system is really beyond their reach. Discussing architecture change with a different team is healthy and helpful and might add to your perspective. Offering to contribute the change that you require is great for building trust between teams. Touching a new domain is an experience you can only benefit from. Most importantly, when your boundaries become more flexible, it means that your impact grows. Whenever you avoid reaching outside your boundaries, realize that what you are actually doing is holding yourself back from having a greater impact.
9. Responsibility / ownership
Although not immediately apparent, very often if you dig into the root cause of why some project was delayed or failed, you will find it boils down to ownership and responsibility. People will always tend to blame their surroundings: “I needed to wait for another team to complete something”, “I had a system issue and no one had time to help me”, “I received definitions too late”. A good engineer knows that those things are almost always excuses. When you are the owner of the task and the responsibility to make it happen is on you, your mindset should be that every problem that you encounter is something that you need to resolve. If you are blocked by another team, go and talk with them. Offer to pair on the problem and don’t “throw” the responsibility on someone else. If you didn’t get definitions yet, make some assumptions about what the definitions will be. It is better to make some progress and later make adjustments, than just sit and wait. If something big is delaying you, know when to raise the flag and know how to workaround the issue so that at least you can make progress on a different front. Never be in a situation where someone else is responsible to solve your problem, it’s the other way around — you are responsible for getting to the finish line and you need to deal with obstacles on the way.
This is a real game changer and often the most critical thing to have for an engineer to be able to have a huge impact on the whole team. Being able to communicate is the single biggest thing that enabled humanity to become what it is, obviously the same thing is just as critical to any aspect of life, including software engineering. Good engineers must be able to eloquently explain their ideas and opinions. They must be able to intelligently and respectfully debate with their peers. Communication is not just about speaking, it is even more important to be able to listen. Not everyone in the team will be able to express their ideas as well and a good engineer must be patient and ask the right questions to understand what other people are thinking and help them to be heard. All of this is just as important both for verbal and written communication, and more importantly it is not only conversing — developers life are full with tons of forms of communication: documents, presentations, documentation, code comments, commit messages. Even writing readable code and choosing good variable names is a form of communication.
This is one of the places even experienced engineers fail very often and don’t even know that it is happening. Think of all the times you said “it is too complicated, leave it to me”. Think of the times you said “this task is a one person job, adding more people won’t make it easier”. Think of all the times you didn’t have time to help someone else and never followed up, or you fixed/refactored someone code without asking for their review, or you did a big change without consulting with your team. There are tons of examples. And the thing is that even for experienced engineers it seems at the moment as the right thing to do. But this is tactical thinking which only pays off in the short term. If we want to achieve great things we must make sure that we can collaborate as a team. It is no coincidence that teamwork came right after communication. Those are the things that make us most effective, it is basic biology. Great engineers not only collaborate, consult with, learn from, assist, pair and respect their peers, they also mentor, point out problems, find interest and learn from everything happening in the team and proactively try to be helpful even for things that don’t directly concern them. Amazing engineers know when and how to come up with designs that will make it easier for many people to collaborate on things where much work is expected.
12. Keep it simple
The complexity of a solution can be one of the silent killers of the team’s ability to move forward and adapt. It is like high blood pressure. For the untrained eye it seems that everything is fine and everything is working as expected, but actually, deep inside, something that doesn’t directly affect any main functionality is slowly killing you. Good engineers create pragmatic solutions and readable code, even if you write more lines of code. Don’t show how “smart” you are by using all the language capabilities, creating redundant levels of abstraction, or writing a function in one line that nobody else can understand or debug. Don’t be a purist, don’t over-engineer solutions where not absolutely necessary and never be afraid to take something that is already complex and try to simplify it.
We can’t do everything. We can’t solve all of the problems. We can’t win all of the debates. We can’t make everything perfect. We have limited time and limited resources and we must use them wisely. This means we must be able to distinguish between what we need to insist on doing, what we can postpone, and what we should ignore. Developers do those decisions dozens of times every day. When we consider whether to investigate a bug, when we consider to do some refactor, when we consider handle some use case or edge case, when we consider to take a detour from our planned task and even when we invest time in convincing someone in our opinion. Good engineers know to be relentless in fixing, investigating, researching or insisting to make their point for the things that are really important. They know to take a note and come back to something later if it is important but not urgent. And they know to leave something alone or accept someone else’s opinion even if they are unhappy about it when it is not really that important.
14. Time management
As mentioned above, the sad truth of our existence is that we are bound by time. The products that we develop eventually need to go live, we have deadlines and estimations and targets to achieve. Good developers must develop not only an intuition for estimating how long their tasks take, but they also need to be clever about how they break down and order their tasks to even smaller parts. They need to manage their interrupts and context switching wisely. This intuition of time estimate is an inseparable part of being able to prioritize as described above. For example, If something is short enough, it might be worth doing even if it is not super important. And if it is too long, it might be better to postpone a bit or consult with your peers or manager.