Trucos y consejos de Salesforce Apex (Parte 1)

Salesforce Jedi
7 min readJun 7, 2023

--

Vamos a hacer una serie de artículos orientados a divulgar trucos y consejor de programación en Apex. Esto trucos y consejos te ayudarán a mejorar tu código y a ahorrar mucho tiempo a la vez que simplificas tu código. Sin más dilación, vamos a ello.

1 Rellenar un mapa con una lista como valores

Este algoritmo es uno de mis preferidos. No es algo estándar de Salesforce, pero yo lo uso constantemente en mi código. El objetivo es rellenar un mapa con una clave a través de la cual podamos acceder a una lista de registros.

Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
List<Contact> tmpContactList = null;
for (Contact contactIterator : contactList) {
tmpContactList = contactsByAccount.get(contactIterator.AccountId);
if (tmpContactList == null) {
tmpContactList = new List<Contact>();
}
tmpContactList.add(contactIterator);
contactsByAccount.put(contact.AccountId, tmpContactList);
}

Hace uso de una de las características del tipo de dato Map para ir sobrescribiendo la lista de registros para determinada clave.

2 Crear un mapa a través de una lista de objetos

Si en vez una lista de valores como en el paso anterior, queremos acceder a todos los datos de un registro a través de su Id podemos hacer lo siguiente:

List<Account> accountList = [SELECT Name, Rating FROM Account LIMIT 10];
Map<Id, Account> accountsMap = new Map<Id, Account> (accountList);

Uno de los constructores de Map nos permite enviarle una lista de sObject y Salesforce automáticamente rellenará un mapa donde la clave sea el Id del registro.

Esto, personalmente, me parece algo imprescindible en nuestro kit de herramientas de desarrollador. Sobre todo en Salesforce que tenemos que trabajar constantemente con mapas.

3 Comprobar si una cadena es nula o está vacía

Estamos constantemente haciendo comprobaciones sobre cadenas de texto para comprobar que no sean nulas o que al menos tengan algún valor. Comparamos esa cadena para que no sea nula, llamamos al método trim() y comprobamos que tenga algún valor más allá de espacios en blanco.

En Salesforce podemos hacer todas esas comprobaciones con el método String.isEmpty() si sólo queremos comprobar que no sea nulo y con el método String.isBlank() si queremos comprobar que tenga algún valor más allá de espacios en blanco.

String str = ' ';
System.debug(String.isEmpty(str)); // false, no es nula
System.debug(String.isBlank(str)); // true, no es nula pero sólo tiene espacios

Esto te ahorrará mucho código y simplificará tus condiciones para que sean más legibles.

4 Reiniciar el contexto de una clase Test

Si nuestro código ya está rozando alguno de los límites de Salesforce, nos costará mucho crear pruebas unitarias para testearlo. Si en esas pruebas unitarias, a parte del propio código, tenemos que ejecutar la creación de datos antes y realizar las comprobaciones después, seguro que nos pasamos de algún límite.

Para ser más fidedigno y el código que estamos testeando en nuestra prueba unitaria consuma los límites que consumirá en una ejecución normal, tendremos que añadir una llamada al método Test.startTest() antes del código que estamos testeando y una llamada al método Test.stopTest() después de ese código.

// Este es un contexto, lo usamos para crear los datos necesarios en el test

Test.startTest();
// Otro contexto, donde se ejecutará la lógica que estamos testeando
Test.stopTest();

// Otro contesto, donde haremos las comprobaciones

Esto no sólo nos permite lidiar con los métodos tests y hace nuestra prueba más fidedigna en cuanto a los límites que consumirá en condiciones normales. También nos permite testear procesos asíncronos, ya que al llamar al método Test.stopTest() todos los procesos asíncronos que haya lanzado el código a testear terminarán y podremos ver el resultado de los mismos.

5 Recupera los Custom Metadata Types sin lanzar una query

Salesforce nos permite recuperar los registros de nuestros Custom Metadata Types y nuestras Custom Settings sin necesidad de consumir límites de la base de datos.

Veamos cómo traeríamos los datos de un Custom Metadata Type sin lanzar ninguna query:

// Traer todos los registros en forma de mapa, la clave será el nombre del registro
Map<String, MyCustomMetadata__mdt> metadataMap = MyCustomMetadata__mdt.getAll();

// Traer la lista de registro para iterar directamente
List<MyCustomMetadata__mdt> metadataList = MyCustomMetadata__mdt.getAll().values();

// Traer un registro en particular a través de su nombre
MyCustomMetadata__mdt singleMetadata = MyCustomMetadata__mdt.getInstance('Metadata Name');

De la misma manera, lo podemos hacer con las Custom Settings de esta manera:

// Traer todos los registros en forma de mapa, la clave será el nombre del registro
Map<String, MyCustomSetting__c> settingMap = MyCustomSetting__c.getAll();

// Traer la lista de registro para iterar directamente
List<MyCustomSetting__c> settingList = MyCustomSetting__c.getAll().values();

// Traer un registro en particular a través de su nombre
MyCustomSetting__c singleSetting = MyCustomSetting__c.getInstance('Metadata Name');

En el caso de las Custom Settings jerárquicas es ligeramente diferente:

// Traer el registro por defecto de la org, en las custom setting jerárquicas
MyCustomSetting__c defaultOrgSetting = MyCustomSetting__c.getOrgDefaults();

// Traer el registro que aplica a determinado perfil
List<Profile> profileTest = [SELECT Id FROM Profile WHERE Name = 'Sales Manager'];
MyCustomSetting__c userSetting = MyCustomSetting__c.getValues(profileTest[0].Id);

// Traer el registro que aplica a determinado usuario
List<User> userTest = [SELECT Id FROM User WHERE Username = 'test.salesforce@sfdcjedi.com'];
MyCustomSetting__c userSetting = MyCustomSetting__c.getValues(userTest[0].Id);

Está muy limitado a la hora de filtrar que registros nos queremos traer. O sabemos cómo se llama el registro del Custom Metadata Type o nos traemos todos los registros. Si nos traemos los datos con SOQL podemos hacer filtros complejos para traernos sólo la información imprescindible. Aunque de esa otra manera estaríamos consumiendo límites de la base de datos, tu elijes lo que mejor se adaptado a cada problema.

6 Recuperar los datos de un Record Type sin lanzar una query

De la misma manera que en el punto anterior, dentro de los datos que podemos obtener en Apex sin tener que lanzar una query, podemos traer el id de los Record Types de determinado objeto a través de su nombre o su DeveloperName.

Schema.SObjectType.Account.getRecordTypeInfosByName()
.get('B2B Customer').getRecordTypeId(); // A partir del nombre
Schema.SObjectType.Account.getRecordTypeInfosByDeveloperName()
.get('B2B_Customer').getRecordTypeId(); // A partir del DeveloperName

Yo siempre os recomendaría obtener el id del Record Type a través del DeveloperName. El nombre del Record Type puede cambiar dependiendo del idioma del usuario.

7 Instancia una lista o un mapa con valores

Muy sencillo y muy útil a veces. No siempre nos va a surgir la necesidad ya que normalmente las listas las rellenamos de manera dinámica. Pero si alguna vez necesitamos una lista estática (sabemos que siempre tendrá los mismos valores), podemos crearla en una sola línea y no escribir una sentencia para añadir cada uno de los valores.

Para instanciar una lista y asignarle ya valores, todo en la misma sentencia, haríamos algo así:

List<String> strList = new List<String> { 'firstValue', 'secondValue' };

Para un mapa la sintaxis sería algo así:

Map<String, Integer> priorityByRating = new Map<String, Integer> {
'Hot' => 1,
'Warm' => 2,
'Cold' => 3
};

8 Ordenar una lista

Un buen programador te dirá que debes conocer métodos de ordenamiento cómo Bubblesort, pero tu le puedes responder que programas en Apex y no lo necesitas. Dentro de los múltiples métodos que pone a nuestra disposición Salesforce en sus clases estándar, tenemos el método List.sort().

Este método nos permite ordenación básica de nuestras listas. Nos ordenará de manera diferente dependiendo del tipo de dato que contiene nuestra lista. Incluso nos permitirá ordenador listas de objetos.

List<String> strList = new List<String> { 'secondValue', 'firstValue' };
System.debug(strList.sort()); // Se mostrará 'firstValue' primero

9 Operador de navegación

Si vienes de otros lenguajes de programación, este operador te sonará. Es bastante común fuera de Salesforce, aunque en Salesforce hace no mucho que lo podemos utilizar.

Una de las estructuras de código que se repiten si parar es un if ternario que evalúa si una variable es nula antes de acceder a alguna de sus propiedades, así evitamos punteros nulos.

String ternaryIf = (myVariable != null) ? myVariable.MyCustomField__c : null

Con el operador de navegación podemos hacer esto mismo simplemente añadiendo el carácter “?” después del nombre de la variable que queremos evaluar:

// Evaluates to: myVariable != null ? myVariable.MyCustomField__c : null
System.debug(myVariable?.MyCustomField__c);

10 Switch

Al igual que el punto anterior, este tipo de condiciones son muy comunes en otros tipos de lenguajes de programación, pero en Salesforce no lo hemos tenido disponible hasta hace poco. Antes teníamos que sobrevivir a base de estructuras de if/else if/else.

La sintaxis es ligeramente diferente a la de otros lenguajes de programación y a mi muchas veces me cuesta acordarme de memoria. Pero siempre tendrás está guía para volverla a consultar cuando lo necesites.

switch on myAccount.Rating {
when 'Hot' {

}
when 'Warm', 'Cold' {

}
when else {
// Si no entra en ninguna de las otras opciones
// La opción 'default' en otros lenguajes
}
}

Un caso de uso que me encanta para este tipo de condiciones, es utilizarla para diferenciar la lógica que sigue nuestro código dependiendo del tipo de dato con el que estamos trabajando. Muy útil cuando escribimos código dinámico para diferentes tipos de objetos y cuando trabajamos con variables tipo sObject genérico.

switch on sobject {
when Account a {
System.debug('Account: ' + a);
}
when Contact c {
System.debug('Contact: ' + c);
}
when null {
System.debug('null');
}
when else {
System.debug('default');
}
}

Espero que te haya parecido interesante y alguno de estos trucos y/o consejos te ayudan en tu día a día. Estoy preparando una segunda parte con más trucos y consejos que seguro os gustarán. Sígueme para más artículos técnicos de Salesforce.

Y recuerda joven padawan:

--

--

Salesforce Jedi

+7 years in Salesforce landscape, now as architect and tech lead. Take a look to our GitHub repo: https://github.com/sfdcjedi