← Back to projects

Senior Software Engineer · 2021–2026

BODi - Streaming Experience

ReactNext.JSTypeScriptReact QueryChromecast SDKVideo PlayerAlgoliaAmplitudePerformance
BODi - Streaming Experience

About

This is the project I have spent the most time on by a wide margin. BODi is a fitness streaming product with more than one million active users currently: a web app, a Chromecast receiver, a video player, a TV app, and a set of internal tools, all sharing content and all expected to work at the same time.

Working on something that size for five years is a different job than building something new. Almost nothing is greenfield. Every change lands on top of years of decisions made by people who are no longer on the team, in a codebase that thousands of people are using while you are editing it.

The BODi streaming home screen, with a continue-watching row and program rails

The project

The surface area is wide. On the customer-facing side there is the catalog, the programs, the workout player, nutrition, badges and favorites, purchases, and search. Behind it there is a content API, an analytics pipeline, a search index, feature flag and configuration systems, and a Chromecast receiver that has to stay in sync with whatever the user is doing on their phone or browser.

My work fell into four rough buckets.

1. Making a large codebase move faster

The single biggest thing I contributed here was reduction, along with modernization. Over time I helped with the modernization of a codebase built by dozens of engineers but that was maintained by me and a few others. I've led the Next.js 10 to 12 migration, along with the removal of the custom code we had to maintain plain React.js with Next.js SSR, running both projects in parallel and showing them as a single website to the end user. This setup brought a lot of complexity to the project, but it was necessary at that time. This big refactor by itself reduced the memory footprint of the web app by 75% and improved the build time by more than half.

"It is way much better and we went from 40 pods to 10 pods without issues. bod web memory issue was really that it had to build inside the pod and then be available. That process was the one that ate all the memory and time for the pod to spin up."

— Kenny, DevOps Lead

Another important migration was migrating from Next.js 12 to the latest stable version of Next.js, migrating all the content website to a new Next.js project, redesigning the architecture of the app, how reusable components should be built, what to delete or what not, which libraries make sense to migrate, etc. Keeping the project up to date with the technologies over the years brought challenges, mainly considering how complex the project was and how small the team was.

2. Migrations on a platform that could not go down

Six large migrations, each of which had to happen underneath live traffic:

  • Algolia V1 to V2 — the search stack the entire catalog depends on.
  • Video.js updates — the main engine behind the custom video player implementation.
  • Chromecast CAF SDK update from v2 to v3 — the receiver project that is shared across platforms and more than 30k users use every day.
  • SSO — replacing the existing authentication flow across the apps, from Akamai to Auth0.
  • Config Manager to Doppler — moving configuration and secrets to a single source.
  • Tealium to Amplitude — rebuilding the analytics layer, which also meant fixing accuracy problems that had been quietly distorting reporting for a long time.

The pattern that made these work was almost always the same: ship the new path behind a flag, run both, then delete the old one properly rather than leaving it as a fallback nobody maintains. It feels easy on paper, but each migration brought its own challenges. For example, dealing with the Chromecast SDK update or the auth provider migration behind a feature flag is a really big challenge, then feature flags on their own are not the only tool to ensure we have an easy way to roll back if something goes wrong.

I'm glad to say that we had challenges and issues along the way, but none of the problems reached the end user. The migrations were all successful and I believe that is mainly because of how we approached them, with a lot of planning, testing, communication with the team, monitoring and mainly how mature we were about the project and how we could handle it.

A program landing page in the BODi web app

Another interesting challenge was to implement the new global search page: This page handles different Algolia indexes, filters, content types, etc., all in one page while providing a fluid experience to the user.

The Algolia SDK helps with pages that should an index per route, but when we have an input to refine the query, keep the state in the URL (if the user copies and pastes the URL in another browser tab, the results should load filtered by the same query and filters), have curated filter lists that should extend the existing facets exported by Algolia and also handle different indexes, it becomes a problem that one logic change in one part can break another part of the page if it is not structured correctly. In-memory caching was also important to avoid unnecessary requests to Algolia, to avoid costs that could be easily avoidable.

The approach I took for this page was the same I try to apply to all projects/tasks I take: Do good research before even touching the code, understand the problem and edge cases, then implement a simple version, validate with the team if the infrastructure and the approach make sense, then iterate on it until I have a final version, along with product and design team review and ensure the PR is self-explanatory, with links to the preview environment, screenshots, videos and a detailed description of the implementation and the edge cases handled. This approach is important to ensure that the code is maintainable and that the team can understand it in the future.

This page was a success too, with no major issues reported by users, and the monitoring systems show it is working fine, even with all the complexity it has.

The BODi web global search page

3. Features across web, TV, and cast

Alongside the platform work, the feature list included the Content Hub, a Metrics Dashboard, Digital Purchases, and significant updates to both the Chromecast SDK integration and the video player.

The multi-platform part was consistently the hardest. A bug that only reproduces when a user starts a workout on iOS and casts it to a TV using a specific device generation is not an easy bug to reproduce. A lot of my time went into reproducing and untangling exactly those cross-platform cases with the iOS and Android teams.

The Video.js updates example is a good way to show it: Every time we updated our Video.js version or when updating how the events flow between the Next.js web app and the player itself, we always relied on monitoring and analytics to ensure that the player was working as expected, understanding for which browsers we expect a worse Conviva SPI score, the thresholds for each browser, what shows that an update was successful or not, as well as understanding when a rollback makes sense or not. The player is a critical part of the product and we had to ensure that it was working as expected, and that the user experience was not hurt by any of our changes.

4. Leading the work

As part of the expertise I got working on the team over the years, I started to lead some initiatives, mainly due to how I communicate with the team and how well I knew the codebase. That was a great opportunity to help other engineers with questions, code reviews, and ramping up new engineers.

I'm also glad to have great engineers working alongside me, and I learned a lot from them. I believe that is one of the most important things in a team, to have people that you can learn from and that you can help to grow as well.

Conclusion

Five years on one product taught me things a shorter engagement never could: understand a codebase in depth, plan refactors or big features ahead of time with precision, build trust with the team, understand and learn that decisions have consequences and bad decisions can have significant impacts later, learn how to lead initiatives, how to better communicate with the team, and mainly build a project over the years we're proud of, making real impact on the business and the users.