Peter Varholak4 min

Continuous Optimization: Resolve & Prevent Threats to Your Business

EngineeringAug 20, 2020



Aug 20, 2020

Peter VarholakFrontend Engineer

Share this article

Every project includes mistakes. The cause could be hacky code during tight deadlines, a lack of experience with the given technology or poor planning when proposing an architecture. These issues may not pose a problem right now. They may seem small. But, if left unchecked, they can easily snowball into obstacles that your team may not be equipped to handle.

With proper utilization of Continuous Optimization and carefully set up processes from the start, it’s possible to catch and resolve problems before they become a significant threat to your business.

Continuous Optimization relies on properly evaluating project health. To do so, there are four core aspects that require attention: Technology, Architecture, Setup and Tech Debt.

Let’s start with Technology. Our focus here is primarily on Legacy Code, Outdated Technology and External Dependencies. What are the symptoms of potential issues, which business risks do these issues pose and how do you avoid or quickly fix each problem? Here’s our take.

This article is a part of our Continuous Optimization e-book. Download it at the bottom of the page!


Choosing the right technology is a complex task in theory, yet in practice it boils down to simply analyzing what’s out there and how it fits your agenda.

One framework could seem absolutely perfect for your new project, but if you don’t have engineers with enough know-how, you might be better off with the tech stack you already have expertise in. Or perhaps you’re looking for, say, an emailing service—in which case, just pick your favorite and move on. No need for careful, weeks-long deliberation. Most of the time, you don’t actually need perfect. You need "good enough."

Sound like we’re setting the bar low? Not at all. The reason that we don’t want to make a specific technology the core of our business is because technologies should function solely as tools that help us achieve our goals. They should be easily replaceable once we get familiar with newer, better tools.

This doesn’t only apply to third-party software. What actually changes more often is the functionality within our own codebase because business needs incessantly evolve. Which is why we need to structure the code in such a way that it’s easy to move things around and recreate whole modules from scratch if needed.

The main blockers in doing this effectively are tight coupling and untested code—which are the primary focus points of Continuous Optimization.


Legacy code is any code you are afraid to change. That fear could stem from insufficient test coverage, outdated technology or a complex dependency relationship between your modules. Changing it poses a high risk because it can introduce unforeseen regression in all code that depends on it. Oftentimes, this code is maintained by a handful of individuals who “know how it works” and any attempts to introduce new engineers into this circle are accompanied by frustration and high business risks.


  • Insufficient test coverage (or no tests at all)
  • Only a small subset of engineers knows how to maintain the code
  • The technology used is outdated


  • Adding new features or changing existing features becomes slower
  • Domain knowledge gets concentrated into a small group of engineers, increasing the bus factor
  • Changes have a high risk of causing regression across multiple projects that depend on the legacy code


Adding unit and acceptance tests allows you to stabilize the existing behavior, which lets you make your changes with greater confidence. Creating a solid test setup is the first step towards tackling legacy code effectively.


Outdated technology is any functionality that could be replaced by its modern counterpart. Keeping outdated tech in the codebase leads to sluggish development, security vulnerabilities and overall higher cost per feature. Using these tools oftentimes hampers the engineers’ experience, who in turn become frustrated with slower progress. Onboarding new people becomes harder as well because junior engineers may not be familiar with the technology used and, if it is niche enough, there may not even be enough professionals on the market.


  • External dependencies are not actively maintained (no LTS)
  • It is difficult to find people with expertise in the given technology
  • The engineer experience suffers, as tools don’t produce fast and quality outputs


  • Older technologies can approach problems in ways that are incompatible with modern design principles, forcing engineers into outdated processes
  • Outdated technology usually has different priorities or was developed with different use cases in mind
  • Older technologies tend to increase latency for users
  • Finding sufficient expertise for code maintenance becomes increasingly more expensive
  • Onboarding takes longer and processes take more time with tools which are slower compared to their modern counterparts


Externalizing functionality opens up windows for potential safety breaches and makes code harder to maintain. Reducing such dependencies brings more control over code quality in the long term.


  • Bundle size is bigger than necessary Heavy reliance on third-party services


  • Fixing external dependencies can prove troublesome, as most of them are a “black box” Security issues
  • Stability problems
  • Slower migration to different services


Isolating external dependencies behind an API layer gives you greater control over changes. Regularly keep dependencies up-to-date and find alternatives for the dependencies which are no longer maintained, or bring the functionality in-house if possible.

To continue reading, download our Continuous Optimization e-book, which goes on to cover Architecture, Setup and Tech Debt. Get your free copy now!

Share this article

Sign up to our newsletter

Monthly updates, real stuff, our views. No BS.