Los triggers, son una funcionalidad ampliamente utilizada, pero que a medida que avanza el proyecto y se afianza, su uso desordenado provoca situaciones inadvertidas o efectos laterales indeseados, con frustración por parte del desarrollador y del usuario.
En este artículo quiero explicar, cuales son las problemáticas habituales, cuando aparecen, y las best practices y frameworks que se han desarrollado para mitigarlas.
Veamos pues, como crear Triggers vitaminados y super-mineralizados.
Esta serie está formada por los siguientes artículos:
-
- Un Patrón Simple pero Potente: Análisis del patrón de Gestión de Triggers de Tony Scott, que introduce las mejores prácticas que todos los frameworks deberían establecer, y que fue publicado en la web Force.com Cookbook.
- El Framework de Appleman que los inició a todos: Análisis del Framework que publicó Dan Appleman en su libro Advanced Apex, y que es la referencia para muchos frameworks que aparecieron posteriormente.
- El Framework de Hari Krishman, que evolucionó los conceptos de los 2 anteriores, y propuso una implementación mejorada de gran calidad.
¿Por qué necesitamos Frameworks?
Los triggers son una herramienta fantástica en Salesforce, pero tienen varias problemáticas asociadas.

- Orden no garantizado: varios desarrolladores pueden escribir una misma variante de trigger sobre un objeto, y Salesforce no garantiza el orden de su ejecución.
- Esto provoca, no asegurar como se realizará la ejecución y por tanto su resultado final.
- Tampoco permite, crear Tests fidedignos con resultados idempotentes.
- Incluso, podemos encontrar problemas en el entorno de Producción que nunca antes descubrimos en los entornos previos, es decir, dado que no podemos garantizar el orden y al pasar al entorno de producción puede haber cambiado.
- Recursividad incontrolada: el uso de triggers, conjuntamente con Workflows, Procesos con Builder etc., crea un escenario tal que:
- ¿Cómo cooperará un nuevo trigger que creamos, con el resto de mecanismos existentes y que yo desconozco?
- Cuando me haya ido del proyecto, ¿cómo podrán mis compañeros desarrolladores y administradores incorporar nuevas funcionalidades sin interferir en mis triggers?
- El máximo exponente de este problema, es la recursividad de actualizaciones DML: ejecuto un trigger que realiza una operación DML, que provoca la ejecución de otro trigger, que a su vez, provoca la ejecución de una Workflow Update, que provoca la ejecución nuevamente de mi trigger. Y se acaba de liar, porque los resultados son totalmente impredecibles, y lo peor de todo, yo no sé como ha pasado todo esto.
- Superación de límites inadvertidamente: el escenario descrito en el punto 2, se ejecuta dentro del mismo contexto de ejecución, lo que dependiendo del número de operaciones DML ejecutadas, puede provocar superar los límites, cuando inicialmente mi trigger, solo realizaba un número muy acotado de operaciones.
- Comprensión del entorno y refactoring complejo: refactorizar o cambiar la funcionalidad de nuestro trigger puede ser trivial, pero:
- ¿qué pasa en un escenario donde son varios los desarrolladores que están trabajando, cada uno con su funcionalidad pero que estamos trabajando con los mismos objetos?
- Y ¿qué pasa con los triggers, que otros compañeros programaron y que ya no están en el proyecto? ¿Y también con administradores o usuarios avanzados que modifican WFs o Procesos mientras yo estoy desarrollando?
- Cualquier cambio parece complejo y provoca incertidumbre.
- En el caso, de desarrollar Packages, es imposible saber a priori, que existirá en la ORG destino, con lo que aún es más impredecible.
- In-habilitación dinámica de un trigger con errores: si tenemos el infortunio de llegar al entorno productivo con un trigger con Bugs, ¿cómo podemos interrumpir la deshabilitar ese trigger problemático y así darnos margen a corregirlo mientras los usuarios siguen trabajando?
…vale, pero que me ofrecerán
Los diversos frameworks existentes, tienen unos principios/objetivos que se centran en minimizar las debilidades comentadas y además en proporcionar nuevas capacidades.
A continuación, enumero estos principios y objetivos que persiguen todos los frameworks:
- Crear un único trigger por objeto y evitar duplicidades
- Crear el trigger sin código, externalizando todo su código en clases externas
- Controlar el orden de ejecución
- Centralizar el enrutamiento de la ejecución en función de los eventos
- Detección la recursividad / Control de re-entradas
- Activar/Desactivar un trigger en caliente en cualquier entorno
- Crear una estructura de código que facilite un entorno multi-programador
Frameworks analizados
Han ido apareciendo propuestas e ideas sobre frameworks, que a cada uno de nosotros nos puede aportar cierto valor.
Es por ello que voy a centrarme en el análisis de las ideas expuestas en los frameworks, que más influencia tienen y cómo han ido aportando nuevas ideas y mejorando las de sus predecesores.
Los frameworks en los que me me basaré son:
- El artículo de Kevin O’hara en la Salesforce Developer Technical Library que servirá para establecer los conceptos básicos para un Framework de Triggers
- Trigger Architecture por Dan Appleman en su libro Advanced Apex Programming
- La propuesta de Hari Krishnan sobre una arquitectura de Triggers, que aglutina las ideas de las 2 propuestas anteriores más ideas procedentes de Tony Scott
- Finalmente, la propuesta de Sirono de la mano de Scott Wells (creador de Illuminated Cloud)

Principios básicos de un Framework para Triggers
Los principios básicos que la mayoría de desarrolladores y por supuesto los frameworks aplican son los 3 siguientes.
Un trigger por objeto
Desarrollar un único trigger por objeto. Como sabemos, desarrollar varios triggers para un mismo objeto, provoca, desconocer cual será el orden de ejecución, y por tanto desconocer como será la ejecución a cada invocación. ya que Salesforce no garantiza ningún orden.
Por ello y como principio súper básico, debemos centralizar en un único trigger, todas las posibles acciones, y no repetir su creación:

Pero pero pero, en ningún caso hay que dejar esta implementación así.
Si la dejamos así, cuando, por ejemplo realizamos una migración masiva de datos, esta se verá penalizada, incluso usando la BULK API, porque el trigger estará activo en cada operación que realicemos sobre el objeto. Es por eso que deberemos implementar un mecanismo de desactivación de triggers.
Trigger sin cuerpo, externalizando todo el código Apex en clases externas
Otro principio básico es extraer todo el cuerpo Apex de nuestro trigger hacia clases externas. Esto posee varios beneficios inmediatos:
- Mientras que varios desarrolladores pueden trabajar en distintas clases con un tasa de colisión baja, varios desarrolladores trabajando en un único trigger, requerirá de operaciones de Merge y seguramente provocará pérdidas de código y tiempo.
- Si exponemos la funcionalidad en clases externas, las podemos exponer para ser consumidas en nuestros Tests, mientras que si tenemos el código en un Trigger, este se vuelve complejo de testear.
- Como principio de orientación a objetos, exponer funcionalidad en clases, nos permite su reutilización, mientras que dejarla en el Trigger lo dificulta.
Añadir Handlers específicos por acción
Aunque inicialmente, necesitamos únicamente implementar una única operación, por ejemplo responder a un update, la generación de un esqueleto completo de operaciones, nos permite no modificar el código del trigger a posteriori, cuando aparezcan nuevas operaciones, y únicamente crear la nueva funcionalidad.
Para los desarrolladores noveles, este enfoque puede parecer un sobre-esfuerzo, y admito que así es, pero a medida que el proyecto va creciendo, obtendremos el beneficio y el sobre-esfuerzo habrá valido la pena.
De hecho, veremos que seguir avanzando en esta idea, nos comportará crear interfaces y/o clases específicas que ampliarán este concepto proporcionándonos más capacidades y más versatilidad de gestión.
Aplicando los 2 conceptos anteriores, podemos implementar un esqueleto de un trigger como sigue (lo mejoraremos muchísimo, pero para mostrar las ideas creo que es ilustrativo):

Conclusiones
A estas alturas hemos solucionado 2 de las problemáticas que habíamos detectado, y realmente casi no hemos arañado la superficie de lo que llegaremos a conseguir mediante la ideas que implementan los autores de los frameworks mencionados.
Espero haber suscitado tu interés por la mejora del diseño e implementación de tus triggers, y prometo ampliarlo de manera creciente en la siguiente entrada, en la que analizaremos el Framework de Tony Scott.
Enlaces Interesantes
- Apex Code Best Practices – Salesforce Documentation by Andrew Albert
- Trigger Frameworks and Apex Trigger Best Practices – By Kevin O’Hara
- Trigger Best Practices Discussion Forum
- Avoid Recursive Trigger Calls – Salesforce Knowledge
- Apex Trigger Framework – By Dan Appleman
- Trigger Pattern for Tidy, Streamlined, Bulkified Triggers Revisited – By Tony Scott
- An architecture framework to handle triggers in the Force.com platform – By Hari Krishnan
- Trigger handler framework – By Scott Wells on Sirono
- Centralized Trigger Framework – By Scott Covert