Monday, October 23, 2017

Tips for passing Data Architecture & Management Designer (SU'17)

Today (22nd Oct'2017), I have successfully passed Data Architecture and Management Designer (SU17) and acquired Salesforce certified Application Architect credential.

I have faced total 60 questions. Unlike Sharing and Visibility exam there are no additional questions. It has taken around 100 hours of preparation mostly one and half months time frame.






Exam Objective

The Salesforce Certified Data Architecture and Management Designer exam has the following characteristics:
  • Content: 60 multiple-choice/multiple-select questions* (2-5 unscored questions may be added)
  • Time allotted to complete the exam: 90 minutes (time allows for unscored questions)
  • Passing Score: 67%
  • Registration fee: USD 400, plus applicable taxes as required per local law
  • Retake fee: USD 200, plus applicable taxes as required per local law
  • Delivery options: Proctored exam delivered onsite at a testing center or in an online proctored environment. Click here for information on scheduling an exam.
  • References: No hard-copy or online materials may be referenced during the exam.
  • Prerequisite: None

Preparing myself

Before I started my preparation, I have prepared a document and noted down all the points and advice mentioned by these guys. Thanks to all of them.


Topics I have received on Exam


  • Strategies for data migration, data archieval
  • How to resolve timeout issues
  • Skinny table
  • PK Chunking
  • Use of Bulk API
  • Use of rollup summary
  • Different types of locking and how to overcome those
  • Master data management
  • Reports and Dashboards
  • Integration with external system
  • Validation rule, workflow rule, outbound message.
  • Indexing
  • Use of External Ids
  • Use of AppExchange product and third party ETL tool
  • Field History tracking
  • Metadata API.
  • Analytic snapshot.
By the way, Salesforce recommended training guide doesn't cover 100% areas of the exam. Around 10-15% of the questions were outside of the material which I could assume so far.



Sunday, October 8, 2017

Visualforce webservice callout synchronously & asynchronously

Overview

Recently we have received a business case to perform a webservice callout from our Custom Visualforce page.

There are following ways we can make callout from Visualforce page.
  • Asynchronously
  • Synchrounously

Approach: Asynchronous callout (@future method)


From visualforce page, first we will verify all standard and business validations and then perform callout and any error message during save will be displayed on the UI.

For example if Customer Name is blank if will show the error message in the UI and will not perform callout.

Visualforce

From commandbutton action, save method will get called.

<apex:page id="MyVisualforcePage" controller="MyController"  showHeader="false">
    <apex:pageMessages id="msgId"/>   
    <apex:form id="MyForm">
        <apex:inputText id="customerNm" value="{!CustomerName}"/><br/>
        <apex:commandButton value="Save" action="{!save}" reRender="msgId"/>
    </apex:form>
</apex:page>

Controller

In the save method, it will verify if customer name is blank and show the error in UI, otherwise call performRestCallout().


public class MyController
{
 public String CustomerName {get;set;}
 
 public PageReference save()
 { 
  if(String.isBlank(CustomerName))
  {
   ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.Error, 'Name cannot be null');
   ApexPages.addMessage(msg);
   return null;
  }
  else
  {
   //perpare JSON and then callout
   MyWebService.performRESTCallout(JSONString);
  }
  //navigate to view page
  PageReference pg =  (new ApexPages.StandardController (new CustomObject__c(Id=recordId))).view();
  pg.setRedirect(true);
  return pg;
 }
}

WebService Class

public class MyWebService
{
    @future(callout = true)
    public static void performRESTCallout(string JSONString)
    {
 //perform callout
    }
}

If any error messages from callout occurs that can be handled following ways:

(Taken from bob_buzzard's answer)

(1) Post a chatter message to the user
(2) Send an email to the user
(3) Create a custom object/setting, add the message to that and write a visualforce page for the sidebar that displays the message.


Approach: Synchronous callout (using commandbutton oncomplete method)


Salesforce doesn't allow to commit data and perform callout in a single transaction as it will throw error message "Uncommited task is pending".

The following approach works well.

From commandbutton's action, we will call save method, it will commit the data and then oncomplete method with the help of javascript and actionFunction we will perform second action and hence perform callout. So, there will be two different transactions and no more errors.

That looks good!!!

Now, what will happen if during save, UI validation and business validations to be performed and if any error occurs that needs to be shown on UI and will not perform oncomplete call.

Secondly, since it is synchronous call, so any exceptions or errors returned from webservice call must be displayed on the UI.

Here is the most tricky part (where I have spend hours to find the work around, finally Eric from StackExchange helped me retaining the error message in UI. My question & Eric's answer).

Visualforce

Here conditionally oncomplete needs to be called.


  • So hasError property has been defined on controller. 
  • Access hasError values in the outputPanel which is getting rendered from commandbutton reRender attribute
  • Using oncomplete javascript function, first verify if error exists (hasMessages == 'false') and then call submit action with the help of actionFunction.

Error will be displayed like this:



Thats nice!!!

<apex:page id="MyVisualforcePage" controller="myExampleController"  showHeader="false">
    <apex:pageMessages id="msgId"/>
    <script>
        function performCallOutMethod()
        {
            if(hasMessages == 'false') {
                performCallOut();
            }
        }
    </script>
    <apex:form id="myForm">
        <apex:actionFunction name="performCallOut" action="{!submit}" reRender="script-block,msgId"/>
        <apex:inputText id="customerNm" value="{!CustomerName}"/><br/>
        <apex:commandButton value="Save" action="{!save}"
                            oncomplete="return performCallOutMethod();" reRender="script-block,msgId"/>
    </apex:form>
 <!-- this is main trick -->
    <apex:outPutPanel layout="block" id="script-block">
        <script>
            var hasMessages = '{!hasError}';
        </script>
    </apex:outPutPanel>
</apex:page>

Controller

Save method will perform validations and then will commit the changes into database. If Customer name is blank then it will show error message.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class MyController
{
 public String CustomerName {get;set;}
 
 public Boolean hasError { 
  get { 
   return ApexPages.hasMessages(); 
  }  
 }
 
 public PageReference save()
 { 
         if(String.isBlank(CustomerName))
  {
          ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.Error, 'Name cannot be null');
   ApexPages.addMessage(msg);
   return null;
  }
                //commit all data here, not giving full code for simplicity.
                insert customObj;
  return null;
 }
 
 public PageReference submit()
 {
  try
  { 
   //prepare JSON string and perform callout
   MyWebService.performRESTCallout(JSONString);
   
   //navigate to view page
   PageReference pg =  (new ApexPages.StandardController (new CustomObject__c(Id=recordId))).view();
   pg.setRedirect(true);
   return pg;
  }
  catch (Exception ex)
  {
   System.debug('Error in submit ' + ex);
                        ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.Error, ex.getMessage());
                        ApexPages.addMessage(msg);
                        return null;
  }
 }
}

WebService Class

Just a simple method and if any error occurs it will be propagated to calling method and finally be displayed at UI.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class MyWebService
{
 public static void performRESTCallout(string JSONString)
        {
  try
  {
   MyWebService.performRESTCallout(JSONString);
  }
  catch(Exception ex)
  {
   throw new CustomException(ex.getMessage());
  }
 }
}

Conclusion



Which approach to be taken for implementation it will be based on business scenarios, data volumes, performance and that is a separate topic all together.

Here, I have tried to put my proof of concepts and approach to perform callouts from Visualforce and necessary error handling.

Hope it helps!