Saltar al contenido

Dealspotr · Demand.io/Profesional

Mantener productivo a Dealspotr

Cómo mejoré por etapas un producto legado en PHP y jQuery sin poner en riesgo su circuito de usuarios y afiliados.

Rol
Responsable técnico e implementador principal
Período
2024 - 2025

Un producto maduro que todavía generaba valor

Dealspotr era una comunidad de cupones. Sus páginas de comercios ayudaban a encontrar y usar promociones, y además sostenían buena parte de la monetización: revelaban códigos, registraban interacciones y visitas a los comercios, y mostraban ofertas que generaban comisiones.

Para ese momento, gran parte de la aplicación tenía casi ocho años. Estaba renderizada principalmente en el servidor con PHP, y jQuery se encargaba de las interacciones del lado del cliente. Años de decisiones de producto estaban incorporados en los templates, el estado compartido, el orden de las promociones y el comportamiento específico de cada tarjeta.

Lideré el trabajo para mantener este sistema útil y productivo. No intenté hacerlo pasar por software nuevo. Teníamos que entregar los cambios que pedía el negocio sin convertir cada pedido en otro parche que complicara al siguiente ingeniero.

Un control simple sobre años de supuestos

Agregar filtros y ordenamiento de promociones es un ejemplo representativo. El pedido parecía acotado: permitir que los compradores limitaran el feed a códigos de cupón, ofertas o promociones para todo el sitio, y luego lo ordenaran por Mejores, Más recientes o Usadas por última vez.

El feed no era una lista convencional. Mezclaba promociones comunes con ubicaciones preferenciales, códigos de revendedores y newsletters, ofertas no verificadas, promociones de competidores, financiación, liquidaciones, descuentos para audiencias específicas y anuncios propios. Esas tarjetas no compartían una única estructura de datos completa, y su posición afectaba el texto, la revelación, la votación, el modal, la analítica y el comportamiento de salida.

Un filtro del lado del cliente podía ocultar ofertas que debían verse, alterar el ranking definido por el servidor, duplicar el manejo de clics o romper la acción principal de una promoción.

Mapeo de las reglas invisibles

Antes de cambiar la interfaz, seguí todo el proceso, desde la preparación de promociones en el servidor hasta el renderizado de tarjetas y las interacciones con jQuery. El modelo de dominio estaba implícito. La vigencia, el tipo, la ubicación, la prioridad comercial y los fallbacks de una promoción se definían en distintas etapas, no en un único objeto.

Antes

base de datos y caché
  -> preparar grupos de promociones del comercio
  -> intercalar tarjetas y módulos comerciales
  -> renderizar distintas variantes de tarjetas
  -> asociar interacciones directas con jQuery

Después

base de datos y caché
  -> preparar un conjunto más amplio de candidatos
  -> preservar las reglas de ubicación existentes
  -> normalizar los metadatos de las tarjetas
  -> filtrar y ordenar en el navegador
  -> gestionar las interacciones mediante elementos padre estables

Esa investigación estableció tres reglas para el cambio:

  • El feed inicial debía conservar el comportamiento de ubicación y ranking seleccionado por el servidor.
  • Ambas familias de tarjetas debían seguir siendo la fuente de sus valores visibles y específicos de cada interacción.
  • Reordenar una tarjeta no podía cambiar el texto, la revelación, la votación, el modal, la analítica ni el comportamiento de salida.

Con una cobertura automatizada limitada para estas interacciones, la exposición por etapas, la analítica y el seguimiento en producción también debían formar parte del modelo de seguridad.

Creación de un punto de separación en lugar de otro parche

Un parche directo dentro de la página existente habría sido lo más rápido, pero habría profundizado el acoplamiento. Reemplazar el feed con un frontend moderno habría creado el problema opuesto: demasiado riesgo antes de entregar algún valor.

Elegí un camino intermedio. Extrajimos la densa grilla de promociones a un límite específico, preservando sus condiciones de ordenamiento y sus renderizadores de tarjetas existentes. El servidor siguió decidiendo qué ofertas existían y cómo se presentaban; jQuery mejoraba progresivamente el conjunto renderizado.

En el límite de las tarjetas, introduje un contrato de metadatos compartido para el tipo de promoción, el descuento, la fecha de creación, la fecha del último uso, el estado de alcance a todo el sitio y la vigencia. Esto le dio al navegador un único lenguaje coherente sin obligar a reescribir de inmediato cada fuente legada de promociones.

Mover tarjetas sin romper sus acciones

El filtrado seleccionaba y reordenaba elementos que ya estaban renderizados. Mover esas tarjetas expuso supuestos en los handlers directos de clic, así que los comportamientos clave pasaron a usar delegación de eventos mediante elementos padre estables.

La primera versión no resolvió todas las interacciones. El trabajo posterior corrigió la gestión de clics, el filtrado, los límites de visualización y el ranking predeterminado. Coordiné ese refuerzo con el equipo para que el estado intacto Todas + Mejores siguiera respetando el orden seleccionado por el servidor.

Ese trabajo posterior fue parte del cambio. Mantener un producto antiguo exige corregir lo que aparece en producción, no dar el trabajo por terminado con el primer merge.

De la exposición controlada al uso cotidiano

Los controles comenzaron detrás de cohortes ponderadas. Adjuntamos el contexto del experimento a la analítica, agregamos overrides para realizar pruebas reproducibles y aumentamos gradualmente la exposición antes de habilitar la experiencia para todo el público.

Así limitamos el posible daño inicial y pudimos observar el comportamiento mientras corregíamos nuestros supuestos. Esto no demuestra una mejora en la conversión. La disponibilidad general fue un resultado de entrega, no la prueba de que el experimento hubiera sido exitoso.

Un límite que siguió dando resultados

La extracción resultó útil más allá del filtrado. En 2025, reutilicé el mismo límite de renderizado para recopilar datos de promociones destinados a datos estructurados Offer y WebPage. Los valores existentes específicos de cada tarjeta podían alimentar una salida legible por máquinas sin crear otra interpretación independiente de cada promoción.

Apliqué el mismo principio incremental en la capa de infraestructura. Una allowlist selectiva de Nginx trasladó un grupo definido de rutas de comercios a SimplyCodes, mientras que el resto siguió pasando por Dealspotr. Después, el equipo alineó los enlaces internos y amplió la migración con el tiempo. Podíamos mover el tráfico deliberadamente sin exigir un reemplazo completo de una sola vez.

Mantener modificable a Dealspotr

Los compradores obtuvieron una forma disponible para todo el público de limitar y reordenar un feed mixto de promociones. El resultado a más largo plazo fue un conjunto de límites más claros alrededor de una de las áreas más complejas de la página:

  • La lógica de ubicación quedó aislada de la página principal del comercio.
  • Los distintos tipos de tarjetas compartían un contrato para el comportamiento del lado del cliente.
  • Las interacciones dinámicas dejaron de depender por completo de la ubicación inicial en el DOM.
  • Los datos estructurados podían reutilizar la información procesada de las promociones.
  • Parte del tráfico podía migrarse mientras la aplicación legada seguía en línea.

No conservo informes que respalden una afirmación cuantificada sobre ingresos, tráfico o SEO. El resultado defendible es más simple: un canal consolidado de usuarios y monetización siguió recibiendo trabajo de producto sin esperar una reescritura.

Deuda mantenida a propósito

El sistema siguió siendo PHP procedural y jQuery. El estado compartido, los registros legados inconsistentes, los fallbacks específicos de cada tarjeta y la cobertura automatizada limitada todavía hacían que los cambios fueran costosos. Algunos comportamientos en producción requirieron correcciones posteriores. Los datos estructurados y las redirecciones todavía necesitan una validación automatizada más completa.

Me detuve antes de hacer una limpieza general porque una refactorización no relacionada habría aumentado el riesgo sin mejorar el resultado inmediato. La siguiente inversión valiosa sería agregar cobertura de caracterización para combinaciones representativas de tarjetas y acciones críticas, y luego trasladar la normalización de promociones a un modelo explícito del lado del servidor.

Cuidado antes que reinvención

Liderar sistemas legados muchas veces implica resistir la reescritura que uno disfrutaría construir. Dealspotr era antiguo, pero todavía servía a los usuarios y sostenía al negocio. Su antigüedad hacía que entender y preservar su comportamiento fuera más importante, no menos.

Mi tarea fue descubrir reglas implícitas, aislar el cambio más pequeño que aportara valor, coordinar entregas graduales y corregir los supuestos que fallaban en producción. El sistema siguió siendo útil y resultó más fácil de modificar en las áreas que el negocio todavía usaba.

Tecnologías

  • PHP
  • jQuery
  • JavaScript
  • MySQL
  • Google Analytics
  • Nginx
  • Kubernetes
  • JSON-LD

Habilidades aplicadas

  • Modernización de sistemas legados
  • Gestión de riesgos
  • Entrega incremental
  • Analítica de producto
  • Liderazgo técnico
ProyectosTodos los casos de estudio

Más