GM
EN/ES
Back to projects

Industrial Android application / Production

SpeedPrintLINK

Android application for custody transfer control at dispensing stations, with a local database, hardware integration and synchronization with the cloud platform.

Role: Maintenance, evolution, integration and testing Duration: 4+ years Speed Solutions 2021 — present

The problem

Custody transfer is the moment a volume of product changes hands, and measuring that moment has legal and commercial consequences. The person recording it stands on the floor, wired to hardware over proprietary protocols, and the site network is not always available. The application has to keep operating offline and reconcile afterwards without losing or duplicating a single operation.

SpeedPrintLINK ↔ SpeedFlowLink centralization Sequence diagram between the Android device and the cloud platform: structure registration, configuration download, offline operation and later reconciliation. Device ANDROID · LOCAL SQLITE Platform CLOUD · SQL SERVER Publishes its physical structure Returns identity within the system Requests configuration Returns current configuration Offline Operation continues against the local database . Nothing is lost and nothing is duplicated. Reconciles what was recorded once the network returns
SpeedPrintLINK ↔ SpeedFlowLink centralization

Constraints

  • Operations cannot stop because the network went down
  • A legacy codebase coexisting with a modern layer
  • Integration with hardware from different vendors and protocols
  • Field devices that cannot be updated on demand

Decisions

Chose Keep the legacy base and build new capabilities in modern layers alongside it
Instead of Rewriting the application from scratch
Because A rewrite would have frozen delivery for months on a product already in operation. Coexistence costs discipline, but it lets you keep shipping while modernizing in parts.
Chose Local database as the source of truth for operations, syncing to the cloud afterwards
Instead of Requiring a permanent connection to the API
Because On site, connectivity is intermittent. Making operations depend on the network is a requirement the business cannot meet.
Chose Explicit synchronization per flow — device structure, configuration, replacement — instead of a generic synchronizer
Instead of A single mechanism replicating tables
Because Each flow has different conflict rules. A generic replicator would have buried those rules where nobody reviews them.
Chose Dependency injection at defined composition points rather than scattered registrations
Instead of Registering services wherever needed
Because In a codebase with two architectures coexisting, composition points are the map that stops the new one from catching the old one's habits.

Outcome

  • Device structure registration to the cloud and configuration download
  • In-field device replacement with traceability of the change
  • Offline operation with later reconciliation
  • Real-time hardware status pushed to the web platform
  • Unit test coverage over the modern layers, plus tests on physical devices

The underlying problem

The application lives where three worlds meet that do not get along: hardware on proprietary protocols, an operation that allows no pauses, and a cloud platform that needs to receive everything that happened. The design is organised around that tension.

Centralization between the two products

The work I learned most from is the integration between this application and the cloud platform. It is not an endpoint — it is a set of flows with rules of their own.

  • Structure registration — the device publishes its physical configuration to the cloud, which recognises it and returns its identity within the system.
  • Configuration download — the platform is the authority on configuration; the application consumes it and applies it locally.
  • Device replacement — when equipment is swapped in the field, history must stay coherent. The device’s identity and its data’s identity are resolved separately.
  • Offline operation — what is recorded locally reconciles later, without duplicating or losing.

Each flow had to decide which side wins in a conflict. Writing it per flow, instead of building a generic synchronizer, keeps that decision visible in the code.

Two architectures coexisting

The codebase combines a legacy layer — static, with direct data access and managers — and a modern layer with dependency injection, MVVM and services. They coexist on purpose.

The rule I followed: new work goes in the modern layer, legacy is touched only when the requirement forces it, and no new layer adopts the old one’s patterns out of convenience. It is slower than rewriting, but the product never stopped delivering.

Why it belongs here

Because it describes the real work of maintaining software already in production: growing its capabilities, integrating it with another system, covering it with tests and sustaining it for years without the luxury of starting over.

The source code belongs to Speed Solutions. This case study describes architecture and decisions only — no source code, customer data or business figures.