· 8 min read

How I Improved Our Development Team's Efficiency

This article was auto-translated from Chinese. Some nuances may be lost in translation.

A few months ago was the release window for a major feature. Before transitioning to the next project, there was no heavy feature development—mostly just fixing minor bugs and refining existing features. Because the development pace was less frantic, I had more time this quarter to focus on process improvements.

Background

Let’s first talk about the situation during development. Every team and organization faces unique challenges, so understanding the background and the specific problems you want to address is crucial. In our case, several issues clearly hindered development:

A Large Number of People Involved Across the Organization

I’m currently involved in fintech development, covering products like FX (foreign exchange), equities, and mutual funds. While larger features are broken out separately (for example, FX is built as a standalone app), most features are implemented under the same website and handled by teams responsible for their respective projects. This led to:

  • High cognitive load whenever touching shared modules, as multiple teams are involved. Out of fear that modifying code might break something elsewhere, people leaned toward workarounds rather than directly confronting the issues.
  • Frequent merge conflicts during parallel project development. For instance, Project A might implement a desktop version, while the concurrently developed Project B had not. Merging the two projects often resulted in conflicts.

The Team Lacks Full Control Over Resources

For example, our QA process had to align with the schedules of all other projects. Since QA resources were limited, a completed feature sometimes had to wait one or two months before undergoing testing. The cost of this delay was substantial:

  • After a month or two, developers forgot the implementation details and had to spend time recalling them.
  • By the time QA reported issues and fixes were applied, the iteration cycle had stretched out significantly.
  • Certain APIs or implementations depended on fixes from other teams whose schedules we couldn’t control, ultimately stalling our development progress.

Cumbersome QA Environments

Ideally, there should only be one QA environment.

However, with parallel project development, limited test environments, and high overhead for spinning up new ones (due to architectural constraints), QA often had to run across two environments simultaneously. Because of the shortage, developers and QA sometimes had to share the same environment, creating several problems:

  • When QA ran into an issue, it was unclear whether it was a real bug or just a developer actively testing a new feature.
  • A lack of QA environments led to massive communication overhead. With such a large team, there were countless channels to coordinate with.
  • Setting up test accounts was tedious, leading to broken, unusable accounts scattered across almost every environment.

Fragmented Sprints

Although the team practiced Scrum, I noticed that after rolling off the previous project, the process became quite rocky. Likely reasons included:

  • Engineers within the team were assigned to different projects, rendering the Sprint Goal essentially meaningless.
  • No dedicated QA resources were available for testing.
  • Progress tracking lacked discipline; frequently, priority A was scheduled, but colleagues ended up working on priority B.
  • There were no clear targets or iterative cadences.

From this perspective, the team might not have met the necessary prerequisites for an ideal Sprint. When so many resources are constrained by external factors, a standard Sprint setup may not be the optimal choice.

The Improvement Process

While most of these problems couldn’t be resolved entirely on the development side, I believed we could at least address the development environment.

Before making improvements, you must consider the motivation and the intended goals. So, as a first step, I prepared a document outlining the current pain points and potential solutions.

The primary objectives were:

  • The development team should be able to freely switch between code from different branches. This was crucial because our developers were responsible for different projects running concurrently, which often led to scenarios like, “Hey, can I borrow the environment for a quick test? I’ll hand it back when I’m done.”
  • QA and developers should not share the same environment. This would eliminate ambiguity around the root cause when issues arose.

With this document ready, I initiated discussions within the team. These discussions served several purposes:

  • Confirming that everyone felt similar pain points, ensuring we were aligned on the problem.
  • Listening to colleagues’ individual constraints and concerns, which would be decisive in whether subsequent changes could roll out smoothly.
  • Brainstorming together. My ideas might have flaws, and pooling our perspectives could yield better alternatives.

While I want to focus more on the improvement process itself rather than the implementation details, here is a brief overview of my initial thinking:

  • Since our frontend runs as an SPA, simply uploading the built JavaScript bundles would allow us to switch branches at will. This would prevent developers from sharing environments with QA and let different dev teams switch environments independently.
  • Switch environments via query parameters. However, persisting query parameters is a hassle, especially since the app includes redirect logic (such as post-payment redirects).
  • Implement something like Deploy Previews (Netlify), where developers could click a URL directly from a PR to view the demo.

After vetting these ideas, several issues surfaced:

  • During deployment, the frontend includes a Node.js server acting as a lightweight auth server and providing convenience APIs. It wasn’t purely static frontend code. A simple file-upload approach would cause confusion and require substantial codebase modifications, which would likely face pushback.
  • Deploy previews typically require dynamic DNS. Since the company uses a private cloud, it was uncertain whether the necessary APIs existed. Additionally, features like login redirected to third-party pages for SSO with domain restrictions, so dynamic preview domain names would be rejected, causing login to fail. While viable for unauthenticated features, it felt like a half-baked solution that didn’t justify the cost.

Along the way, another engineer who felt the same frustrations proactively joined the effort (I had initially expected to fight this battle alone) and helped sort through the issues. I first explained the Deploy Preview concept to him; once he understood, he proposed a fresh alternative to our existing plan:

“Dynamically configuring DNS is too costly. What if we use Nginx for routing instead?”

The idea was to spin up an additional machine using our current deployment method (which took just a few clicks in the private cloud) and add a routing rule to Nginx on the original machine.

If a specific cookie was present, traffic would route to the development machine; otherwise, it would behave normally. This meant we didn’t have to touch a single line of application code (just minor tweaks to Jenkins and Ansible scripts), and the existing deployment pipeline could be reused, drastically reducing implementation costs.

Once we settled on the approach, we solicited feedback from other teams. The response was overwhelmingly positive, and our SRE team gave the green light as well. The implementation was complete.

The Results

Honestly, paper plans and demo presentations rarely make people feel the real impact. It only hits home once people actually start using it. When everyone transitioned to the new environment-switching mechanism, the feedback was universally glowing. We had genuinely improved the workflow.

Key Takeaways

This entire improvement journey took over three months from start to finish. Because it involved multiple teams, it naturally required more time. Staying patient in the early stages is essential; otherwise, you risk losing the team’s buy-in. I learned a great deal along the way:

1. Write the Document First

Drafting documentation is the first step toward building team consensus. When writing it, don’t focus excessively on the “how” of implementation. Instead, focus on defining the problem and outlining potential solutions to spark constructive discussion. Another benefit is that the team perceives the initiative as a collective effort rather than a solo crusade.

2. Focus on the Collective, Not the Individual

A major reason this initiative was well received was that the pain point was shared by many, not just me. When driving improvements, never base your reasoning on “because it feels better to write it this way” or “because I’m more familiar with this technology.” Instead, ask whether the change delivers tangible value. That is how you get buy-in and win allies.

3. Don’t Get Overly Attached to Technology

To be frank, this project barely involved any advanced tech—it was essentially just a conditional check. Yet the overall payoff was huge. Many engineers become obsessed with technology itself while losing sight of the problem they are trying to solve. Technology exists to serve human needs; if you forget that, the technology itself loses its purpose.

4. Don’t Fear Other Teams

Initiatives that require help from other teams can be intimidating. Most people prefer to avoid hassle, stay out of unfamiliar territory, and stick to their assigned tasks. However, as long as you can articulate the problem clearly and address their actual pain points, you’ll find that people are usually on your side. Sometimes their concerns might sound like resistance, but there’s no need to over-interpret them.

5. Find Like-Minded Allies

A huge factor in the success of this project was having another engineer who shared the same interest. He happened to be a backend engineer with a deeper understanding of the architecture, which led to the Nginx-based solution. Like-minded allies can’t be summoned on demand—when you find one, cherish the collaboration.

Related Posts

Explore Other Topics