Backend Development 13 min read

Interface‑Driven Design for Scalable Media File Migration in Elixir and Ruby

The talk explains how Tubi's Multimedia Processing Platform uses an interface‑driven architecture, Elixir protocols, and composable movers and comparators to migrate petabyte‑scale video files across cloud storage while balancing performance, cost, and testability, offering practical insights for Ruby and backend engineers.

Bitu Technology
Bitu Technology
Bitu Technology
Interface‑Driven Design for Scalable Media File Migration in Elixir and Ruby

RubyConf China is an annual technical conference organized by the Ruby China community. The speaker, a Tubi Elixir engineer, introduced the Tubi Multimedia Processing Platform (TMPP), a free streaming service that must ingest, process, and store millions of video files across multiple cloud back‑ends.

The core challenge is migrating petabyte‑scale media files between cloud storage providers while ensuring complete, verified transfers and minimal cost. Functional requirements include batch migration by folder, data integrity verification after each move, and recording the new location in a database.

To meet these needs, the team adopted an interface‑driven design . Two core interfaces were defined:

Mover.move(mover, source, destination) – responsible for moving data (files, DB records, etc.).

Comparator.compare(comparator, source, destination) – responsible for verifying that source and destination data are identical.

Implementations of Mover include FileMover , DBMover , ConcatMover , and CompareAfterMover . FileMover transfers files, DBMover copies database records, ConcatMover composes multiple movers, and CompareAfterMover runs a mover followed by a comparator to ensure consistency.

Implementations of Comparator include MD5Comparator , which compares MD5 hashes of source and destination files, and other hash‑based or record‑based comparators.

In Elixir, these interfaces are expressed as Protocols . For example:

defprotocol Mover do
  def move(mover, source, destination)
end

A concrete CompareAfterMover struct holds a mover and a comparator and implements the Mover protocol by delegating to the embedded components:

defmodule CompareAfterMover do
  defstruct [:mover, :comparator]
  def new(mover, comparator), do: %__MODULE__{mover: mover, comparator: comparator}
end

The composition of movers allows flexible runtime configuration: a fast but expensive FileMover can be paired with a cheap DBMover , or a popularity‑aware PopularityMover can be swapped in based on video demand.

This design yields several benefits: clear separation of concerns, easy replacement of components, runtime configurability, and straightforward unit testing of each mover/comparator. Drawbacks include increased conceptual complexity and the need for good documentation.

For Ruby developers, the talk highlights three takeaways: inject dependencies at object construction, prefer composition over inheritance, and apply interface‑driven design to both code and micro‑service boundaries. The same principles are used in TMPP to orchestrate controller, parsing, transcoding, packaging, and checking services.

Overall, the presentation demonstrates how Elixir’s protocol system and composable interfaces can simplify large‑scale media processing and provide patterns applicable to Ruby and other backend ecosystems.

microservicesbackend developmentRubyInterface DesignElixirFile Migration
Bitu Technology
Written by

Bitu Technology

Bitu Technology is the registered company of Tubi's China team. We are engineers passionate about leveraging advanced technology to improve lives, and we hope to use this channel to connect and advance together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.