Case studies / Automotive Technology

Volvo CQRS Framework: Cloud-Agnostic Business Framework

How we built a cloud-agnostic CQRS framework that enabled 40% faster development for a 22-person team building autonomous vehicle systems.

Client
Infosys (Volvo Project)
Industry
Automotive Technology
Duration
2 years (2018-2020)
Role
Principal Developer
Team
22 distributed developers

The Challenge

Volvo needed a next-generation autonomous vehicle management system that could:

  • Scale across cloud providers without vendor lock-in
  • Support distributed team of 22 developers across multiple locations
  • Enable rapid feature development for competitive advantage
  • Maintain high reliability for safety-critical automotive systems
  • Provide complete audit trails for regulatory compliance

Problems with Existing System

  • Monolithic architecture made changes slow and risky
  • Tightly coupled to Azure created vendor lock-in concerns
  • Difficult to test due to lack of clear boundaries
  • Slow development cycles as team size grew
  • Limited visibility into system behavior and state changes

Business Impact

  • Delayed feature releases affecting competitive position
  • High cloud costs due to inefficient architecture
  • Developer frustration with complex, brittle codebase
  • Risk of vendor lock-in limiting negotiation leverage

The Solution

I architected and developed a domain-driven CQRS (Command Query Responsibility Segregation) system with event sourcing and microservices architecture, designed to be fully cloud-agnostic.

Architecture Overview

graph TB
    subgraph "Client Layer"
        WEB[Web Applications]
        MOBILE[Mobile Apps]
        API_CLIENTS[API Clients]
    end

    subgraph "API Gateway"
        GATEWAY[API Gateway<br/>Authentication & Routing]
    end

    subgraph "Command Side (Write)"
        CMD_SVC[Command Services]
        CMD_HANDLER[Command Handlers]
        DOMAIN[Domain Models]
        EVENT_STORE[Event Store<br/>Immutable Log]
    end

    subgraph "Query Side (Read)"
        QUERY_SVC[Query Services]
        READ_MODELS[Read Models<br/>Optimized Views]
        QUERY_DB[(Query Database<br/>Materialized Views)]
    end

    subgraph "Event Processing"
        EVENT_BUS[Event Bus<br/>Cloud-Agnostic]
        PROJECTIONS[Projections<br/>Event Handlers]
    end

    subgraph "Cross-Cutting"
        TELEMETRY[Observability<br/>Metrics, Logs, Traces]
    end

    WEB --> GATEWAY
    MOBILE --> GATEWAY
    API_CLIENTS --> GATEWAY

    GATEWAY --> CMD_SVC
    GATEWAY --> QUERY_SVC

    CMD_SVC --> CMD_HANDLER
    CMD_HANDLER --> DOMAIN
    DOMAIN --> EVENT_STORE

    EVENT_STORE --> EVENT_BUS
    EVENT_BUS --> PROJECTIONS
    PROJECTIONS --> READ_MODELS
    READ_MODELS --> QUERY_DB

    QUERY_SVC --> QUERY_DB

    CMD_SVC -.-> TELEMETRY
    QUERY_SVC -.-> TELEMETRY
    EVENT_BUS -.-> TELEMETRY

    style EVENT_STORE fill:#d1ecf1
    style QUERY_DB fill:#d1ecf1
    style EVENT_BUS fill:#fff3cd
    style TELEMETRY fill:#d4edda

Cloud-Agnostic Design Pattern

graph LR
    subgraph "Application Layer"
        APP[Application Code<br/>.NET Core]
    end

    subgraph "Abstraction Layer"
        ISTORE[IEventStore]
        IMESSAGE[IMessageBus]
        ILOG[ILogger]
        IMETRICS[IMetrics]
    end

    subgraph "Cloud Implementations"
        AZURE[Azure Impl<br/>EventHub, Storage]
        AWS[AWS Impl<br/>Kinesis, S3]
        GCP[GCP Impl<br/>Pub/Sub, Storage]
        LOCAL[Local Impl<br/>In-Memory, File]
    end

    APP --> ISTORE
    APP --> IMESSAGE
    APP --> ILOG
    APP --> IMETRICS

    ISTORE -.->|Config| AZURE
    ISTORE -.->|Config| AWS
    ISTORE -.->|Config| GCP
    ISTORE -.->|Config| LOCAL

    IMESSAGE -.->|Config| AZURE
    IMESSAGE -.->|Config| AWS
    IMESSAGE -.->|Config| GCP

    style ISTORE fill:#fff3cd
    style IMESSAGE fill:#fff3cd
    style ILOG fill:#fff3cd
    style IMETRICS fill:#fff3cd

Event Sourcing Flow

sequenceDiagram
    participant Client
    participant API
    participant CommandHandler
    participant DomainModel
    participant EventStore
    participant EventBus
    participant Projection
    participant ReadDB

    Client->>API: POST /vehicles/update-location
    API->>CommandHandler: UpdateLocationCommand
    CommandHandler->>EventStore: Load Vehicle Events
    EventStore-->>CommandHandler: Event Stream
    CommandHandler->>DomainModel: Reconstitute from Events
    DomainModel->>DomainModel: Apply Business Rules
    DomainModel->>DomainModel: Create LocationUpdated Event
    DomainModel->>EventStore: Append Event
    EventStore->>EventBus: Publish Event
    EventBus->>Projection: LocationUpdated Event
    Projection->>ReadDB: Update Materialized View
    API-->>Client: 202 Accepted

    Note over EventStore: Immutable, append-only
    Note over Projection: Eventually consistent

Technology Stack

  • Core Framework: .NET Core, C#
  • Patterns: CQRS, Event Sourcing, Domain-Driven Design (DDD)
  • Architecture: Microservices, Cloud-Agnostic Abstractions
  • Event Storage: Custom implementation with Azure Storage / AWS S3 / GCP Storage
  • Messaging: Azure EventHub / AWS Kinesis / GCP Pub/Sub (abstracted)
  • Observability: Custom telemetry with pluggable backends
  • Testing: xUnit, Moq, Integration Tests with TestContainers

Implementation Highlights

Domain-Driven Design

  • Bounded Contexts: Clear separation between Vehicle Management, Route Planning, Maintenance Scheduling
  • Aggregates: Vehicle, Trip, MaintenanceRecord with strong consistency boundaries
  • Value Objects: Location, Speed, FuelLevel, VehicleStatus
  • Domain Events: VehicleRegistered, LocationUpdated, MaintenanceScheduled

CQRS Benefits

Write Side (Commands):

  • Optimized for transactional consistency
  • Business rule enforcement
  • Event generation for audit trail

Read Side (Queries):

  • Optimized for query performance
  • Denormalized views for specific use cases
  • Scalable independently from write side

Event Sourcing Advantages

  • Complete Audit Trail: Every state change captured
  • Time Travel: Reconstruct system state at any point
  • Event Replay: Rebuild read models from events
  • Debugging: Full visibility into what happened when
  • Compliance: Immutable log for regulatory requirements

Key Outcomes

Performance Improvements

graph LR
    A[Before: Monolith] -->|40% Faster| B[After: CQRS + ES]

    subgraph "Before"
        A1[6-8 weeks<br/>per feature]
        A2[High coupling<br/>Many conflicts]
        A3[Difficult testing<br/>Long CI/CD]
    end

    subgraph "After"
        B1[3-5 weeks<br/>per feature]
        B2[Clear boundaries<br/>Parallel work]
        B3[Fast tests<br/>Quick feedback]
    end

    A --- A1
    A --- A2
    A --- A3
    B --- B1
    B --- B2
    B --- B3

    style B fill:#d4edda
    style B1 fill:#d4edda
    style B2 fill:#d4edda
    style B3 fill:#d4edda

Measurable Results

Faster Development

40%

Team delivers new features in 3-5 weeks vs. 6-8 weeks previously

Developers Supported

22

Distributed team works efficiently with clear boundaries

Cloud Providers

3

Azure, AWS, GCP support without code changes

Event Auditability

100%

Complete history of every system state change

Business Value Delivered

  • Reduced time-to-market for new autonomous vehicle features
  • Eliminated vendor lock-in concerns with cloud-agnostic design
  • Improved team productivity through clear architectural boundaries
  • Enhanced system reliability with event-driven architecture
  • Regulatory compliance via comprehensive audit trails
  • Cost optimization through independent scaling of read/write operations

Technical Deep Dive

Code Example: Command Handler

public class UpdateVehicleLocationHandler : ICommandHandler<UpdateVehicleLocation>
{
    private readonly IEventStore _eventStore;
    private readonly IMetrics _metrics;

    public async Task Handle(UpdateVehicleLocation command)
    {
        using var timer = _metrics.Timer("command.update_location");

        // Load vehicle from event stream
        var events = await _eventStore.LoadEvents(command.VehicleId);
        var vehicle = Vehicle.FromEvents(events);

        // Execute domain logic
        vehicle.UpdateLocation(
            command.Latitude,
            command.Longitude,
            command.Timestamp
        );

        // Save new events
        await _eventStore.AppendEvents(
            command.VehicleId,
            vehicle.UncommittedEvents
        );
    }
}

Lessons Learned

What Worked Well:

  • Cloud-agnostic abstractions proved invaluable for flexibility
  • Event sourcing provided excellent debugging and audit capabilities
  • CQRS enabled independent scaling and optimization
  • Clear bounded contexts reduced merge conflicts

Challenges Overcome:

  • Learning curve: Team needed training on DDD and event sourcing patterns
  • Testing complexity: Required new testing strategies for event-driven systems
  • Eventual consistency: UI needed to handle async read model updates
  • Event versioning: Developed strategies for evolving events over time

Client Testimonial

"Raymond architected and developed our cloud-agnostic CQRS and event sourcing framework for autonomous vehicle management. The system supports our entire 22-person development team and has enabled us to build new features 40% faster. His deep understanding of domain-driven design and microservices architecture made him invaluable to our team."

— Principal Architect, Infosys (Volvo Project)