Article / Insight

Migrating an IoT Audit Engine from Scala (ZIO) to Java 21 + Spring Boot

Author: Published: Reading time: 10 min reading

Migrating an IoT audit engine from Scala/ZIO to Java 21 + Spring Boot using Strangler Fig, contract tests, and SRE guardrails without breaking production.

Context: why migrate (market fit, hiring signal, operational consistency)

This blog post is a follow-up to my previous article, Designing an Evidence-Based Audit Engine for IoT Security & Reliability, where I described the original Scala + ZIO design of the audit engine. In this post, I cover the migration from Scala + ZIO to Java 21 + Spring Boot.

The motivation for this migration is mainly for technology market fit. In Denmark, Scala is still relatively niche, while Java and C# dominated backend hiring and are the default choice in many companies. Migrating the audit engine to Java improves:

  • Hiring signal (aligns with mainstream backend stacks)
  • Operational consistency (standard tooling, libraries and familiarity in teams)
  • Maintainability (lower barrier for contributors and future maintainers)

My Java and Scala background

My Java experience goes back more than a decade, across both professional and academic projects, before I later leaned into Scala for distributed systems and functional programming.

2013–2016: Early Java projects (OOP foundations)

During my first computer science degree, I focused heavily on object-oriented programming in Java and built several end-to-end projects, including:

  • A beehive owner management system
  • A flight route planner system

2018–2020: Java backend + distributed systems foundations (BSc CS)

During my bachelor’s in computer science, I worked with more advanced backend concepts and Java for production environments:

  • Spring Boot and scalable service platform patterns (REST APIs, integration patterns, microservices, and container deployments with docker and kubernetes)
  • A Java + Spring Boot + Apache Kafka bachelor project for anomaly detection on vehicle sensor data

2020–2022: Java security + advanced streaming with Kafka (MSc)

During my master’s, I used Java across security, backend development, and systems projects:

  • A file encryption application using Java Bouncy Castle
  • A Spring Boot application related to digital misinformation
  • A Virtual Power Plant prototype for my master’s thesis using Kafka for streaming weather, energy and market data.

Transition to Scala: Akka → data platforms → FP (post MSc)

During my master’s thesis, I began transitioning from Java to Scala, initially to leverage the actor model and the Akka ecosystem. After graduating, I worked full-time with Scala in data engineering:

  • Scala in a data lake context (e.g., Spark, Hadoop ecosystem)
  • Self study for deeper focus on functional programming with Cats and ZIO (including courses from Rock the JVM)

Transition back to wider Java ecosystem

The motivation is not to learn Java from scratch. It’s to bring production-grade Scala + ZIO design into a Java + Spring Boot ecosystem, while keeping the same discipline around reliability, operability, and safe change.

Principle: treat migration as a reliability project

A migration isn’t just rewriting code in another language. It changes the system’s failure modes: configuration, threading and concurrency, timeouts, serialization, database drivers/pooling, dependency injection, deployments and observability defaults. When the business behavior is intended to be the same, the operational behavior often doesn’t stay the same.

That’s why I treat a migration as a reliability project as the first main focus and code translation second.

I’m heavily inspired by Working Effectively with Legacy Code1, especially the idea of making safety nets before making significant changes. My approach is:

  • Refactor before migrating to reduce complexity a bit in my Scala code base, and add tests for contracts.
  • Migrate incrementally using Strangler Fig pattern2 (move one slice at a time), contract tests, and SRE guardrails without breaking production.
  • Refactor after migration once the new platform feels stable, remove temporary glue code and simplify the Java architecture.

The reason for refactor before and after is simple: this migration has a higher risk profile than a normal refactor. Moving from Scala + ZIO to Java + Spring Boot changes the runtime environment and this mean a set of things can break in production, often in ways unit tests won’t catch.

Next: Baseline & safety nets, then the first Java thin slice.

References

Footnotes

  1. Working Effectively With Legacy Code by Michael C. Feathers

  2. Strangler Fig pattern: https://martinfowler.com/bliki/StranglerFigApplication.html

Do you have a question about this article?

If you are considering technical consulting or need help improving your system, feel free to send a short message describing your solution and needs. You will receive a response the same business day with clear next steps.

Telefon: +45 22 39 34 91 or email: tb@tbcoding.dk.

Typical response time: same business day.