Skip to content

UTM Refactor

Andi Lamprecht Andi Lamprecht ·· 4 min read· Draft
ADR-0245 · Author: Eric Gesell · Date: 2025-04-28 · Products: shared
Originally ADR-0114-UTM-Refactor (v8) · Source on Confluence ↗

UTM Refactor

Context

Per the recommended technology stack described by the Syntax Syndicate team, we are rewriting the UTM system in Go.

UTM has many features spread across several services.

image-20250409-212447.png

For the purposes of this ADR, we are concerned with those services written in Clojure

  • utm-themis-api - this service provides API endpoints to manage flight intents and get airspace info.
  • utm-themis-dss - Connects to Discovery Sync Service that allows anonymized information about other drones that are in close proximity to one of our flights.
  • utm-themis-altitude - Handles conversion of altitude between different reference frames.
  • utm-themis-grpc - Provides stream subscriptions for geospatial information, airspace info, and flight intents.
  • utm-themis-charger - Relays airspace data from Atlas into Themis

UTM Rewrite - Current Architecture.pngimage-20250410-172701.png

Decision

Refactor the UTM project into Go.

Create a Baseline

One way to mitigate some of the difficulties around a large rewrite like this is to implement a regression test suite that is first run against the existing implementation. Once those tests are passing, they can be used to test the new implementation to ensure that the API contract is maintained.

A minimal proxy could be an option to easily switch between the new and original services. In this scheme, the proxy can be configured by feature or endpoint depending on need. This will allow fine-grained control over the migration.

UTM Rewrite.png

Rewrite Strategies: Lift-and-shift vs Feature-byFeature

There are tradeoffs in the ways that we approach a rewrite. One strategy is to make an exact copy of the original functionality (lift-and-shift). This strategy seeks to maintain the existing API contract, including bugs and edge-cases. The advantage of lift-and-shift is that it has a minimal impact on API consumers.

An alternative is to focus on features instead of API contracts. This strategy will allow us to reorganize the code in way that makes the most sense for our current and future goals. We can relocate functionality into existing services or change API contracts to take advanatge of lessons learned since the original contracts were developed.

Since our API consumers are internal and both Uncrew and Atlas have expressed interest in changing how they interface with UTM the feature-by-feature strategy is preferred. There might be some cases where we preserve the original API contracts, so these strategies aren’t mutually exclusive.

What Do We Need to Migrate

  • FlightPlan managment(create, update, activate, close)

    • create
    • update
    • activate
    • close
  • Location API

  • Operational intents API

  • Operational intents stream updates

  • Airspace stream updates

  • Report API

  • Integration with uAvionix

  • Integration with InterUSS

  • Integration with RESILIENX

Atlas Integration

Atlas interfaces with UTM in several ways and it will be necessary to account for those integrations.

  • Airspace data is pushed to a PubSub topic that is consumed by utm-themis-charger.
  • Atlas provides a REST API for elevation data
  • utm-themis-charger could be rolled into the Atlas ecosystem to consolidate things like reference frame transformations.

During the refactor to GO we can re-consider the whole communication stack for geospatial data. Currently the geospatial data is stored in 4 places:

  • Atlas (main source of truth)
  • UTM Airspace API (replicated)
  • Uncrew Data Service
  • HubOps Airspace Service

This involves potentially unnecessary reads, writes as well as cache management within multiple software components for the same data. Also the data is being serialized/deserialized on each step which adds additional latency for the whole process.

Definition of Done

The rewrite will be done when we have removed all production Clojure code. This definition allows us to refactor as product requirements change instead of being tied to a direct replacement.

Consequences

What becomes easier or more difficult to do because of this change?

Refactoring into Go will make UTM more accessible to the rest of the engineering team and make it easier to integrate as we evolve our stack.

It will also fit into the CI/CD pipelines, static code analysis, and vulnerability management strategies that the rest of DroneUp uses, where as right now, there needs to be special considerations to support both Go and Clojure.

Any rewrite of this magnitude will take significant effort and has some potential downsides:

  • Moving target - if updates are made to the UTM system while the rewrite it taking place, then the new version must also be updated to account for the new behavior.
  • Functionality gap - the new system may not implement some features the same way, so there’s a risk of edge-cases causing subtle bugs or missing functionality.
  • Big-bang replacement - deploying the new service as a single piece could lead to a lot of issues as bugs that escaped testing and code-review are exposed to production conditions.

Alternatives Considered

The Syntax Syndicate work contains information about the tradeoffs of various languages for DroneUp and well as migration costs between different technologies. Those docs provide detail on the various alternatives considered.

Cited by queries

Last updated on