GoLang to Kotlin Migration for a Medical Device Integration Plugin
- 3 Device adapters migrated
- 3 Milestones, formally accepted
- 70%+ Baseline coverage per module
- 30 days Validated parallel run
Introduction
A European medtech company that develops clinical-grade cardiac and physiological monitoring solutions relied on a locally installed plugin, written in GoLang, to bridge medical hardware and its browser-based clinical web applications. The plugin handles device communication, local data caching and secure upload to cloud storage.
The client decided to move the plugin to Kotlin without interrupting the clinical workflows that depend on it. The objective was clear: migrate three device adapters and the common plugin infrastructure to a production-ready Kotlin Multiplatform codebase, preserving identical business logic, data contracts and clinical behavior, and retire the Go service only once parity was proven.
The Challenge
Migrating a Live Clinical Device Bridge Without Disruption
-
Preserving Clinical Behavior Across a Language Change
The plugin sits between medical hardware and clinical applications, so the migration could not change what the software does. Challenges included:
- Reproducing business logic, data contracts and clinical behavior exactly, in a different language
- Translating Go’s concurrency model, goroutines and channels, into Kotlin without changing runtime behavior
- Keeping the WebSocket contract with the browser application and the cloud storage interface unchanged
- Making sure device data cached locally is neither lost nor altered before upload
- Avoiding a big-bang cutover on software that clinicians depend on
-
Three Devices, Three Integration Paths
Each supported device talks to the plugin differently, and each brought its own constraints. Key obstacles:
- A Holter recorder integrated over the USB mass storage protocol (medium-high complexity)
- A high-fidelity ECG monitor reachable only through a third-party, Windows-only DLL, requiring JNI bindings from Kotlin and a DLL the client neither owns nor modifies (high complexity)
- A blood pressure monitor with no emulator, so validation depended on client-supplied hardware (very high complexity)
- Supporting Windows, macOS and Linux for the common plugin while accepting a Windows-only constraint for the DLL adapter
-
Proving Equivalence Before Retiring the Go Service
Retiring working software is only safe when equivalence is demonstrated. Challenges included:
- Establishing a baseline: a dependency map and test coverage for the Go code, with a target of at least 70% per device module
- Comparing Go and Kotlin outputs on the same de-identified clinical datasets against acceptance thresholds agreed for each device’s clinical algorithms
- Validating without patient testing, using emulators, mock cloud services and datasets
- Coordinating dependencies on client inputs: repository access, emulators, protocol specifications, hardware and a technical point of contact
Our Solution: A Staged, Parity-Proven Migration Framework
Nalashaa implemented a client-aligned migration approach built on the Strangler Fig pattern: the Go and Kotlin services run in parallel, device by device, and the Go service is retired only after the Kotlin version is fully validated.
The solution allowed the client to:
- Keep the existing Go plugin running while each Kotlin adapter was built and proven
- Move device by device, following one repeatable path: Identify, Translate, Integrate, Validate, Retire
- Leave the browser application and the cloud storage service untouched
- Retire Go only after a 30-day validated parallel run and formal sign-off
- Address audit, conversion, validation and cutover in a single, cohesive engagement
This approach ensured the migration progressed at a pace fully controlled by the client. We delivered the migration as three tasks, each closed by a milestone acceptance review.
-
Foundation & Common Plugin Infrastructure
SOLUTION HIGHLIGHTS
- Audited and inventoried the Go repositories, producing a dependency map and a baseline test coverage report
- Initialized a Kotlin Multiplatform monorepo with a Gradle version catalog
- Built an idiomatic Go-to-Kotlin conversion framework (rules below)
- Built an automated parity test harness that feeds the same dataset to the Go service and the Kotlin module and diffs the outputs
- Migrated the common plugin functionality: the WebSocket layer between browser and plugin, persistent local caching before upload, secure cloud upload, and device listing and command dispatch
TECHNICAL ENHANCEMENTS
- Ktor, with WebSocket support, replacing Go HTTP handlers
- Coroutines and Flow replacing goroutines and channels
- Koin for dependency injection
- Sealed classes for structured error handling
Conversion rules applied throughout: GO CONSTRUCT KOTLIN EQUIVALENT Structs Data classes Goroutines Coroutines Channels Kotlin Flow Interfaces Interfaces Error handling Sealed classes HTTP handlers Ktor route handlers Go dependencies Kotlin libraries -
Mass Storage and DLL/JNI Device Adapters
SOLUTION HIGHLIGHTS
- Migrated the Holter recorder adapter, which communicates over the USB mass storage protocol, and validated it against an emulator
- Built the high-fidelity ECG adapter in Kotlin with JNI bindings to the vendor’s third-party DLL, delivered as a Windows-only component
- Used a DLL emulator that replicates the vendor DLL’s behaviour, so the adapter could be tested without the physical device
- Followed Identify, Translate, Integrate, Validate, Retire for each device, moving device traffic from the Go service to the Kotlin service
- Produced a parity report for each adapter and a parallel operation validation report
TECHNICAL ENHANCEMENTS
- Serial protocol handling for retrieving device serial numbers and settings
- The Windows-only constraint contained within the ECG adapter, leaving the common plugin cross-platform
Migration rule in practice: each adapter is retired from Go only once its Kotlin counterpart matches the Go output on the same dataset within the thresholds agreed for that device.
Outcome: Both adapters were shown to match their Go predecessors on the same datasets and emulators, giving the client evidence rather than assurance.
-
Hardware-Interface Adapter, UAT & Go Retirement
SOLUTION HIGHLIGHTS
- Migrated the blood pressure monitor adapter, using client-supplied hardware for hardware-in-the-loop testing because no emulator exists
- Ran end-to-end testing across all three devices: development testing, technical validation, code comparison with the legacy plugin and QA output comparison on emulators, followed by the client’s own user acceptance testing in their environment
- Ran a 30-day validated parallel run, with the Go and Kotlin services operating on the same database
- Retired the Go module on completion of the run and client sign-off
- Delivered release readiness documentation and a deployment handover package
BUSINESS ENABLEMENT
- A single Kotlin Multiplatform codebase that the client’s engineers can extend
- The common plugin and two of the three adapters available on Windows, macOS and Linux
- A repeatable adapter pattern for future devices, with knowledge transfer at handover
- Formal offboarding, with documentation and access revocation at close
Together, the three tasks moved the plugin from Go to Kotlin one validated step at a time (Figure 1).
Architecture & Governance
From the client’s standpoint, the architecture delivered (Figure 2):
-
The plugin stayed a locally installed bridge, with no cloud or container hosting introduced
-
Interfaces to the browser application and the cloud storage endpoint left unchanged
-
One adapter per device, so each device’s protocol, emulator and platform constraints stay isolated
-
A parity harness and a parallel run that made every cutover decision evidence-based
-
Coexistence: Go and Kotlin running side by side on the same database until sign-off
This architecture enabled migration without sacrificing reliability.
Technology and Controls
CORE TECHNOLOGIES
- Kotlin (Kotlin Multiplatform) with a Gradle version catalog
- Ktor for HTTP and WebSocket communication
- Kotlin Coroutines and Flow for concurrency and streaming
- Koin for dependency injection
- JNI bindings to a third-party DLL (Windows-only)
- USB mass storage and serial protocol handling
- GitHub, with Jira or GitHub Issues for task tracking
OPERATIONAL CONTROLS
- Entry gate: Go dependency map and baseline test coverage of at least 70% per device module
- Automated parity comparison against thresholds agreed for each device’s clinical algorithms
- Validation on de-identified datasets, emulators and mock services, with no patient testing
- Weekly status calls, ad-hoc technical calls and formal milestone acceptance meetings
- Written change control: any scope change handled through a formal change order
- Formal offboarding with knowledge transfer and access revocation
Business Impact & ROI
Quantifiable Outcomes
Measured against the engagement’s own yardsticks:
-
3
Device adapters migrated and validated against their Go predecessors
-
3
Milestones, each closed by a formal acceptance review
-
70%+
Go baseline test coverage per device module, set as the entry gate
-
30 days
Validated parallel run completed before the Go module was retired
-
Retired
Go module retirement confirmed, with the browser application and cloud endpoint left unchanged
Strategic Value Delivered
This initiative demonstrates how a production device-integration layer can change language safely, without a big-bang rewrite.
By combining a Strangler Fig rollout, an automated parity harness and device-by-device adapter migration, the client now benefits from:
- A modern, maintainable Kotlin Multiplatform codebase
- Proven clinical equivalence with the legacy plugin
- Cross-platform reach wherever the devices allow it
- A repeatable pattern for migrating and adding adapters
- Lower long-term technical risk
Looking Ahead
With the Kotlin foundation in place, the organization is now positioned to:
- Add self-update capability, deferred to a later phase
- Add diagnostic and telemetry functionality, likewise deferred
- Onboard new device adapters using the established pattern
- Extend platform support as its device portfolio evolves
- Modernize incrementally without business disruption