SlideShare ist ein Scribd-Unternehmen logo
1 von 45
Downloaden Sie, um offline zu lesen
Apex Design Patterns
Developers
Richard Vanhook and Dennis Thong
@richardvanhook @denniscfthong
Safe Harbor
Safe harbor statement under the Private Securities Litigation Reform Act of 1995:
This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties
materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results
expressed or implied by the forward-looking statements we make. All statements other than statements of historical fact could be
deemed forward-looking, including any projections of product or service availability, subscriber growth, earnings, revenues, or other
financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any
statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new
functionality for our service, new products and services, our new business model, our past operating losses, possible fluctuations in our
operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of any
litigation, risks associated with completed and any possible mergers and acquisitions, the immature market in which we operate, our
relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our
service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to
larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is
included in our annual report on Form 10-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most recent
fiscal quarter. These documents and others containing important disclosures are available on the SEC Filings section of the Investor
Information section of our Web site.
Any unreleased services or features referenced 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 services should make the purchase decisions
based upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these
forward-looking statements.
Richard Vanhook
Senior Technical Solution Architect
@richardvanhook

Dennis Thong
Director - Technical Solution Architect
@denniscfthong
The Plan
Cover four design patterns
▪ Problem
▪ Pattern Abstract
▪ Code

Your participation is encouraged!
Patterns
1. ?
2. ?
3. ?
4. ?
Meet Billy, Your Admin
• 3+ yrs as Salesforce Admin
• Just recently started coding
• Sad because of this:
Trigger.AccountTrigger: line 3, column 1
System.LimitException: Too many record
type describes: 101

• Needs your help!
The Offending Code
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = new AccountFooRecordType();
....
}
}

07
08
09
10
11
12
13

public class AccountFooRecordType {
public String id {get;private set;}
public AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
}

• When a single Account is inserted, what happens?
• When 200+ Accounts are inserted…?
Solution: Singleton

Singleton
- instance : Singleton
- Singleton()
+ getInstance() : Singleton
Let’s Code It!
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = new AccountFooRecordType();
....
}
}

07
08
09
10
11
12
13

public class AccountFooRecordType {
public String id {get;private set;}
public AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
}

• Above is the offending code again
• Changes are highlighted in next slides
Let’s Code It!
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = (new AccountFooRecordType()).getInstance();
....
}
}

07
08
09
10
11
12
13
14
15
16

public class AccountFooRecordType {
public String id {get;private set;}
public AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
public AccountFooRecordType getInstance(){
return new AccountFooRecordType();
}
}
Let’s Code It!
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = AccountFooRecordType.getInstance();
....
}
}

07
08
09
10
11
12
13
14
15
16

public class AccountFooRecordType {
public String id {get;private set;}
public AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
public static AccountFooRecordType getInstance(){
return new AccountFooRecordType();
}
}
Static
▪ Can modify member variables, methods, and blocks
▪ Executed when?
• When class is introduced (loaded) to runtime environment

▪ How long does that last in Java?
• Life of the JVM

▪ In Apex?
• Life of the transaction
Let’s Code It!
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = AccountFooRecordType.getInstance();
....
}
}

07
08
09
10
11
12
13
14
15
16

public class AccountFooRecordType {
public String id {get;private set;}
public AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
public static AccountFooRecordType getInstance(){
return new AccountFooRecordType();
}
}
Let’s Code It!
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = AccountFooRecordType.getInstance();
....
}
}

07
08
09
10
11
12
13
14
15
16
17
18

public class AccountFooRecordType {
public static AccountFooRecordType instance = null;
public String id {get;private set;}
public AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
public static AccountFooRecordType getInstance(){
if(instance == null) instance = new AccountFooRecordType();
return instance;
}
}
Let’s Code It!
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = AccountFooRecordType.getInstance();
....
}
}

07
08
09
10
11
12
13
14
15
16
17
18

public class AccountFooRecordType {
private static AccountFooRecordType instance = null;
public String id {get;private set;}
public AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
public static AccountFooRecordType getInstance(){
if(instance == null) instance = new AccountFooRecordType();
return instance;
}
}
Let’s Code It!
01
02
03
04
05
06

trigger AccountTrigger on Account (before insert, before update) {
for(Account record : Trigger.new){
AccountFooRecordType rt = AccountFooRecordType.getInstance();
....
}
}

07
08
09
10
11
12
13
14
15
16
17
18

public class AccountFooRecordType {
private static AccountFooRecordType instance = null;
public String id {get;private set;}
private AccountFooRecordType(){
id = Account.sObjectType.getDescribe()
.getRecordTypeInfosByName().get('Foo').getRecordTypeId();
}
public static AccountFooRecordType getInstance(){
if(instance == null) instance = new AccountFooRecordType();
return instance;
}
}
Patterns
1. Singleton
2. ?
3. ?
4. ?
geocode('moscone center')
//=> 37.7845935,-122.3994262
Your Suggestion to Billy
01
02
03
04
05
06

public class GoogleMapsGeocoder{
public static List<Double> getLatLong(String address){
//web service callout of some sort
return new List<Double>{0,0};
}
}

07
08

System.debug(GoogleMapsGeocoder.getLatLong('moscone center'));
//=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)

But then Billy mentions these requirements
▪ Need other options besides Google Maps
▪ Allow client code to choose provider
Solution: Strategy
Context

Strategy

strategies

Client
+operation()

1

*

+operation()

defines a family of algorithms,
ConcreteStrategyA

encapsulates each one, and makes
them interchangeable

+operation()

▪ Context => Geocoder
▪ operation() => getLatLong()
▪ Strategy => GeocodeService
▪ ConcreteStrategyA => GoogleMapsImpl
▪ ConcreteStrategyB => MapQuestImpl

ConcreteStrategyB
+operation()
Let’s Code It
01
02
03

public interface GeocodeService{
List<Double> getLatLong(String address);
}

04
05
06
07
08

public class GoogleMapsImpl implements GeocodeService{
public List<Double> getLatLong(String address){
return new List<Double>{0,0};
}
}

09
10
11
12
13

public class MapQuestImpl implements GeocodeService{
public List<Double> getLatLong(String address){
return new List<Double>{1,1};
}
}
01
02
03
04
05
06
07
08
09

public class Geocoder {
private GeocodeService strategy;
public Geocoder(GeocodeService s){
strategy = s;
}
public List<Double> getLatLong(String address){
return strategy.getLatLong(address);
}
}
Geocoder

GeocodeService

strategies
Client

+ Geocoder(GeocodeService)
1
+getLatLong(String)

*

+getLatLong(String)

GoogleMapsImpl
+getLatLong(String)

10
11
12

Geocoder geocoder = new Geocoder(new GoogleMapsImpl());
System.debug(geocoder.getLatLong('moscone center'));
//=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)

MapQuestImpl
+getLatLong(String)
01
02
03
04
05
06
07
08
09
10

public class Geocoder {
public static final Map<String,Strategy> strategies = new
Map<String,Strategy>{'googlemaps' => new GoogleMapsImpl()
,'mapquest'
=> new MapQuestImpl()};
private GeocodeService strategy;
public Geocoder(String name){ strategy = strategies.get(name);}
public List<Double> getLatLong(String address){
return strategy.getLatLong(address);
}
}
Geocoder

GeocodeService

strategies
Client

+ Geocoder(String)
1
+getLatLong(String)

*

+getLatLong(String)

GoogleMapsImpl
+getLatLong(String)

11
12
13

Geocoder geocoder = new Geocoder('googlemaps');
System.debug(geocoder.getLatLong('moscone center'));
//=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)

MapQuestImpl
+getLatLong(String)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22

public class Geocoder {
public class NameException extends Exception{}
public static final Map<String,GeocodeService> strategies;
static{
GlobalVariable__c gv = GlobalVariable__c.getInstance('strategies');
List<String> strategyNames = new List<String>();
if(gv != null && gv.value__c != null) strategyNames = gv.value__c.split(',');
strategies = new Map<String,GeocodeService>();
for(String name : strategyNames){
try{strategies.put(name,(GeocodeService)Type.forName(name+'impl').newInstance());}
catch(Exception e){continue;} //skip bad name silently
}
}
private GeocodeService strategy;
public Geocoder(String name){
if(!strategies.containsKey(name)) throw new NameException(name);
strategy = strategies.get(name);
}
public List<Double> getLatLong(String address){
return strategy.getLatLong(address);
}
}
Patterns
1. Singleton
2. Strategy
3. ?
4. ?
Question
How do we extend the functionality of an sObject in Apex without adding new fields?

Transient selection
checkboxes

Calculated Fields
with Updates
Solution – sObject Decorator

(aka Wrapper Classes v2.0)
Example - Scenario
Weather sObject
▪ City__c
▪ TempInFahrenheit__c (in Fahrenheit)

VisualForce Requirements
▪ Stored temperature in Fahrenheit is displayed in Celcius
▪ User enters Temperature in Celcius and is stored to the record in Fahrenheit

Bi-directional Display and
Calculation
The Code – Decorated sObject Class
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23

public class DecoratedWeather {
public Weather__c weather { get; private set; }
public DecoratedWeather ( Weather__c weather) {
this.weather = weather;
}
public Decimal tempInCelcius {
get {
if (weather != null && tempInCelcius == null )
tempInCelcius = new Temperature().FtoC(weather.TempInFahrenheit__c);
return tempInCelcius;
}
set {
if (weather != null && value != null )
weather.TempInFahrenheit__c= new Temperature().CtoF(value);
tempInCelcius = value;
}
}
}
The Code – Custom Controller
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18

public class Weather_Controller {
public List<DecoratedWeather> listOfWeather {
get {
if (listOfWeather == null) {
listOfWeather = new List<DecoratedWeather>();
for (Weather__c weather : [ select name, temperature__c from Weather__c]) {
listOfWeather. add(new DecoratedWeather(weather));
}
}
return listOfWeather;
}
private set;
}
}
The Code – VisualForce Page
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

<apex:page controller="weather_controller">
<!-- VF page to render the weather records with Ajax that only rerenders
the page on change of the temperature
-->
<apex:form id="theForm">
<apex:pageBlock id="pageBlock">
<apex:pageBlockTable value="{!listOfWeather}" var="weather">
<apex:column value="{!weather.weather.name}"/>
<apex:column headerValue="Temperature (C)">
<apex:actionRegion >
<apex:inputText value="{!weather.tempInCelcius}">
<apex:actionSupport event="onchange"
reRender="pageBlock"/>
</apex:inputText>
</apex:actionRegion>
</apex:column>
<apex:column headerValue="Temperature (F)"
value="{!weather.weather.Temperature__c}"
id="tempInF"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>

No client side
logic!!!
Finally, on the VisualForce page
Patterns
1. Singleton
2. Strategy
3. sObject Decorator
4. ?
Billy Has a New Problem!
Billy wrote a trigger to create an order on close of an opportunity,
however:
▪ It always creates a new order every time the closed opportunity is
updated
▪ When loading via Data Loader, not all closed opportunities result in an
order
The Offending Code
01
02
03
04
05
06
07
08

trigger OpptyTrigger on Opportunity (after insert, after update) {
if (trigger.new[0].isClosed) {
Order__c order = new Order__c();
…
insert order
}
}

Poor reusability

Occurs regardless
of prior state
No Bulk
Handling
Any Better?
01
02
03
04
05

trigger OpptyTrigger on Opportunity (after insert, after update) {

01
02
03
04
05
06
07
08
09
10
11
12
13

public class OrderClass {

new OrderClass().CreateOrder(trigger.new);
}

public void CreateOrder(List<Opportunity> opptyList) {
for (Opportunity oppty : opptyList) {
if (oppty.isClosed) {
Order__c order = new Order__c();
Occurs regardless
...
of prior state
insert order;
}
}
}
}

Not bulkified
How’s this?
01
02
03
04
0506

trigger OpptyTrigger on Opportunity (before insert, before update) {
if (trigger.isInsert) {
new OrderClass().CreateOrder(trigger.newMap, null);
else
new OrderClass().CreateOrder(trigger.newMap, trigger.oldMap);

01
public class OrderClass {
02
03
public void CreateOrder(Map<Opportunity> opptyMapNew
04
Map<Opportunity> opptyMapOld) {
05
List<Order__c> orderList = new List<Order__c>();
06
for (Opportunity oppty : opptyMapNew.values()) {
07
if (oppty.isClosed && (opptyMapOld == null ||
08
!opptyMapOld.get(oppty.id).isClosed)) {
09 least it’s
Order__c order = new Order__c();
At
10
...
bulkified
11
orderList.add(order);
12
}
13
}
14
insert orderList ;
15
}

This code is highly coupled
and not reusable
Solution – Bulk Transition

•

•
•

Checks for eligible records
that have changed state and
match criteria
Calls utility class method to
perform the work
Only eligible records are
passed in

•

Generic utility class method that can
be called from any context
At Last!!!
01
02
03
04
05
06
07
08
09
10
11

trigger OpptyTrigger on Opportunity (after insert, after update) {
if (trigger.isAfter && (trigger.isInsert || trigger.isUpdate)) {
List<Opportunity> closedOpptyList = new List<Opportunity>();
for (Opportunity oppty : trigger.new) {
if (oppty.isClosed && (trigger.isInsert ||
(trigger.isUpdate &&
!trigger.oldMap.get(oppty.id).isClosed)))
closedOpptyList.add(oppty);
}
if (!closedOpptyList.isEmpty())
new OrderClass().CreateOrderFromOpptys(closedOpptyList)

01
02
03
04
05
06
07
08
09

public class OrderClass {
public void CreateOrdersFromOpptys(List<Opportunity> opptyList) {
List<Order__c> orderList = new List<Order__c>();
for (Opportunity oppty : opptyList) {
Order__c order = new Order__c();
This method is now a lot
...
more reusable and is bulkorderList.add(order);
safe
}
insert orderList ;

Trigger handles state
transition
Patterns
1. Singleton
2. Strategy
3. sObject Decorator
4. Bulk State Transition
Resources
Wrapper Classes - http://wiki.developerforce.com/page/Wrapper_Class
Apex Code Best Practices - http://wiki.developerforce.
com/page/Apex_Code_Best_Practices
Apex Web Services and Callouts - http://wiki.developerforce.
com/page/Apex_Web_Services_and_Callouts
Sample Code - https://github.com/richardvanhook/Force.com-Patterns
More at #DF13
Apex Enterprise Patterns: Building Strong Foundations
Tuesday, November 19th: 12:15 pm - 01:00 pm - Moscone Center West – 2009
High Reliability DML and Concurrency Design Patterns for Apex
Monday, November 18th: 11:15 am - 12:00 pm - Moscone Center West – 2009
Making Your Apex and Visualforce Reusable
Tuesday, November 19th: 12:15 pm - 01:00 pm - Moscone Center West – 2022
Design Patterns for Asynchronous Apex
Tuesday, November 19th: 05:15 pm - 06:00 pm - Moscone Center West – 2024
The Apex Ten Commandments
Wednesday, November 20th: 04:00 pm - 04:45 pm - Moscone Center West - 2006 / 2008
Speaker Name

Speaker Name

Dennis Thong,
@denniscfthong

Richard Vanhook,
@richardvanhook
We want to hear
from YOU!
Please take a moment to complete our
session survey
Surveys can be found in the “My Agenda”
portion of the Dreamforce app
Apex Design Patterns

Weitere ähnliche Inhalte

Was ist angesagt?

Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Salesforce Developers
 
Managing the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise ScaleManaging the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise ScaleSalesforce Developers
 
Salesforce complete overview
Salesforce complete overviewSalesforce complete overview
Salesforce complete overviewNitesh Mishra ☁
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and TestingSalesforce Developers
 
Single Sign-On and User Provisioning with Salesforce Identity
Single Sign-On and User Provisioning with Salesforce IdentitySingle Sign-On and User Provisioning with Salesforce Identity
Single Sign-On and User Provisioning with Salesforce IdentitySalesforce Developers
 
Salesforce Development Best Practices
Salesforce Development Best PracticesSalesforce Development Best Practices
Salesforce Development Best PracticesVivek Chawla
 
Salesforce Integration
Salesforce IntegrationSalesforce Integration
Salesforce IntegrationJoshua Hoskins
 
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...Sam Garforth
 
Salesforce Streaming event - PushTopic and Generic Events
Salesforce Streaming event - PushTopic and Generic EventsSalesforce Streaming event - PushTopic and Generic Events
Salesforce Streaming event - PushTopic and Generic EventsDhanik Sahni
 
Build Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable ApexBuild Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable ApexSalesforce Developers
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce OrgSalesforce Admins
 
Two-Way Integration with Writable External Objects
Two-Way Integration with Writable External ObjectsTwo-Way Integration with Writable External Objects
Two-Way Integration with Writable External ObjectsSalesforce Developers
 
Understanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce PlatformUnderstanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce PlatformSalesforce Developers
 
OAuth with Salesforce - Demystified
OAuth with Salesforce - DemystifiedOAuth with Salesforce - Demystified
OAuth with Salesforce - DemystifiedCalvin Noronha
 
Episode 20 - Trigger Frameworks in Salesforce
Episode 20 - Trigger Frameworks in SalesforceEpisode 20 - Trigger Frameworks in Salesforce
Episode 20 - Trigger Frameworks in SalesforceJitendra Zaa
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilitySalesforce Developers
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelSalesforce Developers
 
Salesforce Security Best Practices for Every Admin
Salesforce Security Best Practices for Every AdminSalesforce Security Best Practices for Every Admin
Salesforce Security Best Practices for Every AdminCloud Analogy
 

Was ist angesagt? (20)

Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex!
 
Managing the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise ScaleManaging the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise Scale
 
Salesforce complete overview
Salesforce complete overviewSalesforce complete overview
Salesforce complete overview
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and Testing
 
Single Sign-On and User Provisioning with Salesforce Identity
Single Sign-On and User Provisioning with Salesforce IdentitySingle Sign-On and User Provisioning with Salesforce Identity
Single Sign-On and User Provisioning with Salesforce Identity
 
Salesforce Development Best Practices
Salesforce Development Best PracticesSalesforce Development Best Practices
Salesforce Development Best Practices
 
Salesforce Integration
Salesforce IntegrationSalesforce Integration
Salesforce Integration
 
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
 
Salesforce Streaming event - PushTopic and Generic Events
Salesforce Streaming event - PushTopic and Generic EventsSalesforce Streaming event - PushTopic and Generic Events
Salesforce Streaming event - PushTopic and Generic Events
 
Build Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable ApexBuild Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable Apex
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce Org
 
Introduction to Apex Triggers
Introduction to Apex TriggersIntroduction to Apex Triggers
Introduction to Apex Triggers
 
Two-Way Integration with Writable External Objects
Two-Way Integration with Writable External ObjectsTwo-Way Integration with Writable External Objects
Two-Way Integration with Writable External Objects
 
Understanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce PlatformUnderstanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce Platform
 
OAuth with Salesforce - Demystified
OAuth with Salesforce - DemystifiedOAuth with Salesforce - Demystified
OAuth with Salesforce - Demystified
 
Episode 20 - Trigger Frameworks in Salesforce
Episode 20 - Trigger Frameworks in SalesforceEpisode 20 - Trigger Frameworks in Salesforce
Episode 20 - Trigger Frameworks in Salesforce
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura Interoperability
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security Model
 
Salesforce Security Best Practices for Every Admin
Salesforce Security Best Practices for Every AdminSalesforce Security Best Practices for Every Admin
Salesforce Security Best Practices for Every Admin
 
Salesforce asynchronous apex
Salesforce asynchronous apexSalesforce asynchronous apex
Salesforce asynchronous apex
 

Ähnlich wie Apex Design Patterns

Visualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsVisualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsRitesh Aswaney
 
Building Visualforce Custom Events Handlers
Building Visualforce Custom Events HandlersBuilding Visualforce Custom Events Handlers
Building Visualforce Custom Events HandlersSalesforce Developers
 
Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Joshua Birk
 
Developing Offline Mobile Apps With Salesforce Mobile SDK SmartStore
Developing Offline Mobile Apps With Salesforce Mobile SDK SmartStoreDeveloping Offline Mobile Apps With Salesforce Mobile SDK SmartStore
Developing Offline Mobile Apps With Salesforce Mobile SDK SmartStoreSalesforce Developers
 
TrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data Capture
TrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data CaptureTrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data Capture
TrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data CaptureJohn Brock
 
Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013
Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013
Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013Salesforce Developers
 
ELEVATE Advanced Workshop
ELEVATE Advanced WorkshopELEVATE Advanced Workshop
ELEVATE Advanced WorkshopJoshua Birk
 
Event Driven Integrations
Event Driven IntegrationsEvent Driven Integrations
Event Driven IntegrationsDeepu Chacko
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKSalesforce Developers
 
S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummiesdreamforce2006
 
S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummiesdreamforce2006
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPSalesforce Developers
 
Apex enterprise patterns
Apex enterprise patternsApex enterprise patterns
Apex enterprise patternsAmit Jain
 
Solving Complex Data Load Challenges
Solving Complex Data Load ChallengesSolving Complex Data Load Challenges
Solving Complex Data Load ChallengesSunand P
 
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門Salesforce Developers Japan
 

Ähnlich wie Apex Design Patterns (20)

Visualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsVisualforce Hack for Junction Objects
Visualforce Hack for Junction Objects
 
Building Visualforce Custom Events Handlers
Building Visualforce Custom Events HandlersBuilding Visualforce Custom Events Handlers
Building Visualforce Custom Events Handlers
 
Write bulletproof trigger code
Write bulletproof trigger codeWrite bulletproof trigger code
Write bulletproof trigger code
 
Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Detroit ELEVATE Track 2
Detroit ELEVATE Track 2
 
Developing Offline Mobile Apps With Salesforce Mobile SDK SmartStore
Developing Offline Mobile Apps With Salesforce Mobile SDK SmartStoreDeveloping Offline Mobile Apps With Salesforce Mobile SDK SmartStore
Developing Offline Mobile Apps With Salesforce Mobile SDK SmartStore
 
Force.com Friday : Intro to Apex
Force.com Friday : Intro to Apex Force.com Friday : Intro to Apex
Force.com Friday : Intro to Apex
 
TrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data Capture
TrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data CaptureTrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data Capture
TrailheaDX 2019 : Truly Asynchronous Apex Triggers using Change Data Capture
 
Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013
Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013
Salesforce1 Platform ELEVATE LA workshop Dec 18, 2013
 
ELEVATE Advanced Workshop
ELEVATE Advanced WorkshopELEVATE Advanced Workshop
ELEVATE Advanced Workshop
 
Event Driven Integrations
Event Driven IntegrationsEvent Driven Integrations
Event Driven Integrations
 
Introduction to Apex for Developers
Introduction to Apex for DevelopersIntroduction to Apex for Developers
Introduction to Apex for Developers
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDK
 
S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummies
 
S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummies
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCP
 
Apex enterprise patterns
Apex enterprise patternsApex enterprise patterns
Apex enterprise patterns
 
Solving Complex Data Load Challenges
Solving Complex Data Load ChallengesSolving Complex Data Load Challenges
Solving Complex Data Load Challenges
 
ELEVATE Paris
ELEVATE ParisELEVATE Paris
ELEVATE Paris
 
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
 
Finding Security Issues Fast!
Finding Security Issues Fast!Finding Security Issues Fast!
Finding Security Issues Fast!
 

Mehr von Salesforce Developers

Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSalesforce Developers
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceSalesforce Developers
 
Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base ComponentsSalesforce Developers
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsSalesforce Developers
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaSalesforce Developers
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentSalesforce Developers
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsSalesforce Developers
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsSalesforce Developers
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsSalesforce Developers
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce dataSalesforce Developers
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionSalesforce Developers
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceSalesforce Developers
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureSalesforce Developers
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DXSalesforce Developers
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectSalesforce Developers
 
Modern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesModern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesSalesforce Developers
 

Mehr von Salesforce Developers (20)

Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component Performance
 
Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base Components
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer Highlights
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX India
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local Development
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web Components
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web Components
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer Highlights
 
Live coding with LWC
Live coding with LWCLive coding with LWC
Live coding with LWC
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce data
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An Introduction
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in Salesforce
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data Capture
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DX
 
Get Into Lightning Flow Development
Get Into Lightning Flow DevelopmentGet Into Lightning Flow Development
Get Into Lightning Flow Development
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS Connect
 
Introduction to MuleSoft
Introduction to MuleSoftIntroduction to MuleSoft
Introduction to MuleSoft
 
Modern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesModern App Dev: Modular Development Strategies
Modern App Dev: Modular Development Strategies
 
Dreamforce Developer Recap
Dreamforce Developer RecapDreamforce Developer Recap
Dreamforce Developer Recap
 

Kürzlich hochgeladen

TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 

Kürzlich hochgeladen (20)

TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 

Apex Design Patterns

  • 1. Apex Design Patterns Developers Richard Vanhook and Dennis Thong @richardvanhook @denniscfthong
  • 2. Safe Harbor Safe harbor statement under the Private Securities Litigation Reform Act of 1995: This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services. The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of any litigation, risks associated with completed and any possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most recent fiscal quarter. These documents and others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site. Any unreleased services or features referenced 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 services should make the purchase decisions based upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
  • 3. Richard Vanhook Senior Technical Solution Architect @richardvanhook Dennis Thong Director - Technical Solution Architect @denniscfthong
  • 4. The Plan Cover four design patterns ▪ Problem ▪ Pattern Abstract ▪ Code Your participation is encouraged!
  • 6. Meet Billy, Your Admin • 3+ yrs as Salesforce Admin • Just recently started coding • Sad because of this: Trigger.AccountTrigger: line 3, column 1 System.LimitException: Too many record type describes: 101 • Needs your help!
  • 7. The Offending Code 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = new AccountFooRecordType(); .... } } 07 08 09 10 11 12 13 public class AccountFooRecordType { public String id {get;private set;} public AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } } • When a single Account is inserted, what happens? • When 200+ Accounts are inserted…?
  • 8. Solution: Singleton Singleton - instance : Singleton - Singleton() + getInstance() : Singleton
  • 9. Let’s Code It! 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = new AccountFooRecordType(); .... } } 07 08 09 10 11 12 13 public class AccountFooRecordType { public String id {get;private set;} public AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } } • Above is the offending code again • Changes are highlighted in next slides
  • 10. Let’s Code It! 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = (new AccountFooRecordType()).getInstance(); .... } } 07 08 09 10 11 12 13 14 15 16 public class AccountFooRecordType { public String id {get;private set;} public AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } public AccountFooRecordType getInstance(){ return new AccountFooRecordType(); } }
  • 11. Let’s Code It! 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = AccountFooRecordType.getInstance(); .... } } 07 08 09 10 11 12 13 14 15 16 public class AccountFooRecordType { public String id {get;private set;} public AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } public static AccountFooRecordType getInstance(){ return new AccountFooRecordType(); } }
  • 12. Static ▪ Can modify member variables, methods, and blocks ▪ Executed when? • When class is introduced (loaded) to runtime environment ▪ How long does that last in Java? • Life of the JVM ▪ In Apex? • Life of the transaction
  • 13. Let’s Code It! 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = AccountFooRecordType.getInstance(); .... } } 07 08 09 10 11 12 13 14 15 16 public class AccountFooRecordType { public String id {get;private set;} public AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } public static AccountFooRecordType getInstance(){ return new AccountFooRecordType(); } }
  • 14. Let’s Code It! 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = AccountFooRecordType.getInstance(); .... } } 07 08 09 10 11 12 13 14 15 16 17 18 public class AccountFooRecordType { public static AccountFooRecordType instance = null; public String id {get;private set;} public AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } public static AccountFooRecordType getInstance(){ if(instance == null) instance = new AccountFooRecordType(); return instance; } }
  • 15. Let’s Code It! 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = AccountFooRecordType.getInstance(); .... } } 07 08 09 10 11 12 13 14 15 16 17 18 public class AccountFooRecordType { private static AccountFooRecordType instance = null; public String id {get;private set;} public AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } public static AccountFooRecordType getInstance(){ if(instance == null) instance = new AccountFooRecordType(); return instance; } }
  • 16. Let’s Code It! 01 02 03 04 05 06 trigger AccountTrigger on Account (before insert, before update) { for(Account record : Trigger.new){ AccountFooRecordType rt = AccountFooRecordType.getInstance(); .... } } 07 08 09 10 11 12 13 14 15 16 17 18 public class AccountFooRecordType { private static AccountFooRecordType instance = null; public String id {get;private set;} private AccountFooRecordType(){ id = Account.sObjectType.getDescribe() .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); } public static AccountFooRecordType getInstance(){ if(instance == null) instance = new AccountFooRecordType(); return instance; } }
  • 19. Your Suggestion to Billy 01 02 03 04 05 06 public class GoogleMapsGeocoder{ public static List<Double> getLatLong(String address){ //web service callout of some sort return new List<Double>{0,0}; } } 07 08 System.debug(GoogleMapsGeocoder.getLatLong('moscone center')); //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0) But then Billy mentions these requirements ▪ Need other options besides Google Maps ▪ Allow client code to choose provider
  • 20. Solution: Strategy Context Strategy strategies Client +operation() 1 * +operation() defines a family of algorithms, ConcreteStrategyA encapsulates each one, and makes them interchangeable +operation() ▪ Context => Geocoder ▪ operation() => getLatLong() ▪ Strategy => GeocodeService ▪ ConcreteStrategyA => GoogleMapsImpl ▪ ConcreteStrategyB => MapQuestImpl ConcreteStrategyB +operation()
  • 21. Let’s Code It 01 02 03 public interface GeocodeService{ List<Double> getLatLong(String address); } 04 05 06 07 08 public class GoogleMapsImpl implements GeocodeService{ public List<Double> getLatLong(String address){ return new List<Double>{0,0}; } } 09 10 11 12 13 public class MapQuestImpl implements GeocodeService{ public List<Double> getLatLong(String address){ return new List<Double>{1,1}; } }
  • 22. 01 02 03 04 05 06 07 08 09 public class Geocoder { private GeocodeService strategy; public Geocoder(GeocodeService s){ strategy = s; } public List<Double> getLatLong(String address){ return strategy.getLatLong(address); } } Geocoder GeocodeService strategies Client + Geocoder(GeocodeService) 1 +getLatLong(String) * +getLatLong(String) GoogleMapsImpl +getLatLong(String) 10 11 12 Geocoder geocoder = new Geocoder(new GoogleMapsImpl()); System.debug(geocoder.getLatLong('moscone center')); //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0) MapQuestImpl +getLatLong(String)
  • 23. 01 02 03 04 05 06 07 08 09 10 public class Geocoder { public static final Map<String,Strategy> strategies = new Map<String,Strategy>{'googlemaps' => new GoogleMapsImpl() ,'mapquest' => new MapQuestImpl()}; private GeocodeService strategy; public Geocoder(String name){ strategy = strategies.get(name);} public List<Double> getLatLong(String address){ return strategy.getLatLong(address); } } Geocoder GeocodeService strategies Client + Geocoder(String) 1 +getLatLong(String) * +getLatLong(String) GoogleMapsImpl +getLatLong(String) 11 12 13 Geocoder geocoder = new Geocoder('googlemaps'); System.debug(geocoder.getLatLong('moscone center')); //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0) MapQuestImpl +getLatLong(String)
  • 24. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Geocoder { public class NameException extends Exception{} public static final Map<String,GeocodeService> strategies; static{ GlobalVariable__c gv = GlobalVariable__c.getInstance('strategies'); List<String> strategyNames = new List<String>(); if(gv != null && gv.value__c != null) strategyNames = gv.value__c.split(','); strategies = new Map<String,GeocodeService>(); for(String name : strategyNames){ try{strategies.put(name,(GeocodeService)Type.forName(name+'impl').newInstance());} catch(Exception e){continue;} //skip bad name silently } } private GeocodeService strategy; public Geocoder(String name){ if(!strategies.containsKey(name)) throw new NameException(name); strategy = strategies.get(name); } public List<Double> getLatLong(String address){ return strategy.getLatLong(address); } }
  • 26. Question How do we extend the functionality of an sObject in Apex without adding new fields? Transient selection checkboxes Calculated Fields with Updates
  • 27. Solution – sObject Decorator (aka Wrapper Classes v2.0)
  • 28. Example - Scenario Weather sObject ▪ City__c ▪ TempInFahrenheit__c (in Fahrenheit) VisualForce Requirements ▪ Stored temperature in Fahrenheit is displayed in Celcius ▪ User enters Temperature in Celcius and is stored to the record in Fahrenheit Bi-directional Display and Calculation
  • 29. The Code – Decorated sObject Class 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class DecoratedWeather { public Weather__c weather { get; private set; } public DecoratedWeather ( Weather__c weather) { this.weather = weather; } public Decimal tempInCelcius { get { if (weather != null && tempInCelcius == null ) tempInCelcius = new Temperature().FtoC(weather.TempInFahrenheit__c); return tempInCelcius; } set { if (weather != null && value != null ) weather.TempInFahrenheit__c= new Temperature().CtoF(value); tempInCelcius = value; } } }
  • 30. The Code – Custom Controller 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 public class Weather_Controller { public List<DecoratedWeather> listOfWeather { get { if (listOfWeather == null) { listOfWeather = new List<DecoratedWeather>(); for (Weather__c weather : [ select name, temperature__c from Weather__c]) { listOfWeather. add(new DecoratedWeather(weather)); } } return listOfWeather; } private set; } }
  • 31. The Code – VisualForce Page 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <apex:page controller="weather_controller"> <!-- VF page to render the weather records with Ajax that only rerenders the page on change of the temperature --> <apex:form id="theForm"> <apex:pageBlock id="pageBlock"> <apex:pageBlockTable value="{!listOfWeather}" var="weather"> <apex:column value="{!weather.weather.name}"/> <apex:column headerValue="Temperature (C)"> <apex:actionRegion > <apex:inputText value="{!weather.tempInCelcius}"> <apex:actionSupport event="onchange" reRender="pageBlock"/> </apex:inputText> </apex:actionRegion> </apex:column> <apex:column headerValue="Temperature (F)" value="{!weather.weather.Temperature__c}" id="tempInF"/> </apex:pageBlockTable> </apex:pageBlock> </apex:form> </apex:page> No client side logic!!!
  • 32. Finally, on the VisualForce page
  • 33. Patterns 1. Singleton 2. Strategy 3. sObject Decorator 4. ?
  • 34. Billy Has a New Problem! Billy wrote a trigger to create an order on close of an opportunity, however: ▪ It always creates a new order every time the closed opportunity is updated ▪ When loading via Data Loader, not all closed opportunities result in an order
  • 35. The Offending Code 01 02 03 04 05 06 07 08 trigger OpptyTrigger on Opportunity (after insert, after update) { if (trigger.new[0].isClosed) { Order__c order = new Order__c(); … insert order } } Poor reusability Occurs regardless of prior state No Bulk Handling
  • 36. Any Better? 01 02 03 04 05 trigger OpptyTrigger on Opportunity (after insert, after update) { 01 02 03 04 05 06 07 08 09 10 11 12 13 public class OrderClass { new OrderClass().CreateOrder(trigger.new); } public void CreateOrder(List<Opportunity> opptyList) { for (Opportunity oppty : opptyList) { if (oppty.isClosed) { Order__c order = new Order__c(); Occurs regardless ... of prior state insert order; } } } } Not bulkified
  • 37. How’s this? 01 02 03 04 0506 trigger OpptyTrigger on Opportunity (before insert, before update) { if (trigger.isInsert) { new OrderClass().CreateOrder(trigger.newMap, null); else new OrderClass().CreateOrder(trigger.newMap, trigger.oldMap); 01 public class OrderClass { 02 03 public void CreateOrder(Map<Opportunity> opptyMapNew 04 Map<Opportunity> opptyMapOld) { 05 List<Order__c> orderList = new List<Order__c>(); 06 for (Opportunity oppty : opptyMapNew.values()) { 07 if (oppty.isClosed && (opptyMapOld == null || 08 !opptyMapOld.get(oppty.id).isClosed)) { 09 least it’s Order__c order = new Order__c(); At 10 ... bulkified 11 orderList.add(order); 12 } 13 } 14 insert orderList ; 15 } This code is highly coupled and not reusable
  • 38. Solution – Bulk Transition • • • Checks for eligible records that have changed state and match criteria Calls utility class method to perform the work Only eligible records are passed in • Generic utility class method that can be called from any context
  • 39. At Last!!! 01 02 03 04 05 06 07 08 09 10 11 trigger OpptyTrigger on Opportunity (after insert, after update) { if (trigger.isAfter && (trigger.isInsert || trigger.isUpdate)) { List<Opportunity> closedOpptyList = new List<Opportunity>(); for (Opportunity oppty : trigger.new) { if (oppty.isClosed && (trigger.isInsert || (trigger.isUpdate && !trigger.oldMap.get(oppty.id).isClosed))) closedOpptyList.add(oppty); } if (!closedOpptyList.isEmpty()) new OrderClass().CreateOrderFromOpptys(closedOpptyList) 01 02 03 04 05 06 07 08 09 public class OrderClass { public void CreateOrdersFromOpptys(List<Opportunity> opptyList) { List<Order__c> orderList = new List<Order__c>(); for (Opportunity oppty : opptyList) { Order__c order = new Order__c(); This method is now a lot ... more reusable and is bulkorderList.add(order); safe } insert orderList ; Trigger handles state transition
  • 40. Patterns 1. Singleton 2. Strategy 3. sObject Decorator 4. Bulk State Transition
  • 41. Resources Wrapper Classes - http://wiki.developerforce.com/page/Wrapper_Class Apex Code Best Practices - http://wiki.developerforce. com/page/Apex_Code_Best_Practices Apex Web Services and Callouts - http://wiki.developerforce. com/page/Apex_Web_Services_and_Callouts Sample Code - https://github.com/richardvanhook/Force.com-Patterns
  • 42. More at #DF13 Apex Enterprise Patterns: Building Strong Foundations Tuesday, November 19th: 12:15 pm - 01:00 pm - Moscone Center West – 2009 High Reliability DML and Concurrency Design Patterns for Apex Monday, November 18th: 11:15 am - 12:00 pm - Moscone Center West – 2009 Making Your Apex and Visualforce Reusable Tuesday, November 19th: 12:15 pm - 01:00 pm - Moscone Center West – 2022 Design Patterns for Asynchronous Apex Tuesday, November 19th: 05:15 pm - 06:00 pm - Moscone Center West – 2024 The Apex Ten Commandments Wednesday, November 20th: 04:00 pm - 04:45 pm - Moscone Center West - 2006 / 2008
  • 43. Speaker Name Speaker Name Dennis Thong, @denniscfthong Richard Vanhook, @richardvanhook
  • 44. We want to hear from YOU! Please take a moment to complete our session survey Surveys can be found in the “My Agenda” portion of the Dreamforce app