SlideShare a Scribd company logo
1 of 45
Download to read offline
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

Introduction to apex code
Introduction to apex codeIntroduction to apex code
Introduction to apex codeEdwinOstos
 
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
 
Lwc presentation
Lwc presentationLwc presentation
Lwc presentationNithesh N
 
Introduction to External Objects and the OData Connector
Introduction to External Objects and the OData ConnectorIntroduction to External Objects and the OData Connector
Introduction to External Objects and the OData ConnectorSalesforce Developers
 
Integrating with salesforce
Integrating with salesforceIntegrating with salesforce
Integrating with salesforceMark Adcock
 
Episode 10 - External Services in Salesforce
Episode 10 - External Services in SalesforceEpisode 10 - External Services in Salesforce
Episode 10 - External Services in SalesforceJitendra Zaa
 
Apex Trigger in Salesforce
Apex Trigger in SalesforceApex Trigger in Salesforce
Apex Trigger in SalesforceCloud Analogy
 
Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...
Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...
Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...CLTConsultingService
 
Salesforce integration with Box.com, docuSign & QuickBooks made easy
Salesforce integration with Box.com, docuSign & QuickBooks made easySalesforce integration with Box.com, docuSign & QuickBooks made easy
Salesforce integration with Box.com, docuSign & QuickBooks made easySaxon Global inc
 
Documenting Your Salesforce Org by Nik Panter
Documenting Your Salesforce Org	 by Nik PanterDocumenting Your Salesforce Org	 by Nik Panter
Documenting Your Salesforce Org by Nik PanterSalesforce Admins
 
Why Flow with Salesforce Flow
Why Flow with Salesforce FlowWhy Flow with Salesforce Flow
Why Flow with Salesforce FlowAjeet Singh
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelSalesforce Developers
 
Lightning Components Introduction
Lightning Components IntroductionLightning Components Introduction
Lightning Components IntroductionDurgesh Dhoot
 
Making External Web Pages Interact With Visualforce
Making External Web Pages Interact With VisualforceMaking External Web Pages Interact With Visualforce
Making External Web Pages Interact With VisualforceSalesforce Developers
 
Business Process Mapping for Salesforce Admins
Business Process Mapping for Salesforce AdminsBusiness Process Mapping for Salesforce Admins
Business Process Mapping for Salesforce AdminsSalesforce Admins
 
Sap integration salesforce_presentation
Sap integration salesforce_presentationSap integration salesforce_presentation
Sap integration salesforce_presentationSalesforce Deutschland
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce OrgSalesforce Admins
 
Getting started with Salesforce security
Getting started with Salesforce securityGetting started with Salesforce security
Getting started with Salesforce securitySalesforce Admins
 

What's hot (20)

Introduction to apex code
Introduction to apex codeIntroduction to apex code
Introduction to apex code
 
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
 
Lwc presentation
Lwc presentationLwc presentation
Lwc presentation
 
Introduction to External Objects and the OData Connector
Introduction to External Objects and the OData ConnectorIntroduction to External Objects and the OData Connector
Introduction to External Objects and the OData Connector
 
Introduction to Apex Triggers
Introduction to Apex TriggersIntroduction to Apex Triggers
Introduction to Apex Triggers
 
Integrating with salesforce
Integrating with salesforceIntegrating with salesforce
Integrating with salesforce
 
Development Best Practices
Development Best PracticesDevelopment Best Practices
Development Best Practices
 
Episode 10 - External Services in Salesforce
Episode 10 - External Services in SalesforceEpisode 10 - External Services in Salesforce
Episode 10 - External Services in Salesforce
 
Apex Trigger in Salesforce
Apex Trigger in SalesforceApex Trigger in Salesforce
Apex Trigger in Salesforce
 
Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...
Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...
Oracle Cloud ERP Report and Analytics | What are Cloud ERP reporting Options ...
 
Salesforce integration with Box.com, docuSign & QuickBooks made easy
Salesforce integration with Box.com, docuSign & QuickBooks made easySalesforce integration with Box.com, docuSign & QuickBooks made easy
Salesforce integration with Box.com, docuSign & QuickBooks made easy
 
Documenting Your Salesforce Org by Nik Panter
Documenting Your Salesforce Org	 by Nik PanterDocumenting Your Salesforce Org	 by Nik Panter
Documenting Your Salesforce Org by Nik Panter
 
Why Flow with Salesforce Flow
Why Flow with Salesforce FlowWhy Flow with Salesforce Flow
Why Flow with Salesforce Flow
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security Model
 
Lightning Components Introduction
Lightning Components IntroductionLightning Components Introduction
Lightning Components Introduction
 
Making External Web Pages Interact With Visualforce
Making External Web Pages Interact With VisualforceMaking External Web Pages Interact With Visualforce
Making External Web Pages Interact With Visualforce
 
Business Process Mapping for Salesforce Admins
Business Process Mapping for Salesforce AdminsBusiness Process Mapping for Salesforce Admins
Business Process Mapping for Salesforce Admins
 
Sap integration salesforce_presentation
Sap integration salesforce_presentationSap integration salesforce_presentation
Sap integration salesforce_presentation
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce Org
 
Getting started with Salesforce security
Getting started with Salesforce securityGetting started with Salesforce security
Getting started with Salesforce security
 

Similar to 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
 
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 webinarJackGuo20
 

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 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 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
 
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
 
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
 

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
 
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 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
 
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
 
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
 

Recently uploaded

Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
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
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
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
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024SynarionITSolutions
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
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
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 

Recently uploaded (20)

Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
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
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
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
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
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...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 

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