To many, the term full-stack development may sound like a buzz word that is just a trendy concept, but this couldn’t be further from the truth. As the title suggests, it does give your development team superpowers.
The traditional way to setup development teams is by creating divisions between the development stack. Here is a simple example of this setup:
UI / UX: The team’s focus is on the look and feel that the end-user will experience.
Server Side: The team’s focus is on facilitating requests and responses between the UI team and the database team.
Database: The team’s focus is on optimizing data storage and retrieval.
On paper creating separate teams based on their skillset appears to be a sound approach, but there are many flaws.
The “Us vs Them” Mentality
Many dev shops are plagued by the constant battles between the different teams. Even though all of the developers participating in the stack are working to fulfill the same goal, there will come a point in time where each team will have its own idea of how to implement a solution or will believe another team is telling them how to do their job. This creates resentment and the barriers between the teams will thicken. As this barrier between the teams grows, it becomes less likely each team can come to agreements on solutions and priorities.
In the full-stack world, most of these issues will be avoided because each team will be divided up by domain rather than by technology. This means the team is in charge of their own destiny. If a developer needs a web api endpoint for a feature to go along with their front-end work, they simply create the endpoint they need avoiding all of the handoffs between multiple teams. No waiting or pointing fingers. They are fully accountable.
Addressing Knowledge Gaps
As mentioned above, a team designed for the full stack will be focused on one or more domain(s). This allows each developer to have a full understanding of the problems they are solving instead of just the small piece they are working on. When developers see the whole picture, they become aware of edge cases that they might not otherwise have seen, understand how to future proof and optimize their code, and are able to provide suggestions to other stakeholders that might not have been considered. For example, A developer realizes that the amazing UX they are wanting to build causes significant performance issues unless a change is made on the backend. Since they know about the entire architecture, they are able to come up with a strategy that solves both problems. They are able to solve this by knowing the entire problem, not just half of the problem. Empowering developers with knowledge around an entire domain provides them with a deep understanding of the product they are building. It can also benefit other stakeholders with alternative points of view, but ultimately provides the end-user a better experience which is what the product is all about.
We can measure the effectiveness of a development team by how long it takes to deliver value to the customer, this is called the “cycle time”. At Realtracs we take this number very seriously. By following a feature’s cycle time we are able to identify issues and bottlenecks in the development process. This allows us to constantly improve and optimize our process.
When we take a look at the traditional team structure there are many forms of waste that occur. Even though it seems that dividing your team by skillset would improve the overall cycle time, there is a caveat. It may be hard to spot what’s wrong with this approach, but when you look a little closer you will notice there is a hidden cycle time in play.
Let’s take a look at the illustration above and we can clearly see that there is a lot of context switching between feature A and feature B. We can also see that not only are Max and Pedro switching between features, but there is some rework that is required from Max once Pedro finishes his portion of feature A. Overall the process is complex and it’s not hard to see how mistakes can occur.
It is important to understand the the illustration above has been simplified. In reality there are many developers working on many different projects. To illustrate all of the meetings, context switching, miscommunications would be impossible to follow.
During development there is always going to be some form of context switching which involves meetings, coaching co-workers, updating managers on progress, etc. This should be expected and is required to further develop the people on your team and keep everyone in the loop about a project’s status.
Where the traditional model fails us is with coordination between the multiple teams. In order to get a fully working feature or application there are many handoffs that are required due to the interdependent nature of this structure. Synchronizing the different teams to have all of the pieces fall into place nicely takes time. It requires many meetings between the teams to plan, solve any shortcomings, get approvals, and wait for blockers to be removed. This extra time ends up being larger than the actual work involved. The bigger the teams and the organization, the more bottlenecks occur. These bottlenecks result in a lot of waiting and ultimately delay value to the customers (waiting is a form of waste).
When we take a look at the illustration above we can see this approach is much more simple. When a feature is being developed by a single person, it is very clear for a manager to know who to talk to for a status update. We can also see that each developer is focused on a single feature which eliminates the need for context switching between multiple features.
When we have a development team that has the freedom to code across the entire development stack without having to schedule meetings or wait for a request to be prioritized, the speed of development is drastically increased. These teams are not organized to increase the speed of coding, but to optimize the process as a whole. By minimizing handoffs and reducing the amount of context switching, we improve the overall cycle time for the team and ultimately deliver value to the customer in a timely manner.
Being a full-stack development team does not imply it is made up of amateur developers who do not have a deep understanding of either the UI or the server-side. In fact, the opposite applies. At Realtracs, we follow a simple principle: that we should be made up of T-shaped individuals. This means we are masters of some things and apprentices of others. It’s important on a team of full-stack developers to collaborate and learn from the experiences of your teammates in areas where you may not be as strong.
Sharing knowledge with one another creates a very healthy environment, and one where each team member will be able to grow their skillset and help mentor others. The two-way mentoring helps build consistent coding standards, fosters trust, and promotes humility.
The success of any team is determined by the amount of collaboration they have. Empowering developers to code through the entire stack is not intended to replace collaboration, but to eliminate the division of responsibilities. This is especially true when you have a full stack team with varying levels of skill within the development stack. Although a developer would be able to code without collaborating, this would result in misalignment and missed opportunities to grow their skillset. Communication is what sparks new ideas, raises concerns, shares knowledge, and builds trust. This is why collaboration is the most important piece to a successful full-stack development team. Additionally, full-stack encourages collaboration across teams. If someone gets stuck on a technology or architecture design, they go to someone else who is an expert in the subject. This other expert is not necessarily on the same team. Teams should be organized to have a complimenting set of skills, meaning they shouldn’t all just be experts of the front-end or back-end.
Empower and Protect
We follow another team principle at Realtracs that we call “Empower and Protect.” This means when we write our code we are mindful of the person that comes behind us. If we write a function or framework, this enables all of us to have more tools available when facing a problem. We write code in a way that will empower our fellow developers and protect them from misuse. We can accomplish this in a number of ways. For example, we write plenty of comments about the intention or caveats of a function, and we include extra checks to handle missing or malformed parameters for better error messaging. However, nothing empowers a teammate more than unit tests. Unit tests create a level of trust in the code that a relatively simple change will not come back to haunt you when it goes to production. This is especially true when onboarding team members who are both unfamiliar with the code and the potential impacts to their change. There are a number of ways to empower and protect a team, but the point is that being intentional about the way we write code is key to a team’s success.
As you can see, full-stack development has several advantages over a traditional development team. It promotes more collaboration, team alignment, individual growth, and efficiency through the entire process. Each developer on your team will feel a much greater sense of accountability for the product (and responsible for the customer) which will help your team to become an empowered product team rather than just a feature team. To top it all off, there is no bigger triumph than completing a project where you had your hand in every part of the development stack.