From Java to Go: Kicking Off the Insurance Hub Transformation

After years spent mastering Go through books, hands-on exercises, and migrating my Campsite Booking API from Java, I’m setting out on my most ambitious project yet: transforming a Java-based insurance system into a modern, cloud-native Go application. This post marks the start of a comprehensive migration journey—one that will dive into every aspect of system modernization, from architecture redesign to deployment strategy.

Unlike my previous Go learning projects, which began as greenfield efforts, this undertaking tackles the real-world complexity of migrating an existing Java microservices system. In this inaugural post, I’ll share my motivation for making the shift, offer an in-depth analysis of the original Java-based architecture, and outline the cloud-native design I’m aiming for. Join me as I explore the challenges and discoveries at every stage of this transformation.

Raison d’Être or What’s My Motivation

As a professional Java developer, I believe real growth comes from stepping outside your comfort zone. Learning another JVM language like Kotlin or Scala—even though both have their strengths—doesn’t truly stretch your perspective the way learning Go does. Go exposes you to fresh paradigms and new approaches to problem solving, thanks to its minimal syntax, explicitness, and unique concurrency model. Its clear standard library and philosophy of “no hidden magic” push me to rethink how I structure code and systems. What’s more, Go was engineered for cloud-native development and microservices—an architectural approach that has already become the standard across our industry—so adding it to my toolkit directly expands both my technical ability and my readiness for today’s challenges.

This leap is about much more than a line on my résumé. Immersing myself in Go means grappling with unfamiliar idioms, evolving my approach to system design, and adapting to today’s fast-paced, polyglot teams. It positions me to contribute more effectively in modern cloud environments and to tackle both legacy migrations and new projects with greater confidence. By embracing Go, I’m not just diversifying my skill set—I’m preparing deliberately for the future of software development and expanding how I create robust, scalable solutions.

Why Insurance Hub?

Before turning my sights to Go, I briefly explored Python, but my progress never went beyond basic syntax and a few HackerRank challenges. With Go, I decided to take a different approach: no dabbling, no shortcuts—just a deep commitment to mastering its ecosystem, tools, design patterns, and the realities of building distributed, cloud-native systems. My goal was simple: if I ever switched to a Go developer role, I’d be productive and ready from day one.

Mastering a new language—especially while balancing a full-time Java job—is a gradual process that demands patience and steady focus. My Go journey began in 2022 with Jon Bodner’s “Learning Go,” cemented through practice on Exercism’s Go track. In 2023, I stepped up to Travis Jeffery’s “Distributed Services with Go Workshop,” which was not just a lesson in Go but a deep dive into distributed systems. I made it a point to follow every chapter hands-on, maintaining a working fork of the source code and tackling “Elements of Programming Interviews” to broaden my grasp.

In 2024, I dug into “Event-Driven Architecture In Golang” by Michael Stack—one of the best resources I’ve found for event-driven, cloud-native systems in Go. Again, I worked methodically through the code, regularly updating my repository as I refined my knowledge and adapted to Go’s evolving patterns.

That same year, I reached a new milestone: migrating my “Campsite Booking API” project from Java to Go. I’d previously detailed the original Java code on my blog, so this new migration was inspired by the Mallbots example from Michael Stack’s book, borrowing its architecture and best practices as I rebuilt in Go. The challenge stretched over many months but resulted in a fully functional Go-based microservice—a major step forward, now public as the campsite-booking-go repository.

To keep sharpening my skills, I explored more titles— “Test-driven Development in Go” by Adelina Simion, “Efficient Go” by Bartłomiej Płotka, “Functional Programming in Go” by Dylan Meeus, and “Ultimate Go Notebook” by William Kennedy with Hoanh An. Each added a fresh perspective and deepened my toolkit as I moved forward.

When I was ready for a new challenge, I wanted a project with real-world complexity: not a blank slate, but something like the Mallbots app, drawn from an existing codebase. That led me to “Micronaut Microservices POC,” a simplified Java-based insurance sales system, designed around distributed microservices. The project was a perfect fit, aligning with my insurance industry experience and offering the right architecture for a meaningful migration experiment. Reimagining and rebuilding this system in Go—now “Insurance Hub” in my GitHub—lets me grow my Go skills and practice the full spectrum of system modernization: migration, architecture, Kubernetes deployment, CI/CD, testing, and more.

This journey is truly a “dual-learning project”—blending technical growth with hands-on modernization. Having ported the code and mapped out my migration plan, I’m excited to share every useful lesson ahead. Let’s get started!

System Analysis Deep Dive

Disclaimer: All subsequent analysis and migration decisions are made with these assumptions in mind:

  • Though the original Java project was a proof of concept, I treat it as a production-ready system, maintained in a non-cloud-native environment. This approach better simulates real-world learning.
  • As in most real-world scenarios, a complete greenfield rewrite isn’t feasible. The system can’t simply be discarded and rebuilt from scratch. Instead, a phased migration strategy is the only way to ensure business continuity and reduce risk.

A Tale of Two Architectures

Understanding the “why” behind this migration starts with comparing where I began and where I’m headed. Here’s a high-level look at the existing Java-based system versus the modern Go-based target. This “before and after” view highlights the key shifts in technology, deployment, and operations.

Current State

View diagram on www.plantuml.com

Java-based C4 System Container Diagram

Target State

View diagram on www.plantuml.com

Go-based C4 System Container Diagram

Aspect Before (Current State) After (Target State)
Language & Framework Java 14 with Micronaut framework Idiomatic Go, using the standard and proven lightweight libraries
Data Persistence PostgreSQL, MongoDB, Elasticsearch PostgreSQL with JSONB (replaces MongoDB), Elasticsearch retained
Interservice Communication RESTful HTTP APIs (sync), Kafka (async) Internal gRPC, REST at the edge, Kafka (async)
Deployment & Environment Non-cloud-native, Docker Compose for local dev, bespoke production Fully cloud-native, Kubernetes-first, 12-factor principles
Observability Basic distributed tracing with Zipkin, no centralized logging or full metrics Full-stack: OpenTelemetry tracing with Tempo, centralized logs with Loki, Prometheus metrics, Grafana dashboards and alerting
File & Artifact Storage Local filesystem for docs, statements, rules S3-compatible object storage (MinIO)
Legacy Integrations JSReports for PDFs, file-based tariff rules Replaced by Go libraries (chromedp) and in-memory Tarantool

Key Architectural Shifts

This transformation solves several significant concerns:

  • Operational Complexity: Reduces diverse technologies and touchpoints, focusing on manageable, standardized components.
  • Cloud-Native Alignment: Moves from traditional deployment to Kubernetes, enabling automated scaling, rolling updates, and best practices.
  • Simplified Data Governance: Unifies persistence, reducing complexity while maintaining flexibility via PostgreSQL JSONB.
  • Performance & Reliability: Embraces gRPC and Go concurrency, yielding faster, more efficient, and resilient systems.
  • Enhanced Developer Experience: Standardizes protocols and tooling, improving productivity and troubleshooting.

For deeper details, see the full System Overview and Migration Analysis.

Migration Strategy Overview

Migrating a real system isn’t about throwing out the old and starting from scratch—especially when business continuity is critical. The Insurance Hub follows a six-phase plan built on proven industry patterns to pace progress and manage risk. Each step builds on the last, ensuring both stability and learning at every stage.

Why a Phased, Safe Migration?

Rather than a risky “big bang” rewrite, this migration takes two safe, iterative paths:

  • Lift and Shift: Move the existing system (with as few changes as possible) into a modern platform like Kubernetes. This quickly delivers cloud-native benefits (scalability, resilience) without altering business logic, serving as a learning exercise and a safe first step.
  • Strangler Fig Pattern: Gradually replace parts of the system (service by service) with Go-based alternatives. The old and new systems run in parallel during transition; traffic is slowly redirected as confidence grows. This minimizes disruption, allows stepwise validation, and supports rapid rollback if issues appear.

The Six Phases at a Glance

Phase Summary
1. Foundational Infrastructure & Environment Migration (Lift and Shift) Move the live Java system and all its dependencies into Kubernetes, configuring external storage and using K8s-native service discovery. No code rewrites—just infrastructure changes to validate the new platform safely.
2. Foundational Observability with Shared Trace Storage Deploy a modern observability stack (Grafana, Tempo, Prometheus, Loki) alongside the legacy system. Zipkin trace data is preserved and made visible in the new stack—no code changes needed.
3. Data Store Consolidation Migrate all data to PostgreSQL, replacing MongoDB where needed (using JSONB for flexible data). Update relevant services to use the unified data layer and simplify persistence management.
4. Phased Service Migration to Go (Strangler Fig Pattern) One by one, rewrite Java services in Go, deploying them alongside the originals. Use observability tools to monitor, gradually cut over traffic, and safely retire each old service after validation.
5. Modernize Edge and Authentication Upgrade the gateway and authentication: replace the Java gateway with Envoy Proxy and adopt Keycloak for identity. Modern, robust security is achieved as older, fragile components are replaced.
6. Finalization, Automation, and Optimization Complete the transformation: fully retire all old services, automate deployments with GitOps, fine-tune resources, and document everything. The system is now modern, maintainable, and ready for continuous improvement.

By splitting the migration into well-defined, sequential phases, you ensure the system remains both operational and continuously improvable throughout the process. Each phase is an opportunity to test, learn, and refine your approach—without putting the business or the user experience at unnecessary risk.

Stay tuned: each phase will be explored in depth in upcoming posts, sharing technical lessons learned and real-world strategies for safe, sustainable system modernization.

Iterative Dev with GitHub Projects

Managing a migration of this scale means staying organized beyond just code. I use GitHub Projects —a flexible, deeply integrated tool for planning and progress tracking. I’ve put this to the test before, like in the forth major iteration of my Campsite Booking API, where it broke down the work and made milestones visible.

For the Insurance Hub, I chose a Kanban board. Kanban’s visual simplicity makes it perfect for a solo developer: focusing on the workflow—“To Do” to “Done”—without extra bureaucracy. To structure it for a six-phase migration, I introduced custom Phase labels for every task, and saved dedicated views for each migration step. This organization lets me zoom in on focused work or get a big-picture overview, helping me adjust priorities as needed.

It’s a light but powerful system for managing long-term, iterative work. Follow along on the (currently empty) Insurance Hub Migration Project on GitHub.

How AI Fits In

To boost my learning and productivity, I make strategic use of modern AI tools—with clear boundaries. My main goal is to master Go and its ecosystem, not to let AI write code for me or fall into the trap of “vibe-coding,” where agents produce all the output. Instead, I treat AI as an advanced research tool—a “Stack Overflow on steroids”—for questions, documentation, and best practices. I focus on writing the code myself.

Which AI Tools Am I Using?

  • JetBrains AI Pro (with AI Assistant & Junie):
    In IntelliJ IDEA with the Go plugin, JetBrains AI Pro offers contextual code suggestions, chat help, and in-editor research, leveraging LLMs from OpenAI, Google, and Anthropic (Claude). I use AI assistance for knowledge, and explanations that go far beyond just pure code snippets. The Junie AI Coding Agent joins in for complex refactoring, but my hands-on approach remains the priority.

  • Ollama Local Server (Small/Medium Models):
    For privacy and speed, I run Ollama locally, using models like Code Llama, Phi-3 Mini, or Mistral 7B. These give me instant help with Go syntax or concepts without any cloud risk.

  • Perplexity.ai (Free Tier):
    Perplexity synthesizes documentation, forums, and official sources into focused answers, perfect for deep-diving Go idioms or clarifying challenging topics—saving hours of scattered searching.

  • Grammarly (with Generative AI):
    Sound engineering involves effective communication, so I use Grammarly’s paid AI suite to review and enhance my technical writing.

I keep a transparent log of all AI interactions and learnings in this GitHub Gist, which serves as an open journal until I finish the migration and publish a dedicated post on my AI “adventures.”

Key takeaway:
AI is an accelerator, not a shortcut. By keeping the responsibility for writing and understanding code firmly in my hands, and using AI as a reference and research tool, I aim for both speed and depth in mastering Go and modern system design.

For a thoughtful look at the “vibe-coding” trend and its pitfalls, see this analysis.

Wrapping Up

The migration to Insurance Hub is more than just a technical change—it’s a hands-on opportunity to practice modern software craftsmanship. By stepping outside my Java comfort zone and embracing Go, cloud-native design, and a disciplined approach to AI, I’m focused on both personal growth and real architectural challenges. Each phase underscores the belief that steady, incremental change—coupled with open documentation and a willingness to experiment—leads to lasting progress.

Whether you’re a developer weighing a major stack change, a team wrestling with legacy modernization, or simply curious about continuous learning in practice, I hope these insights prove helpful and encouraging. Watch for future updates, where I’ll detail each phase, share lessons learned, and provide practical tools for your own projects. Your questions, feedback, and experiences are always welcome—let’s keep the conversation going!

Continue reading the series “Insurance Hub: The Way to Go”: