2. Confidential | Restricted to FinancialForce ‹#›
All non-public information in this presentation is FINANCIALFORCE CONFIDENTIAL. This presentation and related
discussions may refer to planned or proposed products, services, features or functions. Any unreleased products,
services, features or functions mentioned in this or other presentations, press releases or public statements are not
currently available and may not be delivered on time or at all. Customers who purchase our products or services
should base those purchase decisions on features and functions that are currently available. FinancialForce assumes
no obligation and does not intend to update any statements about future products, services, features or functions.
Disclaimer
4. Confidential | Restricted to FinancialForce ‹#›
Item 1 Introducción SoC
Item 2 SoC en Force.com
Item 3 Capa de Servicio
Item 4 Capa de Dominio
Item 5 Selectors - Acceso a Datos
Item 6 Q & A
Agenda
5. Confidential | Restricted to FinancialForce ‹#›
Si pensamos en el cuerpo humano, tenemos
huesos, músculos, órganos, que de manera
individual no tienen mucho sentido pero que
trabajando en un conjunto se benefician todos.
Separación de Conceptos (SoC) simplifica el
desarrollo y mantenimiento de aplicaciones.
¿Que és
SoC?
I - Introducción
6. Confidential | Restricted to FinancialForce ‹#›
I - Benefícios de SoC
Evolución Gestión del Impacto Roles y
Responsabilidad
8. Confidential | Restricted to FinancialForce ‹#›
Base Size of Solution or Code Number of Developers Requirements Scope
Number of Client Types &
Interactions
SOC Appropriate?
Small 1 to 2
● Well known and unlikely to
change
● One-off solutions
● Limited number of objects
● Standard UI
● Simple UI / Triggers
● No Batch Mode
● No API
● No Mobile
Typically not
Small to Medium 1 to 6
● Well known but may need to
evolve rapidly
● Growing number of objects and
processing interactions
● Product deliverable or larger
duration projects
● Standard UI
● Advanced VF /
Lightning
● Batch Mode
● API (on roadmap)
● Mobile (on roadmap)
Worth considering
Large > 6
● Scope driven by multiple
customer and user types
● Large number of objects
● Generic product or solution
aimed at Mid to Enterprise
market with Customer or
Partner integrations
● Growing development team!
● Standard UI
● Advanced VF /
Lightning
● Batch Mode
● Developer / Partner API
● Mobile Clients
● New Platform Feature
Ready, Chatter Actions!
Definite benefits
I - Cuando usar SoC
9. Confidential | Restricted to FinancialForce ‹#›
Lorem ipsum dolor sit amet
II - SoC en Force.com
Codificación
Tradicional
(Coding)
Codificación
Declarativa
(Point and Click)
10. Confidential | Restricted to FinancialForce ‹#›
II - SoC en Force.com
Presentación
- Declarativa: Layouts, Flow, Record Types, Formulas, Reports, Dashboards
- Tradicional: Apex Controllers, Visualforce, Lightning Components
Negocio
- Declarativa: Formula, Validation, Workflow, Process Builder, Sharing Rules
- Tradicional: Apex Services, Apex Custom Actions
Acceso a Datos
- Declarativa: Data Loaders
- Tradicional: SOQL, SOSL, Salesforce APIs
Base Datos
- Declarativa: Custom Objects, Fields, Relationships, Rollups
- Tradicional: Apex Triggers
11. Confidential | Restricted to FinancialForce ‹#›
Lorem ipsum dolor sit amet
II - Consideraciones Generales
BulkificaciónProgramación
Orientada por Objetos
12. Confidential | Restricted to FinancialForce ‹#›
Lorem ipsum dolor sit amet
II - Consideraciones Generales
SeguridadNaming conventions
13. Confidential | Restricted to FinancialForce ‹#›
Andrew Fawcett tiene publicada una librería de acceso
público donde nos aporta una solución para aplicar SoC en
Force.com
https://github.com/financialforcedev/fflib-apex-common
fflib
II - Desgranando SoC en FF
16. Confidential | Restricted to FinancialForce ‹#›
III - Capa de Servicio (Business)
Nos ayuda a formar un
encapsulado claro y
estricto de código
Es pura y abstracta Hay asegurarse de
que esté lista para su
uso (aplicaciones
móviles, API, UI)
23. Confidential | Restricted to FinancialForce ‹#›
III - Capa Servicio - Beneficios
Interfaces Mocks Test Desarrollo en Paralelo
24. Confidential | Restricted to FinancialForce ‹#›
Lorem ipsum dolor sit amet
IV - Capa de Dominio
Conjunto de requisitos
comunes, terminología
y funcionalidad
Construido para
resolver un problema
concreto
30. Confidential | Restricted to FinancialForce ‹#›
IV - Overrides Methods - fflib Domain
Invocado desde el método
handleBeforeInsert (interno a la fflib).
Permite rellenar campos con valores
predeterminados.
Confidential | Restricted to FinancialForce 30
31. Confidential | Restricted to FinancialForce ‹#›
IV - Propios Metodos - fflib Domain
Posibilita la creación de
métodos propios.
Ejemplo, OpportunityLineItems
para aplicar descuentos a
nivel de línea.
Confidential | Restricted to FinancialForce 31
32. Confidential | Restricted to FinancialForce ‹#›
Encapsula la lógica de consultar la información de
los objetos.
Selectors
V - Acceso a Datos
34. Confidential | Restricted to FinancialForce ‹#›
V - Ventajas de las Selectors
Evita consultas
inconsistentes
Evita datos
inconsistentes
Evita inconsistencia en
la seguridad
35. Confidential | Restricted to FinancialForce ‹#›
V - Beneficios de las Selectors
Visibilidad, reutilización
y mantenimiento
Previsibilidad de los
datos
Optimiza el
Rendimiento.
36. Confidential | Restricted to FinancialForce ‹#›
V - Selectors - tener en cuenta en Diseño
Métodos estáticos o
instancias.
Retornar listas
SObject.
Devolución de
conjuntos de registros
personalizados.
37. Confidential | Restricted to FinancialForce ‹#›
V - Selectors en fflib
fflib_SObjectSelectors, es tan simple como crear una clase que la herede e
instanciarla.
Confidential | Restricted to FinancialForce 37
39. Confidential | Restricted to FinancialForce ‹#›
V - Ejemplo - Product2 & Selectors
Confidential | Restricted to FinancialForce 39
40. Confidential | Restricted to FinancialForce ‹#›
V - Ejemplo - Product2 & Selectors (SOQL)
Después de haber ejecutado el método selectById.
Y el método getSObjectFieldList define una lista de campos para la consulta.
Para evitar problemas de Heap Size, omitir campos pocos utilizados o grandes.
Confidential | Restricted to FinancialForce 40
41. Confidential | Restricted to FinancialForce ‹#›
Conclusiones Finales
Mejor
legibilidad
Identificamos
las partes de
nuestro
entorno
Reduce el
impacto de la
evolución
Aprendizaje
rápido
Mejora
estructura del
código
42. Confidential | Restricted to FinancialForce ‹#›
Lorem ipsum dolor sit amet
¿Preguntas?
Agustín Jiménez Molina
ajimenez@financialforce.com
www.linkedin.com/in/agustín-jiménez-molina-a4208732
Soy Agustín Jiménez, estudié Ingeniería Informática en Granada, de ahí estuve realizando varios trabajos en diferentes empresas hasta que me traslade a Madrid.
Una vez allí, estuve trabajando en varias empresas, las mas importantes en Caser Seguros, participando en el desarrollo de su sistemas, en Indra, el cual estaba involucrado en el desarrollo de distintos proyectos entornos Java.
Tras esta etapa, pasé a formar parte de un equipo dedicado a Big Data para Segurcaixa Adeslas.
Pasado un tiempo me ofrecieron la posibilidad de formar parte de FinancialForce, me llamó tanto la atención que no lo dudé ni un instante y decidí afrontar este nuevo reto. Teniendo que decir que para mi, Salesforce en aquella época era completamente desconocido, pero mis conocimientos en otros entornos me ha servido para adaptarme con rapidez.
La forma mas fácil de entender que es SoC es fijarse en el cuerpo humano, tenemos huesos, músculos, órganos, que de manera individual no tienen mucho sentido y no tendría ninguna utilidad, en cambio, en todo su conjunto, es lo que conocemos como el Cuerpo Humano. Todas las partes se benefician, el uno del otro.
Esto, trasladandolo a un nivel tecnológico, podemos pensar en diferentes áreas como: Visuales; Almacén de datos; Lógica de negocio; comunicación con sistemas externos. Que en vez de tenerlo todo ubicado en un mismo sitio (llámese fichero, carpeta o cualquier otra cosa similar), vamos separando cada parte según su área, de tal manera que sea sencillo a la hora de mantener, el impacto de regresiones sea el mínimo y tendremos un software más saludable.
Por lo que el valor de la Separación de Conceptos es simplificar el desarrollo y mantenimiento de programas informáticos. Cuando los intereses están bien separados, se pueden reutilizar, desarrollar y actualizar las distintas secciones individuales de forma independiente. La posibilidad de modificar una parte del código del programa sin tener que revisar y modificar las demás es de gran valor en el mantenimiento de software.
Los beneficios que nos podemos encontrar el usar SoC son:
Evolución: Con el paso del tiempo, la tecnología va evolucionando, es posible que una capa tenga que ser ampliada, re-elaborada o incluso eliminada. Un ejemplo muy claro, echando un vistazo atrás, han existido frameworks de javascripts que posteriormente han ido desapareciendo.
Gestión del Impacto: La modificación, creación o eliminación de una o más capas no debería afectar al resto de software.
Roles y Responsabilidad: Cada capa tiene su propia responsabilidad, de tal manera que si está dedicado para algo exclusivo, no tiene que ceder a otra esa funcionalidad. Por ejemplo, no tiene sentido en una capa que se va a dedicar al almacenamiento de datos que haya una parte visual, pues no es su cometido. Al igual que si pensamos en una capa de Interfaz de usuario, encontrarnos funcionalidad de tratamiento de datos, es un sinsentido, pues no sería para lo que se pensó inicialmente.
Una estructura estandar de SoC es como la que nos encontramos, aunque podemos tener la estructura de tal manera que se ajuste mas a nuestra solución.
Dependiendo de dónde haya escrito su código, es posible que ya esté en buena forma para abordar algunos de los escenarios. La tabla que muestro a continuación nos puede ayudar a decidir si aplicamos SoC o no se recomienda porque fuera un costo mayor montarlo.
Puede utilizar cualquiera de estos métodos por sí solo o conjuntamente.
Los dos enfoques se ajustan a las capas SoC estándar de la siguiente manera (comentar muy resumida cuentas y pasar siguiente pagina donde se detalla cada uno de las capas).
Describir por encima las capas y lo que contiene cada una de ellas.
Organización que tengo el código deployado es:
Org: ajm_elevate2017@fforce.com / elevate2017
Programación Orientada por Objetos - Un objeto customizado no puede extender de otro de la misma manera que las clases en los lenguajes POO como Java. Por lo tanto, a menudo terminan creando una serie de objetos comunes que comparten aspectos similares, conjuntos de campos y relaciones. Al definir sus clases de dominio para estos objetos, consideremos el uso de herencia o interfaces para abstraer los aspectos comunes de comportamiento en una clase o interfaz compartida, lo que le permite crear y reutilizar la lógica que se aplica a través de dichos objetos.
Bulkificacion - Es una consideración clave del diseño en Force.com y tiene relación con la capa de dominio para asegurar que los constructores de clase de dominio, parámetros, métodos y propiedades tratan los datos en términos de listas y no singulares. Este enfoque ayuda a promover, y por lo tanto propagar en las capas. Un aspecto a tener en cuenta es que no tiene sentido tener un servicio bulkificado si el resto del código de la aplicación no lo admite.
Un ejemplo claro de bulkificación está en si queremos aplicar el descuento a más de una oportunidad, tenemos que llamar tantas veces al método de aplicar descuentos como oportunidades tengamos, en cambio si el método aceptara un listado de oportunidades el rendimiento sería mayor y nuestro aplicativo sería mas eficiente, porque ahorramos tiempo de llamada entre métodos, entrada/salida de método.
Naming conventions - Sea cual sea, debe quedarse claro el objetivo de clase y metodo que se está definiendo, tenemos que tener claro si estamos en una capa de servicio, dominio, selectors, so on… Debe ser algo común estandarizado en toda la solución de tal manera que sepamos cuando estamos consultando información y/o guardando algún valor.
Seguridad - un ejemplo de como se va aplicar CRUD en nuestra solución, o el uso del with sharing or without sharing, son aspectos que tenemos que tener en cuenta. Puede que nos olvidemos de controlar si cierto usuario tenga acceso a ciertos datos, entonces en determinados lugares del aplicativo tenemos que implementar seguridad
Andrew Fawcett, compañero de FinancialForce, MVP en Salesforce, publicó una librería que nos da soporte para poder trabajar por capas.
Estas librerías son públicas y se pueden acceder a través del enlace…
Actualmente en FF la estamos usando y nos aporta mucha funcionalidad ya implementada como el tema de multicurrencies, seguridad y manego de triggers.
Durante la presentacion, voy a tomar como ejemplo en como aplicar descuentos a oportunidades y/o sus líneas.
Si analizamos el código, vemos que esta primera aproximación cumpliría con el objetivo inicial, podríamos crear un botón dentro de Opportunity que invoque a este método y nos calcule los descuentos.
Este método applyDiscount se le pasa como parámetro el Opportunity como objecto y el valor en porcentaje del descuento.
Como vemos, dentro del mismo se hace una serie de calculos, primero calcula el factor del descuento, otra funcionalidad que puede ser añadida y dependiendo si la oportunidad tiene lineas (o no) hace unos calculos con el total (caso de no tener lineas) o calcula el descuento por cada línea.
La capa de servicio nos ayuda a formar un encapsulado claro y estricto de código que implementa tareas de negocio, cálculos y procesos. Esta debe permanecer pura y abstracta, para soportar los tiempos cambiantes.
Es importante asegurarse de que la capa de servicio está lista para su uso en diferentes contextos como:- aplicaciones móviles- formularios de interfaz de usuario- interfaces de usuario web complejas y numerosas API
Los distintos consumidores de la capa de servicio son:
Apex UI Controllers
Apex Web Service
Apex Rest Service
Batch Apex
Scheduled apex
Queueable
Antes de tener la capa de servicio definida, tenemos que tener en cuenta las siguientes consideraciones:
Naming Conventions: la capa de servicio debe ser lo suficientemente abstracta como para ser significativa para varios clientes. Este aspecto a menudo recae en los verbos y sustantivos que se utilizan en la clase, los métodos y los nombres de los parámetros. Hay que asegurar que se expresen en términos generales de la aplicación o la tarea en lugar de relacionarse con un llamador del cliente específico. Por ejemplo:
este nombre de método se basa en la operación de negocio OpportunityService.ApplyDiscount (...)
mientras que este nombre de método se basa en una operación de uso de cliente específica OpportunityService.handleDiscountForACME (...). Este segundo nombre es mas engorroso de entender e ilegible
Bulkificación (Plataforma) - Una de las preocupaciones principales de todo el código en Force.com es bulkificación. Tenemos que considerar los servicios con listas ven vez de conjuntos de parámetros individuales. Por ejemplo:
los parámetros de este método permite aumentar los descuentos en distintas oportunidades applyDiscount (List <Opportunity> opportunityList)
mientras que este método obliga a los llamadores a llamar al método repetidamente al opportunity services pasandole oportunidad a oportunidad.
Una vez más, el segundo podría ser innecesario.
Agrupar Funcionalidad - con el fin de evitar reescribir sobre cómo tratar aspectos de la interacción con la capa de servicio, por ejemplo, el manejo de errores. Cada desarrollador tiene sus propias idea y totalmente diferente a otros.
Por lo tanto, en este caso, normalmente es mejor aprovechar la semántica predeterminada de manejo de errores de Apex lanzando excepciones.
Aparte, tenemos que tener en cuentas mas consideraciones como:
Servicios Comunes - Aunque los clientes pueden ejecutar varias llamadas de servicio una tras otra, hacerlo puede ser ineficaz y causar problemas transaccionales de base de datos. Es mejor crear servicios comunes que agrupan internamente múltiples llamadas de servicio en una sola llamada de servicio. También es importante asegurarse de que la capa de servicio esté lo más optimizada posible con respecto al uso de SOQL y DML. Esto no significa que los servicios más granulares no puedan ser expuestos; Sólo significa que se debe dar a los consumidores (Llamantes, origen) la opción de utilizar un único servicio más específico si es necesario.
Gestión de Transacciones - La capa de servicio a menudo tienen requisitos diferentes en cuanto a la longevidad del proceso que se está llevando a cabo y la información que se está gestionando. Por ejemplo, una sola solicitud al servidor y varias solicitudes se dividen en ámbitos separados: el estado de administración (como Batch Apex) o una Interfaz de Usuario compleja que mantiene su propio estado de página en varias solicitudes. Dadas estas variaciones en la administración del estado, es mejor encapsular las operaciones de la base de datos y el estado del servicio dentro del método de la capa de servicio.
Configuración - Es posible que tenga una configuración común, como proporcionar control para permitir que el cliente indique a la capa del servidor que no envíe cambios, ni envíe correos electrónicos. Este escenario puede ser útil en los casos en que el cliente está implementando la funcionalidad de vista previa. Tenemos que asegurar de considerar la manera de implementar esto consistentemente, tal vez como una sobrecarga de métodos que toma un parámetro compartido Options, similar a los métodos DML en Apex.
Un ejemplo de como invocar a la capa de servicio desde una Standard Controller, es como se muestra a continuación.
Nosotros tendríamos nuestra clase controller y en nuestro método applyDiscount, podríamos invocar directamente a Apply Discounts de la services que tenemos definida.
OpportunityApplyDiscountController.cls (Controlador UI)
A continuación, la misma llamada pero en este caso desde un Batch Apex, tenemos nuestros metodos start/finish y dentro del execute, está invocando a la services.
OpportunityApplyDiscountJob.cls
Por este último ejemplo, desde un remote action, tenemos nuestro controller igualmente que desde allí, invoca a la capa de servicio con los mismos parámetros que tenemos definido con anterioridad.
Podemos realizar la implementación de servicios de simulacro de pruebas (mock test) y desarrollo en paralelo. Los servicios pueden utilizar una factory pattern junto con las interfaces Apex para resolver dinámicamente la implementación en lugar de codificarla directamente en los métodos. Este enfoque es útil para dar más flexibilidad.
Además, definir el diseño de la capa de servicio por adelantado permite a los equipos de desarrolladores trabajar mejor juntos o en paralelo. Aquellos que necesitan llamar a los servicios pueden usar implementaciones falsas para devolver datos estáticos, mientras que aquellos que implementan los servicios pueden trabajar en el código sin afectar a sus llamadas.
Un Dominio es un campo de estudio que define un conjunto de requisitos comunes, terminología y funcionalidad para cualquier programa de software construido para resolver un problema concreto.
Si la complejidad requiere de la codificación Apex, considere estructurar y factorizar el código utilizando técnicas de programación orientada a objetos (OOP) y el patrón Modelo de dominio.
Al igual que la Capa de Servicio, el modelo de Dominio proporciona un nivel más granular de encapsulación y reutilización de código dentro de la aplicación, como validación compleja, predeterminada y otra lógica relacionada con el cálculo y la manipulación complejas.
Los consumidores de la capa de dominio son:
Triggers: las operaciones de creación, lectura, actualización y eliminación (CRUD), incluyendo la recuperación, ocurren en sus custom objects como usuarios o herramientas interactuando a través de las interfaces de usuario de Salesforce estándar o de una API de la plataforma. Las operaciones se encaminan al código de clase de dominio correspondiente a ese objeto/operación.
Servicios: El código de la capa de servicio debe ser fácil de identificar y facilitar la reutilización de código relacionado con uno o más de los objetos con los que interactúa cada una de sus operaciones a través de clases de dominio.
la clase fflib_SObjectDomain que incluye dentro de la libreria, nos ofrece un conjunto de metodos útiles. Los métodos virtuales son susceptibles de ser sobreescritos, pero no es obligatorio.
La clase tiene un método estático “triggerHandler” que será utilizado desde los triggers.
La clase fflib_SObjectDomain es base para todas las clases de dominio, proporcionando funcionalidad útil, como seguridad de objetos.
El siguiente código de trigger es posible dado el uso de la clase fflib_SObjectDomain (que forma parte de la biblioteca de código abierto Apex Enterprise Patterns). Esta clase forma como base para todas las clases de dominio en su aplicación.
Consideremos también otro punto de entrada. Como se ilustra en el diagrama anterior, los usuarios pueden invocar los triggers de Apex a través de las IU de Salesforce o el código que manipula los registros a través de DML o Salesforce APIs.
Teniendo en cuenta el papel de la clase de dominio con respecto a la encapsulación de toda la lógica y el comportamiento de un objeto de dominio determinado, tenemos que asegurarnos de que las llamadas de disparador de Apex también se enrutan a los métodos de clase apropiados.
Al igual que con muchos patrones emergentes alrededor de Apex Triggers, es bueno mantener la lógica mínima en el trigger. Los Apex Triggers no son clases y tienen medios limitados para factorizar código o usar principios OO como herencia.
Echamos un vistazo al OpportunitiesService, el siguiente código muestra una nueva implementación del método de servicio applyDiscounts.
En esta ocasión llama a la clase de dominio Opportunities que encapsula la lógica que realiza los cálculos de descuento mediante su propio método applyDiscount.
Opportunities.cls
Como comenté con anterioridad, los métodos virtuales se pueden sobreescribir y la manera es tan sencilla como el ejemplo que muestro a continuación.
Utilizando la palabra reservada “override” nos permiten añadir la funcionalidad específica. En este caso, se asigna valores por defectos el Tipo de Descuento a aplicar, tomandolo de un Custom Setting.
Esto nos da de pensar que podríamos añadir un check indicando si no se ha introducido manualmente, pueda rellenarlo, o cualquier otro comportamiento que se requiera.
No siempre tenemos que sobreescribir los métodos que nos facilita la clase fflib_SObjectDomain, tenemos la posibilidad de crear métodos propios para un dominio concreto. Por ejemplo, tengamos el Dominio OpportunityLineItems para aplicar descuentos a nivel de línea, aquí podemos darle cierta lógica a una funcionalidad dada.
Los objetos y las bases de datos relacionales tienen diferentes formas para estructurar los datos. Muchas partes de un objeto, como colecciones y herencia, no están presentes en las bases de datos relacionales. Cuando se construye un modelo de objetos con mucha lógica de negocios, es valioso utilizar estos mecanismos para organizar mejor los datos y el comportamiento que conlleva.
Al final y al cabo, el concepto de selectors es encapsular la lógica de consultar la información de los objetos existentes en una organización.
Es usado principalmente por clases dentro de la capa de Servicio y el Dominio. Sin embargo, los controladores de UI y Batch Apex también pueden abastecerse de ellas.
El uso de la capa de selector la podemos hacer desde las diferentes capas, no siendo necesario tener que pasar por alguna otra para llegar a la información. (Controladores, Batch Apex, Servicio o Dominio.)
Las ventajas que tenemos de utilizar esta capa de selectors son:
Consultas Inconsistentes: las mismas consultas que se realizan desde diferentes lugares para la misma información o criterios pueden dar lugar a inconsistencias en su aplicación. Tal vez ciertos criterios deben aplicarse y se pierden. Algunas veces el código es copiado y pegado en el tiempo. Piense en una consulta como una gran lógica, no es una gran idea copiar y pegar.
Datos inconsistentes - Cuando los datos de registro consultados empiezan a fluir alrededor de su lógica, los métodos que reciben los registros pueden volverse frágiles. Tal vez un pedazo de código solicita que una cuenta u oportunidad se le pasan, sin embargo, no puede garantizar qué campos han sido consultados y, por tanto, el contenido resultante, causando el temido error de tiempo de ejecución: “System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: X.Y.” Los desarrolladores pueden terminar haciendo otra consulta sobre el mismo conjunto de registros simplemente para consultar los campos requeridos. O tal vez las rutas de código fluyan de tal manera que los registros dados por diferentes consultas se pasen a una función compartida. De cualquier manera esto no es bueno.
Inconsistencia en la seguridad - Salesforce requiere que todo el código Apex se adhiera a la seguridad del objeto del usuario en ejecución. Desafortunadamente, Apex se ejecuta a nivel de sistema, por lo que es responsabilidad del desarrollador comprobar la seguridad antes de hacer la consulta. Afortunadamente, no se necesita mucho código Apex para hacer esto, pero se pasa fácilmente por alto y no es fácil de probar en las pruebas unitarias. Mantener esto en una selector hace la vida mucho más fácil.
Dadas las ventajas descritas con anterioridad, el aplicar esta capa de Selectors nos beneficia en:
Visibilidad, reutilización y mantenimiento - La selectors facilita la búsqueda y el mantenimiento de la lógica de consulta. Si se actualiza los criterios de la consulta o se agregan campos, el riesgo al entorno es mínimo. El selector utiliza las referencias en tiempo de compilación a los nombres de campo, incluso si se están construyendo consultas dinámicas. Al hacerlo, se asegura que cuando se borren los campos, la plataforma evita la eliminación si existen referencias en el código.
Previsibilidad de los datos a consultar - Debe quedar claro lo que el selector está haciendo (con el nombre del método), y lo que está devolviendo. Retornar objetos parcialmente poblados no siempre es un buen modelo, ya que no está claro para el consumidor o para quien el consumidor pasa los datos de registro, lo que resulta en excepciones de tiempo de ejecución.
Optimiza el Rendimiento - Hacer las consultas lo más óptimas posible, expresando principalmente los criterios a través de listas, animando a bulkificar su código al llamar a los métodos selectores. Los selectores también deben ser capaces de equilibrar la necesidad de coherencia de los datos de campo consultados frente a los datos de campo óptimos cuando se trate de grandes conjuntos de datos.
Aparte de las consideraciones generales vistas con anterioridad, tenemos que tener en cuenta las siguientes consideraciones:
Métodos - Los métodos pueden ser estáticos o una instancia. Este último permite el uso de una clase base y herencia de comportamiento común. Los nombres de los métodos (normalmente prefijados con select) indican idealmente la información y cualquier información secundaria relacionada, como selectById y selectByIdWithProductLines, por ejemplo.
Devolver listas de sObject - Principalmente los métodos Selector deben devolver las listas sObject. Aunque Apex ahora admite mapas y conjuntos deterministas, ninguno puede ser usado para reflejar un orden de clasificación. La solución es proporcionar dos variantes de métodos, selectByIdMap y selectByIdList, o simplemente tener selectById y permitir que el llamador envuelva la lista devuelta en un mapa si es necesario. Por ejemplo:
Map<Id, Account> accountsById =
new Map<Id, Account>( accountsSelector.selectByIds(accountIds) );
Devolución de conjuntos de registros lógicos personalizados - en algunos casos, devolver la representación física de una Cuenta, Oportunidad o MyObject__c a través de una instancia de SObject no es la mejor manera de reflejar los campos que se han consultado. En los casos en los que desea consultar sólo unos pocos campos, por ejemplo, para evitar problemas de heap o viewstate, o está seleccionando campos de varias relaciones o realizando una consulta agregada, considere el uso de una clase Apex personalizada (POJO de Java) para implementar Un Contenedor para el resultado de la consulta para exponer los campos de resultados de la consulta más explícitamente como una representación más lógica de la información específica consultada.
Utilizar la clase base fflib_SObjectSelector para hacer la creación y ejecución de consultas SOQL sea más fácil, más consistente y más compatible con el mínimo código.
Esta clase nos proporciona funcionalidad útil como:
Inclusión de Características especiales de la Organización - campos dependientes ( CurrencyIsoCode) que sólo están visibles cuando está habilitada la función de moneda múltiple.
Capacidad para incluir (opcionalmente) campos definidos por un FieldSet.
Aplicación de la seguridad de la plataforma lanzando una excepción si el usuario no tiene acceso de lectura al objeto. Se puede desactivar esta función a través de un argumento constructor si el código consumidor desea omitirlo.
Los métodos de la clase base fflib_SObjectSelector, que es una clase base abstracta, por lo que tenemos que implementar al menos los métodos marcados como abstract(se indican con un A):
getSObjectType()
getSObjectFieldList()
Y para terminar, unas conclusiones finales o beneficios que podemos tener de implantar SoC en nuestra solución:
Mejora la estructura de nuestro código.
Reduce el impacto de la evolución de nuestro código.
Mantenimiento del aplicativo sencillo.
El aprendizaje es más rápido.
Tenemos identificado las partes que se compone nuestro entorno.
Mejora la legibilidad.