Carlos Gude Sánchez

Carlos Gude Sánchez

Senior Backend Engineer & Software Architect

PHP · Symfony · Modernización de legacy · Integraciones con APIs · DDD / Hexagonal

Ubicación
Cambados (Pontevedra), España · CET
Disponibilidad
Abierto a puestos 100 % remotos
Email
carlos.sgude@gmail.com
GitHub
CarlosGude (se abre en una pestaña nueva)
LinkedIn
carlos-gude (se abre en una pestaña nueva)

Los mismos datos como CV legible o como el archivo JSON con el que se genera esta página. Abrir cv.es.json

Perfil

Senior Backend Engineer y Software Architect con más de 10 años construyendo y modernizando sistemas PHP/Symfony, incluidas plataformas distribuidas de alto volumen. Especializado en migrar sistemas legacy críticos sin interrupción del servicio, en hacer que los cambios sean seguros mediante tests y análisis estático integrados en CI, y en diseñar capas de integración con APIs externas. Experiencia en producción en logística, viajes, transporte público y SaaS para retail; autor del bundle open source IntegrationEngine.

Experiencia

  1. – Datcisions Senior Backend Engineer SaaS para retail

    SaaS de planificación de stock y compras para marcas de moda y retail. Encargo de duración definida centrado en la calidad y la modularización de la plataforma.

    • Subí PHPStan en la plataforma principal del nivel 5 al 9 y reduje la baseline de nivel 9 de 3.339 a 239 errores (−93 %).
    • Recuperé una suite de tests que ya no se ejecutaba y la amplié a más de 2.100 tests en verde.
    • Modularicé el monorepo en bundles de Symfony: separé IAM y el control de acceso de Security, repartí 127 migraciones entre módulos y eliminé 53.000 líneas de código muerto en el proceso.
    • Construí desde cero el conector con el ERP en la nube Holded y lo llevé a producción en 11 días, con PHPStan y PHP-CS-Fixer como puertas de calidad en CI.
    • Detecté y corregí dos vulnerabilidades IDOR en una revisión de seguridad por iniciativa propia.
  2. – PrimeIT Senior Backend Engineer Consultoría tecnológica

    Consultora tecnológica internacional.

    • Lideré la migración sin interrupción del servicio de un sistema legacy con más de 100 endpoints, de PHP 7.4 / Symfony 4 a PHP 8.3 / Symfony 6, usando agentes de programación con IA para los refactors mecánicos, con cada cambio validado por tests y análisis estático.
    • Reescribí la autenticación con el componente Security nativo de Symfony, eliminando las vulnerabilidades del modelo anterior.
  3. – Quadrant TravelTech Backend Engineer, Integrations Viajes

    A través de Interacso de mayo de 2023 a enero de 2024; después, contratado directamente por Quadrant.

    • Diseñé e implementé más de 5 integraciones de viajes, entre ellas Booking.com, Iberia, Lleego y Hostalia.
    • Construí una capa de integración multiproveedor en la que se podían añadir proveedores nuevos sin cambiar el core.
  4. – Auro Backend Engineer Logística

    Plataforma de logística de última milla.

    • Desarrollé e integré más de 10 APIs de partners externos para una plataforma de logística de última milla con seguimiento de envíos en tiempo real.
    • Diseñé la capa de eventos y mensajería que coordinaba varios transportistas y procesaba más de 300.000 mensajes por minuto para el posicionamiento de repartidores con alta concurrencia (RabbitMQ, SQS y Symfony Messenger, con consumidores idempotentes).
  5. – Jamenet Backend Engineer, project-based Transporte público

    Metro Bilbao.

    • Construí la integración Drupal–Symfony–Vue para Metro Bilbao, un sistema 24/7 que da servicio a tráfico real de pasajeros.
    • Implementé el procesamiento masivo en tiempo real de datos de líneas y horarios.

Experiencia anterior

  1. –

    Freelance · Plataforma de streaming en tiempo real

    Desarrollo integral en solitario de una plataforma tipo Twitch: chat en directo con WebSockets, streaming de vídeo con WebRTC, pagos con Stripe, PayPal y Redsys, economía virtual y moderación.

  2. –

    Syntelix · Backend Engineer

    Pipelines de ingesta en tiempo real y mensajería ordenada y sin pérdidas para telemetría marítima.

  3. –

    Card2Card · Full-stack Symfony Developer

    Único responsable técnico de una plataforma SaaS de e-commerce personalizable.

  4. –

    Freelance · Desarrollo web y backend PHP

    Más de 10 proyectos para pymes locales, agencias, e-commerce y clientes de turismo y hostelería.

Habilidades, idiomas y formación

Habilidades técnicas

  • Arquitectura

    Hexagonal · DDD · Clean Architecture · Event-Driven · CQRS

  • Backend

    PHP 8.x · Symfony 6 / 7 / 8 · API Platform · Doctrine · REST · Webhooks

  • Calidad

    TDD · PHPUnit · PHPStan · Infection · Deptrac · PHP-CS-Fixer · SonarQube

  • Infraestructura

    RabbitMQ · SQS · Docker · CI/CD con GitHub Actions · Linux

  • Bases de datos

    MySQL · PostgreSQL · Redis

  • Desarrollo asistido por IA

    Agentes de programación con IA para refactors, generación de tests, migraciones, revisión de código y documentación, con cada cambio validado por PHPStan max, Deptrac, mutation testing y revisión de código humana

Idiomas

Español
Nativo
Inglés
Competencia profesional

Formación

Técnico Superior en Administración de Sistemas Informáticos en Red –
Nivel 5 del Marco Europeo de Cualificaciones (EQF)
Autodidacta
PHP, Symfony y arquitectura de software, aprendidos de forma autodidacta. Formación continua en arquitectura, DDD y el ecosistema PHP/Symfony, aplicada en proyectos profesionales y open source.

Proyectos

IntegrationEngine

Bundle open source para Symfony · Autor y mantenedor

Una estructura común para construir y mantener integraciones con APIs externas en Symfony.

Requiere
PHP 8.2+ · Symfony 6.4 / 7 / 8
Licencia
MIT
  1. Action + Context
  2. IntegrationEngine
  3. API externa
  4. Mapper
  5. Response tipada
Por qué lo construí

Cada vez que integraba una API externa en Symfony, volvía a resolver piezas parecidas: autenticación, peticiones HTTP, mapeo de respuestas y gestión de errores. Además, cada integración tendía a organizarse con sus propias convenciones. IntegrationEngine nació de esa experiencia.

Cómo está organizado
  • Cada operación contra la API externa es una Action.
  • Un Mapper transforma la respuesta externa en un objeto Response tipado.
  • El bundle se encarga del flujo común: configuración, autenticación y transporte HTTP.
  • Cada integración conserva los detalles específicos de su proveedor.

Una forma de trabajar repetible —contratos claros y una estructura coherente— basada en problemas que me he encontrado en producción. Los proveedores siguen siendo distintos; el bundle da a esas diferencias un lugar predecible.

Ejemplo real: Obtener una película de TMDB Tomado de la aplicación de demo
  1. Declarar la operación

    Método, ruta y mapper de la action get_movie.

    src/Integrations/Tmdb/Tmdb.yaml
    get_movie:
      action: 'App\Integrations\Tmdb\GetMovie\GetMovieAction'
      method: GET
      path: /3/movie/{movie_id}
      mapper: 'App\Integrations\Tmdb\Mappers\GetMovieMapper'
  2. Llamarla desde la aplicación

    Una fachada pequeña mantiene el engine fuera de controladores y servicios.

    src/Integrations/Tmdb/TmdbIntegration.php
    public function getMovie(int $movieId): GetMovieResponse
    {
        $engine = $this->registry->get('tmdb');
        $context = DefaultActionContext::create(['movie_id' => $movieId]);
    
        $response = $engine->send('get_movie', $context);
        \assert($response instanceof GetMovieResponse);
    
        return $response;
    }
  3. TMDB responde con su propio modelo

    El fixture de test que usa la demo para esta llamada: 25 campos, la mayoría innecesarios para la aplicación.

    tests/Catalog/Infrastructure/Integrations/Tmdb/Fixtures/get-movie.json
    {
      "adult": false,
      "backdrop_path": "/fhvyh6G8M55gkTIPCbeFjvyAh4c.jpg",
      "belongs_to_collection": null,
      "budget": 250000000,
      "genres": [
        {
          "id": 28,
          "name": "Action"
        },
        {
          "id": 12,
          "name": "Adventure"
        }
      ],
      "homepage": "https://www.marvel.com/movies/avengers-endgame",
      "id": 299536,
      "imdb_id": "tt4154796",
      "original_language": "en",
      "original_title": "Avengers: Endgame",
      "overview": "After the devastating events that decimated the planet and wiped out half of all life, the Avengers assemble once more in order to reverse Thanos' actions and restore balance to the universe.",
      "popularity": 408.72,
      "poster_path": "/or06FN4Hf2tfsWASP2Oa6aSy0l1.jpg",
      "production_companies": [
        {
          "id": 420,
          "logo_path": "/hUzeosd33nzE5MCNsZxCGEKTW5l.png",
          "name": "Marvel Studios",
          "origin_country": "US"
        }
      ],
      "production_countries": [
        {
          "iso_3166_1": "US",
          "name": "United States of America"
        }
      ],
      "release_date": "2019-04-26",
      "revenue": 2798200000,
      "runtime": 181,
      "spoken_languages": [
        {
          "english_name": "English",
          "iso_639_1": "en",
          "name": "English"
        }
      ],
      "status": "Released",
      "tagline": "Part of the journey is the end.",
      "title": "Avengers: Endgame",
      "video": false,
      "vote_average": 8.3,
      "vote_count": 32000
    }
  4. El Mapper se queda con lo que usa la aplicación

    Los nombres de campo del proveedor se quedan aquí; el resto del código solo ve la respuesta tipada.

    src/Integrations/Tmdb/Mappers/GetMovieMapper.php
    protected static function transform(AbstractAction $action, array $response, array $headers): ResponseInterface
    {
        /** @var array{id: int, title: string, overview: string, poster_path: string, vote_average: float, release_date: string} $response */
        return new GetMovieResponse(
            id: $response['id'],
            title: $response['title'],
            overview: $response['overview'],
            posterPath: $response['poster_path'],
            voteAverage: $response['vote_average'],
            releaseDate: $response['release_date'],
        );
    }
  5. Respuesta tipada

    GetMovieResponse::toArray() para el fixture anterior.

    GetMovieResponse
    {
      "id": 299536,
      "title": "Avengers: Endgame",
      "overview": "After the devastating events that decimated the planet and wiped out half of all life, the Avengers assemble once more in order to reverse Thanos' actions and restore balance to the universe.",
      "poster_path": "/or06FN4Hf2tfsWASP2Oa6aSy0l1.jpg",
      "vote_average": 8.3,
      "release_date": "2019-04-26"
    }

Fuente: integrationEngine-demo/tree/main/src/Integrations/Tmdb (se abre en una pestaña nueva)

IntegrationEngine Demo

Aplicación Symfony · Autor

Aplicación de referencia ejecutable que usa el bundle contra APIs reales, incluidas peticiones concurrentes con una aceleración medida de 5–13× frente a las llamadas secuenciales.

Requiere
PHP 8.4+ · Symfony 7.4
Licencia
MIT
Qué cubre
  • REST · TMDB
  • GraphQL · Countries
  • CSV · Supplier
  • Peticiones form-encoded y webhooks firmados de Stripe
Notas de implementación
  • Cargas concurrentes con sendMany() y aislamiento de fallos parciales; aceleración medida de 5–13× para 20 cargas de películas concurrentes frente a la ejecución secuencial.
  • Bounded contexts y gateways aíslan las integraciones del código de negocio.
  • La CI exige tests, PHPStan max, PHP-CS-Fixer, Deptrac, validación de instalación en producción / Docker y mutation testing.

Contacto

Abierto a puestos 100 % remotos de Senior Backend Engineer y Software Architect.