SlideShare a Scribd company logo
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

More Related Content

What's hot

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
Salesforce Developers
 
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
Salesforce Developers
 
Modeling and Querying Data and Relationships in Salesforce
Modeling and Querying Data and Relationships in SalesforceModeling and Querying Data and Relationships in Salesforce
Modeling and Querying Data and Relationships in Salesforce
Salesforce Developers
 
Deep Dive into Apex Triggers
Deep Dive into Apex TriggersDeep Dive into Apex Triggers
Deep Dive into Apex Triggers
Salesforce 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 data
Salesforce Developers
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security Model
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
Salesforce Developers
 
Salesforce integration best practices columbus meetup
Salesforce integration best practices   columbus meetupSalesforce integration best practices   columbus meetup
Salesforce integration best practices columbus meetup
MuleSoft Meetup
 
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
Salesforce Developers
 
Apex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsApex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong Foundations
Salesforce Developers
 
Understanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We DoUnderstanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We Do
Salesforce Developers
 
Salesforce Integration Pattern Overview
Salesforce Integration Pattern OverviewSalesforce Integration Pattern Overview
Salesforce Integration Pattern Overview
Dhanik Sahni
 
Salesforce Integration
Salesforce IntegrationSalesforce Integration
Salesforce Integration
Joshua Hoskins
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce Org
Salesforce Admins
 
Development Best Practices
Development Best PracticesDevelopment Best Practices
Development Best Practices
Salesforce Partners
 
Salesforce CPQ
Salesforce CPQSalesforce CPQ
Salesforce CPQ
Jade Global
 
Introduction to Apex for Developers
Introduction to Apex for DevelopersIntroduction to Apex for Developers
Introduction to Apex for Developers
Salesforce Developers
 
Sales Cloud Lightning Migration Best Practices (May 12, 2017)
Sales Cloud Lightning Migration Best Practices (May 12, 2017)Sales Cloud Lightning Migration Best Practices (May 12, 2017)
Sales Cloud Lightning Migration Best Practices (May 12, 2017)
Salesforce Partners
 
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
Salesforce Developers
 

What's hot (20)

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
 
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
 
Modeling and Querying Data and Relationships in Salesforce
Modeling and Querying Data and Relationships in SalesforceModeling and Querying Data and Relationships in Salesforce
Modeling and Querying Data and Relationships in Salesforce
 
Deep Dive into Apex Triggers
Deep Dive into Apex TriggersDeep Dive into Apex Triggers
Deep Dive into Apex Triggers
 
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
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security Model
 
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
 
Salesforce integration best practices columbus meetup
Salesforce integration best practices   columbus meetupSalesforce integration best practices   columbus meetup
Salesforce integration best practices columbus meetup
 
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
 
Apex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsApex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong Foundations
 
Understanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We DoUnderstanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We Do
 
Salesforce Integration Pattern Overview
Salesforce Integration Pattern OverviewSalesforce Integration Pattern Overview
Salesforce Integration Pattern Overview
 
Salesforce Integration
Salesforce IntegrationSalesforce Integration
Salesforce Integration
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce Org
 
Development Best Practices
Development Best PracticesDevelopment Best Practices
Development Best Practices
 
Salesforce CPQ
Salesforce CPQSalesforce CPQ
Salesforce CPQ
 
Introduction to Apex for Developers
Introduction to Apex for DevelopersIntroduction to Apex for Developers
Introduction to Apex for Developers
 
Sales Cloud Lightning Migration Best Practices (May 12, 2017)
Sales Cloud Lightning Migration Best Practices (May 12, 2017)Sales Cloud Lightning Migration Best Practices (May 12, 2017)
Sales Cloud Lightning Migration Best Practices (May 12, 2017)
 
Salesforce crm projects
Salesforce crm projects Salesforce crm projects
Salesforce crm projects
 
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
 

Similar to Apex Design Patterns

Visualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsVisualforce Hack for Junction Objects
Visualforce Hack for Junction Objects
Ritesh Aswaney
 
Building Visualforce Custom Events Handlers
Building Visualforce Custom Events HandlersBuilding Visualforce Custom Events Handlers
Building Visualforce Custom Events Handlers
Salesforce Developers
 
Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Detroit ELEVATE Track 2
Detroit ELEVATE Track 2
Joshua 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 SmartStore
Salesforce Developers
 
Force.com Friday : Intro to Apex
Force.com Friday : Intro to Apex Force.com Friday : Intro to Apex
Force.com Friday : Intro to Apex
Salesforce 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 Capture
John 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, 2013
Salesforce Developers
 
ELEVATE Advanced Workshop
ELEVATE Advanced WorkshopELEVATE Advanced Workshop
ELEVATE Advanced WorkshopJoshua Birk
 
Event Driven Integrations
Event Driven IntegrationsEvent Driven Integrations
Event Driven Integrations
Deepu 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 SDK
Salesforce 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 JSQCP
Salesforce Developers
 
Apex enterprise patterns
Apex enterprise patternsApex enterprise patterns
Apex enterprise patterns
Amit Jain
 
Solving Complex Data Load Challenges
Solving Complex Data Load ChallengesSolving Complex Data Load Challenges
Solving Complex Data Load Challenges
Sunand P
 
ELEVATE Paris
ELEVATE ParisELEVATE Paris
ELEVATE Paris
Peter Chittum
 
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
モダンなイベント駆動型システム連携を学ぼう〜Platform Events 入門
Salesforce Developers Japan
 
Finding Security Issues Fast!
Finding Security Issues Fast!Finding Security Issues Fast!
Finding Security Issues Fast!
Salesforce Engineering
 
Get ready for your platform developer i certification webinar
Get ready for your platform developer i certification   webinarGet ready for your platform developer i certification   webinar
Get ready for your platform developer i certification webinar
JackGuo20
 

Similar to 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 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!
 
Get ready for your platform developer i certification webinar
Get ready for your platform developer i certification   webinarGet ready for your platform developer i certification   webinar
Get ready for your platform developer i certification webinar
 

More from 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 Developers
Salesforce 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 Components
Salesforce Developers
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer Highlights
Salesforce 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 India
Salesforce 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 Development
Salesforce 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 Components
Salesforce 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 Components
Salesforce Developers
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer Highlights
Salesforce Developers
 
Live coding with LWC
Live coding with LWCLive coding with LWC
Live coding with LWC
Salesforce 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 Salesforce
Salesforce 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 Capture
Salesforce Developers
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DX
Salesforce Developers
 
Get Into Lightning Flow Development
Get Into Lightning Flow DevelopmentGet Into Lightning Flow Development
Get Into Lightning Flow Development
Salesforce 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 Connect
Salesforce Developers
 
Introduction to MuleSoft
Introduction to MuleSoftIntroduction to MuleSoft
Introduction to MuleSoft
Salesforce Developers
 
Modern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesModern App Dev: Modular Development Strategies
Modern App Dev: Modular Development Strategies
Salesforce Developers
 
Dreamforce Developer Recap
Dreamforce Developer RecapDreamforce Developer Recap
Dreamforce Developer Recap
Salesforce Developers
 
Vs Code for Salesforce Developers
Vs Code for Salesforce DevelopersVs Code for Salesforce Developers
Vs Code for Salesforce Developers
Salesforce Developers
 
Vs Code for Salesforce Developers
Vs Code for Salesforce DevelopersVs Code for Salesforce Developers
Vs Code for Salesforce Developers
Salesforce Developers
 
Manage Massive Datasets with Big Objects & Async SOQL
Manage Massive Datasets with  Big Objects & Async SOQLManage Massive Datasets with  Big Objects & Async SOQL
Manage Massive Datasets with Big Objects & Async SOQL
Salesforce Developers
 

More from 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
 
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
 
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
 
Vs Code for Salesforce Developers
Vs Code for Salesforce DevelopersVs Code for Salesforce Developers
Vs Code for Salesforce Developers
 
Vs Code for Salesforce Developers
Vs Code for Salesforce DevelopersVs Code for Salesforce Developers
Vs Code for Salesforce Developers
 
Manage Massive Datasets with Big Objects & Async SOQL
Manage Massive Datasets with  Big Objects & Async SOQLManage Massive Datasets with  Big Objects & Async SOQL
Manage Massive Datasets with Big Objects & Async SOQL
 

Recently uploaded

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 

Recently uploaded (20)

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 

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