Nerd @ Work

When Salesforce is life!

[Salesforce / Interview Tips] Preparing for a job interview as a Salesforce Developer

 
Salesforce Developers possess a strong working knowledge of the platform and can add serious value to a business. But given the competitive talent market, you must be prepared to set yourself apart from your peers to really stand out during a job interview.

While job interviews can take many weird and wonderful formats, you should be prepared for two different types of questions during the interview. One will test your technical competency for the role, and the other will measure your experience and knowledge of CRM development in a commercial environment.

Technical questions during the interview

Firstly, the interviewer will want to get a grasp of your technical understanding of the Salesforce platform, so be prepared to answer questions around the architecture or processes involved in Salesforce development.

This can be slightly daunting, as you’re essentially being tested to see whether you really have the skills that are listed on your resume, but there’s no reason to be intimidated. If you’ve worked as a Salesforce Developer in the past, particularly if you’re certified, none of these questions should be outside your realm of understanding.

If you do struggle with a question, there’s nothing wrong with admitting you’ve never worked with that particular tool or concept before—the interviewer will appreciate your honesty, as some people would try to bluff it in this situation (and make themselves look silly in the process). You could even ask them about it, which would show you’re always looking to learn.

If you’re nervous about the kind of questions you may be asked during the interview, we have a resource that details technical interview questions for Salesforce Developers, based on our experience as a specialist Salesforce recruiter. It’s unlikely the interviewer will ask you something incredibly technical, but it’s nice to be prepared just in case.

Experience-driven questions during the interview

As well as what you know, the interviewer will also want to find out what you’ve done so far in your career, and how your experience makes you the perfect candidate for their job. How did you become a Salesforce Developer? What kind of projects have you worked on in the past? What has been the biggest challenge in your career so far and how did you overcome it?

The best way to prepare for this line of questioning is to revisit your portfolio and map out your entire learning journey. A small project you worked on three years ago could be incredibly useful for the task at hand, and so you should be prepared to recall what you did and why.

This is especially useful if you can map it against your education journey—how much did you know at that stage of your career and what would you do now that’s different? Base this around what you’ve learned, the training you’ve undertaken, and the certifications you’ve gained since then.

There’s also merit in talking about mistakes that have been made on projects in the past and how they impacted development. The fact you’ve identified these mistakes and now know better is a testament to the knowledge and experience of your role. Remember that experience is not inherently nominal—a developer with three years of experience who has worked on complex projects will be more valuable than a developer with five years of experience who hasn’t.

Five quick tips for interview preparation

To interview successfully, it isn’t all about having an answer for whatever question is thrown at you. There’s also an onus on you to do your research and find out exactly what will help you stand out in the context of the position you’re applying for. Consider the following:

  • Find out which Salesforce product/edition/instance the company is using — if you don’t know which product you’ll be working with, how can you convince the interviewer that you’re experienced enough to develop on it?
  • Find out what format your interview will take — some interviews are relatively informal chats, whereas some involve practical exercises such as development tasks or challenges. Clarify this before the interview to avoid being blindsided.
  • Focus on how taking this job would benefit both parties — as a Salesforce professional, you’re always looking to improve your career standing. If you can identify what it is about this particular company/role that will help you achieve your long-term career goals, telling this to the interviewer will showcase your ambition and drive.
  • Avoid using overly technical language — in some cases, your interviewer won’t actually have a strong knowledge of the Salesforce platform, and so speaking in technical terms won’t demonstrate your point the way you’d like to. Without being patronising, be prepared to communicate complicated concepts in simple language. This will also demonstrate your comprehensive understanding of the Salesforce platform.
  • Identify the company’s revenue streams and demonstrate how you can optimise them — while a company will value a lot of things, the bottom line is turnover. If you can demonstrate, based on experience, the value you can add to the business and the potential return on investment in you, the interviewer will start to see hiring you as an essential financial decision—you’ve become indispensable before you even sign the contract!
  • Preparation is key, but nobody is immune to a bad interview—sometimes you and the company simply won’t be a good fit, and this is fine. Whether successful or not, it will be valuable experience that you can take forward in your Salesforce journey, so don’t be discouraged if things don’t go to plan. Just remember to approach it with a level head and confidence in your ability. You have skills that this company needs, otherwise they wouldn’t have invited you in to interview in the first place!

[Salesforce] Dealing with the running User on Einstein Bot dialogs

 
As part of the Salesforce Solutions Team at WebResults I spend some time training myself on new products and trying to build POCs (prove of concepts) to give value to the training and promote the knowledge inside my company.

I recently was playing with Einstein Bots and got stuck when needed to identify the running user, when dealing with queries to get actual user info from the CRM.

I though it was enough to call the UserInfo.getUserId() method and I could get who is the user calling the bot, but unfortunately the running user of an Apex InvocableMethod is the AutomatedProcess user, that you can monitor from Setup > Debug Logs > User Trace Flags [New] as shown below:

I believe that Salesforce will add this feature in the next feature but I had to find a workaround.

The Workaround

I started a thread on Stackoverflow, where I got some ideas but no solution at all.

After a while I came up with a dirty solution that allowed me to know the exact user logged into the community. I won’t explain all the trial and errors but the whole solution, with some code samples.

Here is the list of actions:

  1. Enable Pre-Chat
  2. Override Pre-Chat with a Lightning Component
  3. The Pre-chat Lightning component calls its controller to get if there is a valid running user and returns back all the data needed for the prechat
  4. The Lightning component compiles all the needed inputs for the pre-chat (e.g. name, email and username) and submits for the chat: if the info are found, the component hides the pre-chat fields (that may be filled by a non authenticated user)
  5. The info submitted are written on the Transcript object
  6. An Einstein Bot dialog examines the Transcript object using an IncobaleMethod of an Apex class and determines which is the running user
  7. The bot can now change its behavior depending on the fact that the user is logged or not

To get all of this working you need 2 custom fields:

  • A custom field on the Contact/Lead record (we’ll call it Username__c) that is used to configure the prechat on the Snap-In
  • A custom field on the LiveChatTranscript object (we’ll call it Username__c as well) used to store the info got from the Pre-Chat component

Once fields are created, we need to setup the Pre-Chat page on the Snap-in settings related to the bot:

And setup the Pre-chat page:

Now let’s create the Lightning component that will replace the Snap-in chat (configured in the picture above):

prechat.cmp

For the what & whys plese refer to the official documentation in this link.

The component uses the lightningsnapin:prechatAPI that is needed to trigger the chat once the info are filled in.

<aura:component
    implements="lightningsnapin:prechatUI"
    controller="Bot_PreChatCmpCnt">
     
    <aura:attribute name="userId" access="PRIVATE" type="string" default="-"/>
    <aura:attribute name="firstName" access="PRIVATE" type="string" />
    <aura:attribute name="lastName" access="PRIVATE" type="string" />
    <aura:attribute name="email" access="PRIVATE" type="string" />
 
    <!-- Contains methods for getting pre-chat fields, starting a chat, and validating fields -->
    <lightningsnapin:prechatAPI aura:id="prechatAPI"/>
     
 
    <!-- After this component has rendered, call the controller's onRender function -->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
     
    <aura:renderIf isTrue="{!empty(v.userId)}">
        <lightning:input type="text" value="{!v.firstName}" label="Name *">
        <lightning:input type="text" value="{!v.lastName}" label="Lastname *">
        <lightning:input type="text"  value="{!v.email}" label="Email *">
         
        <lightning:button label="Start chat!" onclick="{!c.onStartButtonClick}"/>
    </aura:renderIf>
</aura:component>

The list of input fields are only shown when the v.userId attribute is blank (you can note that it is initialized with “-“, and in the lightning controller is blanked only when no logged user is found).

prechatController.js

The controller calls the Apex controller to get the main user info: if they are found, the chat is started.

({
doInit: function(component, event, helper) {
        var action = component.get("c.getCurrentUser");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var result = JSON.parse(response.getReturnValue());
                console.log(result, embedded_svc);
                component.set('v.userId', result.userId);
                if(result.userId){
                    component.set('v.firstName', result.firstName);
                    component.set('v.lastName', result.lastName);
                    component.set('v.email', result.email);
                    helper.startChat(component, event, helper);
                }
            }else if (state === "ERROR") {
                var errors = response.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        console.log("Error message: " +
                                 errors[0].message);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
        });
        $A.enqueueAction(action);
    },
    onStartButtonClick: function(component, event, helper) {
        //handling errors
        if(!component.get('v.firstName')
          || !component.get('v.lastName')
           || !component.get('v.email')) return alert('Missing fields.');
        helper.startChat(component, event, helper);
    }
});

prechatHelper.js

The startChat() method compiles the array of fields to be passed to the chat plugin, that will start the chat with the Bot.

({
     
    startChat: function(component, event, helper){
        var fields = [
            {
                label: 'FirstName',
                name: 'FirstName',
                value: component.get('v.firstName')
            } ,
            {
                label: 'LastName',
                name: 'LastName',
                value: component.get('v.lastName')
            }  ,
            {
                label: 'Email',
                name: 'Email',
                value: component.get('v.email')
            },{
                label: 'Username',
                name: 'Username__c',
                value: component.get('v.userId'),
            }
        ];
        if(component.find("prechatAPI").validateFields(fields).valid) {
            component.find("prechatAPI").startChat(fields);
        }
    }
});

prechatHelper.js

The Apex controller simply makes a query on the user object and considers it a loggedin user if the ContactId field is not null (but you can use your own conditions):

public class Bot_PreChatCmpCnt {
    @auraenabled
    public static String getCurrentUser(){
        Map<String,Object> output = new Map<String,Object>();
        User u = [Select Username, FirstName, LastName, Email, contactId From User Where Id = :UserInfo.getUserId()];
        if(u.ContactId != null){
            output.put('userId', u.UserName);
            output.put('firstName', u.FirstName);
            output.put('lastName', u.LastName);
            output.put('email', u.Email);
        }else{
            output.put('userId', '');
        }
        return JSON.serialize(output);
    }
}

That said we need to instruct the Pre-Chat plugin to write the fields on the LiveChatTranscript object, which is the only thing that grants the Bot’s dialogs to be aware of the running context. Create a new Static Resource and remember to set the Cache Control to Public.

embedded_svc.snippetSettingsFile.extraPrechatFormDetails = [
  { 
    "label":"Username", "transcriptFields":[ "Username__c" ],
  },{
    "label":"Cognome", "transcriptFields": ["LastName__c"]
  },{
   "label":"Nome", "transcriptFields": ["FirstName__c"]
  },{
   "label":"Email", "transcriptFields": ["Email__c"]
}];

This Static Resource must be configured in the Snap-in Component on the Community builder:

Einstein Bot Dialog Apex action

Last step, before configuring the bot, is to create a new Apex Class that will retrieve the users information coming from the current transcript:

public without sharing class Bot_GetSnapInsPreChatData {
    public class PrechatOutput{
        @InvocableVariable
        public String sFirstName;
        @InvocableVariable
        public String sLastName;
        @InvocableVariable
        public String sEmail;
        @InvocableVariable
        public String sContactID;
        @InvocableVariable
        public String sLoggedUser;
    }
    public class PrechatInput{
        @InvocableVariable
        public String sChatKey;
    }
    @InvocableMethod(label='Get SnapIns Prechat Data')
    public static List<PrechatOutput> getSnapInsPrechatData(List<PrechatInput> inputParameters)
    {
        System.debug('######## Input Parameters: '+inputParameters);
         
        String sChatKey = inputParameters[0].sChatKey;
        String sContactId = null;
        List outputParameters = new List();
        PrechatOutput outputParameter = new PrechatOutput();
        if (sChatKey != null && sChatKey != '')
        {
            List<LiveChatTranscript> transcripts = [SELECT Id, CaseId,
                                                    ContactId, Username__c
                                                    FROM LiveChatTranscript WHERE ChatKey = :sChatKey];
            if (transcripts.size()>0)
            {
                sContactId = transcripts[0].ContactId;
                outputParameter.sLoggedUser = transcripts[0].Username__c;
            }
        }
         
        if (sContactId != null && sContactId != '')
        {
            List<Contact> contacts = [SELECT Id, FirstName, LastName, Email, Username__c
                                      FROM Contact WHERE Id = :sContactId];
            if (contacts.size()>0)
            {
                outputParameter.sFirstName = contacts[0].FirstName;
                outputParameter.sLastName = contacts[0].LastName;
                outputParameter.sEmail = contacts[0].Email;
                outputParameter.sContactId = contacts[0].Id;
            }
        }
        outputParameters.add(outputParameter);
        return outputParameters;
    }
}

This class read the coming sChatKey value to query the LiveChatTranscript object that stores all the informations coming from the PreChat.

This LiveChatTranscript can be further manipulated to add more and more data for your context.

You must also define a hidden Bot variable containing the Live chat transcript key, that must be called LiveAgentSessionId (and is populated by the Live Agent engine automatically):

Now you can safely configure your dialog and be sure to know if the user is logged or not, and change the Bot behavior consequently:

[Salesforce] Top Winter19 Platform Release features

 

While the Winter ’19 Salesforce platform release rolls out,I want to introduce to you all Priscilla Sharon, Salesforce Business Solution Executive for DemandBlue, who will share with us here top Winter 19 release features.

DemandBlue is in the business of helping its customers maximize their Salesforce investment through predictable outcomes. As we thrive in an era of cloud-based Infrastructure, Platform and Software services, DemandBlue has pioneered “Service-as-a-Service” through a value-based On Demand Service model that drives bottom-line results. They foster innovation through “Continuous Engagement and On Demand Execution” that offers their customers Speed, Value and Success to achieve their current and future business objectives.

Their On Demand Services for Salesforce include Advisory, Development & Customization, Integration, Administration & Support, Maintenance, and Lightning Migrations.


It’s been a busy month for Salesforce. With the most awaited, world’s greatest tech conference, Dreamforce 2018 unveiling today and the launch of Winter ’19 Release, we are excited to bring you some of most amazing Salesforce Winter ’19 features that enable you to work faster and smarter with more Lightning features, Einstein Intelligence and a whole lore more.

Go on and take a sneak peek into our Top 12 most favorite Salesforce Winter ’19 Release features.

Also, check out the Salesforce Winter ’19 Release notes here.

Change Your View with Display Density Settings (Lightning)

This is one of most useful Salesforce Winter ’19 Features – Two new Lightning Experience display density settings give you more control of how you want to view data without changing the page layout. Select one of the settings as the default, but users can choose their own display density at any time from the user profile menu.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_lex_display_density.htm

Compact

Comfy

Say Goodbye to Copy and Paste and Hello to Quick Text (Lightning)

Copying and pasting content is time consuming and tedious. But now, you can say goodbye to Copy/paste with the newest Salesforce Winter ’19 features. Quick text is fast and easy—you can insert predefined messages into emails, tasks, events, chats, and more. To make quick text easier to use, we added more ways to insert quick text. Use a keyboard shortcut, a button in rich-text editor toolbars, like for email publishers, or a popup button next to supported text fields.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_general_quicktext_buttons.htm

Assign a New Owner to Multiple Leads, Cases, or Custom Objects at One Time (Lightning)

The Salesforce Winter ’19 Features enable you to use the Change Owner page-level button to assign a new owner for up to 200 selected leads, cases, or custom objects. You can access the button in the page-level action menu in a list view or related list in standard table mode, or in Related List Quick Links.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_lex_change_owner.htm

Recover Your Unsaved Text After Getting Timed Out (Lightning, App)

Sometimes your Lightning Experience session is interrupted, whether you’ve been inactive too long or you lost your connection. You used to see the same timeout message, regardless of how your session ended. Now, with the Salesforce Winter ’19 Features, the message that pops up is specific to your scenario and tells you how to recover unsaved text.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_lex_invalid_session_messages.htm

Find the Data You Need in a Jiffy with List View Search (Lightning)

Use the new search bar to search the field data in your list views and find the records you need in record time with the newest Salesforce Winter ’19 features.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_lex_search_lists.htm

Collaborate with Ease with List View Sharing (Lightning)

Have a list view with an amazing set of filters that you’d love to share with your team? Or maybe you have a list view that you only want a select few to access. The Salesforce Winter ’19 features allow you to take collaboration to the next level by sharing your list views with user groups in your org.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_lex_share_lists.htm

Add and Remove Meeting Participants from Any User Interface (Classic)

Attendees (in Lightning Experience) and invitees (in Salesforce Classic) are linked to the same data, so updating those fields should be simple. Now with the Salesforce Winter ’19 features, when you set up sales reps to work with attendees from Lightning Experience and the Salesforce app, they don’t lose access to edit invitees from Salesforce Classic.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_sales_productivity_edit_attendees_anywhere.htm

Send and Receive Images and File Attachments with SMS Text Messaging and Facebook Messenger (Lightning)

They say that a picture is worth a thousand words. The Salesforce Winter ’19 features allow Agents and customers to get straight to the point by sending images and files in an SMS message and Facebook Messenger.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_livemessage_send_and_receive_images.htm

Support Your Customers on YouTube (Lightning, Classic)

One of most amazing Salesforce Winter ’19 Release features is that you can now deliver service to your customers by turning their YouTube comments into cases in Salesforce. Connect your YouTube channel directly to Service Cloud, track cases, and respond directly to customers.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_scs_youtube.htm

Use Joined Reports as Source Reports for Dashboard Components (Lightning)

With a joined report as its source report, a dashboard component can contain data from multiple standard or custom report types. Or, you can provide multiple views of the same object using the Salesforce Winter ’19 features.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_rd_dashboards_source_joined_reports.htm

Give Supervisors a Sneak Peek into What Agents and Customers Are Typing in Chats (Lightning)

The Salesforce Winter ’19 features help supervisors stay on top of messages sent between agents and customers. Supervisors can see what an agent is typing before sending a message with the agent sneak peek feature. Customer sneak peek lets a supervisor see what customers are typing before they hit send.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_omnichannel_supervisor_sneak_peek.htm?edition=&impact=

Explore Data from Multiple Datasets in a Single Lens (Einstein Analytics – Lightning, Classic)

Sometimes the data you want to explore and visualize reside in different datasets. Don’t let that stop you from drilling into your data. With the Salesforce Winter ’19 features, you can now combine multiple datasets in a lens and discover insights about your business faster.

Ref.: https://releasenotes.docs.salesforce.com/en-us/winter19/release-notes/rn_bi_explorer_multiple_datasets.htm?edition=&impact=

To learn more about how you can take immediate advantage of the newest features and innovations, talk to our team!
What are your favorite Salesforce Winter ’19 Release features? Please feel free to share your thoughts in the comments section below.

[Salesforce DX / Data Fractory] Populate your Salesforce org with data using Forceea and Salesforce CLI: a step-by-step guide

 
Today’s post has been written by Nikos Mitrakis, the creator of Forceea, an amazing Data Factory Framework for Salesforce.

Some facts about Nikos:

  • Salesforce Developer at Johnson & Johnson EMEA Development Centre (EDC)
  • Started his Salesforce journey in 2014
  • Has passed 9 certifications, including Certified Application Architect
  • Holds a Physics degree
  • Leader of Limerick, Ireland Developer Group
  • Married since 1994, has a daughter
  • Loves watching sci-fi movies and good comedies
  • Lives in Limerick, Ireland

All posts by Nikos


So, you are an awesome Administrator, Developer, Consultant or Architect and you have your Scratch org, Developer Sandbox or Developer edition org ready for development, testing, training or a demo. But your org doesn’t have any data ☹, or it doesn’t have the data you want. What can you do?

Well, you have the following options:

  1. Use an ETL tool to move data from another Org or get data from CSV files.
  2. Use Salesforce CLI (Command Line Interface) using the commands sfdx force:data:tree:export and force:data:tree:import to export/ data from another Org and import the data (in JSON format).
  3. Develop a custom solution (Apex) to insert the records you need programmatically.
  4. Use a Data Factory to insert the required data.

The first (ETL) and second (CLI) solutions don’t need development skills, they may not be very difficult to configure (using CLI should be easier), and they let you populate your org with a specific set of records – if you really want this. The problem is that data requirements change very fast and if you have to continuously create manually the records you need in one org and then copy them to your org, this process will eventually be slow and time-consuming.

The third (Apex) solution gives you the maximum flexibility, but it’s time-consuming as well, not to mention the high level of technical knowledge it requires.

Now let’s see the fourth solution, the Data Factory. Using a Data Factory, you won’t have to write complex code or have advanced knowledge of an ETL tool. You’ll be able to easily generate and insert the records you need for any SObject and easily modify the process to adopt any new data requirements. Sounds interesting?

Stay with me as we’re going to implement such a data population project using Forceea (forˈsēa) data factory framework – this framework is an open source GitHub project (https://github.com/nmitrakis/Forceea). Keep in mind that the framework is perfect for a developer who wants to create records for the test methods, but that’s another story.

In this step-by-step guide we’ll assume that you have no programming knowledge! (you may be even a power Salesforce user). Ready to start? (Take a deep breath…)

Step 0: Prerequisites – Prepare your org

  • For Classic orgs: You have created a Sandbox or a Developer org.
  • For Salesforce DX Scratch orgs: you have created your scratch org.

For both Classic and DX, after the org creation you should have deployed your project’s metadata and set your org ready for the final data population.

Step 1: Install the Salesforce CLI

If you haven’t installed the Salesforce CLI, go to https://developer.salesforce.com/tools/sfdxcli, download the CLI for your system and install it. Accept the default settings and after a while your Salesforce CLI will be ready to run.

Step 2: Authorize your org

To use CLI, you need to authorize your org. To do this, open the Command Prompt window and execute the following command:

sfdx force:auth:web:login -r https://login.salesforce.com -a OrgAlias

Some comments here:

  • If you’re authorizing a sandbox, the instance URL will be https://test.salesforce.com.
  • You should replace OrgAlias with the alias of your org (choose one, e.g. sf1).

To verify that everything is fine, log into your org using the command

sfdx force:org:open -u OrgAlias

Step 3: Install Forceea

There are two ways to install Forceea.

Method 1: Go to https://github.com/nmitrakis/Forceea and click the following button:

You’ll be re-directed to the page:

  • If you install in a sandbox, select Deploy to: Sandbox. Otherwise, accept the default selection (Production/Developer).
  • Click the Login to Salesforce button (on the right corner) and give your credentials.
  • Then click Allow to give the tool the access to your org. You are redirected to a new page where the From GitHub Repository section lists the details of Forceea URL and the To Salesforce Org section the details of the target org. Click the Deploy button (on the right corner).
  • After a few seconds you’ll see the message Deployment Complete at the bottom of your page.

Method 2: Go to the GitHub repository https://github.com/nmitrakis/Forceea and click Clone or Download.

Click Download ZIP. After a few seconds the Forceea-master.zip will have been downloaded. Unzip the zip file and you will find the metadata folder, which contains

  • the src folder, with a folder with each metadata component and the package.xml
  • the dx folder, with the Salesforce DX components
  • a build.properties file
  • a build.xml file

The easiest way to regularly use Forceea is to include its metadata into your Repository (either classic or DX metadata). Then you can deploy it with your project’s metadata.

Step 4: Create the Forceea scripts

What are Forceea scripts?

Forceea uses a language (Sample Data Definition Language – SDDL) to describe the “nature” of the required data. A script is a set of commands. Let’s see an example, which creates and inserts opportunities:

FObject obj = new FObject('Opportunity', 100);
obj.setDefinition('Name', 'static value(Opp-)');
obj.setDefinition('Name', 'serial type(number) from(1) step(1) scale(0)');
obj.setDefinition('AccountId', 'random lookup(Account) field(Industry) value(Chemicals,Construction) source(salesforce)');
obj.setDefinition('Amount', 'random type(number) from(1000000) to(10000000) scale(-3)');
obj.setDefinition('StageName', 'random type(picklist)');
obj.setDefinition('CloseDate', 'random type(date) from(2017-01-01) to(2017-12-31)');
obj.setDefinition('Forceea__c', 'static value(xJio9!23)'); // ** create this field **
obj.insertRecords(true);

If the above commands look like Apex statements, you’re right, they are Apex statements, but you may forget it for the moment! The above script will insert 100 Opportunity records with:

  • Name: Opp-1, Opp-2, .., Opp-100
  • Account: any account for which the Industry is “Chemicals” or “Construction”
  • Amount: a random integer from 1M to 10M, round to 1000 (e.g. 9,252,000)
  • Stage: any picklist value
  • Close date: any date from 1 Jan. 2017 to 31 Dec. 2017

A field definition begins with obj.setDefinition and has two text parameters:

  • The field API name, e.g. Amount or AccountId
  • The SDDL definition, e.g. random type(number) from(1000000) to(10000000) scale(-3) or random type(picklist).

Finally, we insert the created records using obj.insertRecords(true). The parameter true means that it is all or nothing, so if any error happens, no records will be inserted.

The framework has many cool features:

  • Creates records for standard or custom objects, for any standard or custom field.
  • Automatically defines required fields.
  • Can create data for fields of every data type: Integer, Currency, Double, Date, Datetime, Time, Boolean,
    String, TextArea, Percent, Reference, Email, Phone, URL, Base64, Picklist and MultiPicklist.
  • Handles record types and field dependencies (dependent picklists).
  • Supports record groups for inserting and deleting records.
  • Validates the definitions based on the field data type.
  • Can be used for in test methods or for populating Salesforce orgs with sample data for demos and User
    Acceptance Testing (UAT).
  • Has an extended error messaging system.
  • You can get a lot of script examples from http://bit.ly/Forceea131_Examples and download the User Guide from http://bit.ly/Forceea131_UserGuide.

    Write your own scripts

    Now you know what is a Forceea script, let’s see how you can write the scripts for your specific needs. To do this, use the following template:

    FObject obj = new FObject('SObject_API_Name', Number_of_records);
    FObject.seed = 1;
    <field definitions>
    obj.insertRecords(true);
    

    where are one or more SDDL field definitions, like the previous definitions we used to create a script for Opportunity records.

    The seed is very important when you want to create the same random records every time. For example, when you populate a Scratch org with sample data, we may want each developer to have the same (but random) set of records. Forceea uses its own engine to create random data (generally called Pseudo-random Number generator – PRNG), which you can control.

    Now, let’s suppose you want to populate your org with Account and Opportunity records. This means that first you must create records for accounts and then for opportunities (an opportunity is related to an account, that’s why we insert accounts first).

    Accounts

    Open your favourite text editor (I use VSCode) and create a script using the above template. Your script may look like:

    FObject obj = new FObject('Account', 100);
    FObject.seed = 1;
    obj.setDefinition('RecordTypeId', 'static value(BigAccount)');
    obj.setDefinition('Name', 'static value("Company ")');
    obj.setDefinition('Name', 'serial type(number) from(100) step(1) scale(0)');
    obj.setDefinition('NumberOfEmployees', 'random type(number) from(10) to(1000) scale(-1)');
    obj.setDefinition('AnnualRevenue', 'random type(number) from(10000000) to(100000000) scale(3)');
    obj.setDefinition('Rating', 'random type(picklist) except(Hot)');
    obj.setDefinition('Phone', 'random type(phone) format("(30) 210 dD-00-DD")');
    obj.setDefinition('Industry', 'random type(picklist)');
    obj.setDefinition('Type', 'random type(list) value(Prospect, Customer - Direct, Customer - Channel)');
    obj.setDefinition('Site', 'random type(url)');
    obj.setDefinition('ShippingStreet', 'random type(street) group(shipping)');
    obj.setDefinition('ShippingPostalCode', 'random type(postalcode) group(shipping)');
    obj.setDefinition('ShippingCity', 'random type(city) group(shipping)');
    obj.setDefinition('ShippingState', 'random type(state) group(shipping)');
    obj.setDefinition('ShippingCountry', 'random type(country) group(shipping)');
    obj.insertRecords(true);
    

    Even though we don’t have the space here to describe every SDDL definition of the above script, I’d like to mention the first field definition for field RecordTypeId (if you use record types, modify the definition with the API name of your record type instead of BigAccount, otherwise delete this line) and the address definitions ShippingStreet, ShippingPostalCode, etc (where you get real addresses from United States).

    You may think that these definitions are difficult, but most of them are obvious and easy to understand. So, back to our script for the Account SObject, give it the name Accounts.apex and save it into your preferred folder (let’s call it ForceeaScripts).

    Opportunities

    Now it’s time to create the Opportunities.apex file with the script for the Opportunity SObject. Follow the previous procedure and write a script like the example I gave you above.

    Keep in mind that Forceea will try to automatically find the required fields and generate a field definition for them but, as a rule of thumb, you should always create your definitions for all required fields.

    Record Deletion

    When you create records, you probably want to repeat this procedure again, and replace the existing set of data with another set with different or the same field values. To do this, you probably want to delete the existing inserted records before you insert the new ones. This is the responsibility of the Record Deletion files.

    First, we’ll delete the opportunities we created. Follow these steps to configure it:

    • Create a new text file, call it delete-opportunities.apex and save it in the ForceeaScripts folder.
    • Write this script in the file:

      String flag = 'xJio9!23';
      List<Opportunity> records = [SELECT Id FROM Opportunity WHERE Forceea__c = :flag LIMIT 5000];
      delete records;
      

    You’re right! At first sight these commands may look difficult if you are not a developer, but they aren’t really hard to understand if you follow these instructions:

    • Line 1: You may select your own (random) value, like xJio9!23 – but don’t forget to enclose it in single quotation marks
    • Line 2: Find a filed you don’t use, which has a Text data type or create your own text field and call it Forceea__c. Here I use the latter, because I couldn’t find any available (not used) standard field on the Opportunity SObject.

    Now go to the opportunities.apex file and add the following line before the command obj.insertRecords(true); :

    obj.setDefinition(Forceea__c', 'static value(xJio9!23)');

    As you can see, we set the field definition for the field Forceea to be our static value xJio9!23. Do the same for the Account SObject, creating the file delete-accounts.apex with the following commands:

    String flag = 'xJio9!23';
    List<Account> records = [SELECT Id FROM Account WHERE Tradestyle = :flag LIMIT 5000];
    delete records;
    

    In Line 2, I suppose the TradeStyle text field is not used in your org, so you may use it here. Else, you should create a new field as previously.

    Go to the accounts.apex file and add the following line before the command obj.insertRecords(true); :

    obj.setDefinition('TradeStyle', 'static value(xJio9!23)');

    Be careful! The above scripts will delete up to 5,000 records, so if you have more records you have 2 options:

    • Increase LIMIT 5000 up to 10000 (e.g. LIMIT 8000)
    • Execute the delete-accounts.apex again (you may use it as many times as you want)

    That’s it! Now you have 4 files into your ForceeaScript folder:

    • account.apex
    • opportunities.apex
    • delete-accounts.apex
    • delete-opportunities.apex

    For your convenience, I have created these files in a zipped file, which you can download from http://bit.ly/ForceeaWithCLI.

    You may use these files for your training. I suppose you should modify them if you want to use them in a production system (with specific requirements for the field values), but you’ll probably need no modifications if you execute them in an out-of-the-box Developer/Scratch org.

    Step 5: Execute your scripts

    The last step is to execute the scripts and insert the created records. Create a new text file, call it execute-scripts.bat and save it in the ForceeaScripts folder (I included it in the above zipped file).

    In this file you’re going to insert the CLI commands which execute the *.apex files you created previously.

    If you use Windows, your execute-scripts.bat file will look like:

    sfdx force:apex:execute -f .\delete-opportunities.apex -u OrgAlias
    sfdx force:apex:execute -f .\delete-accounts.apex -u OrgAlias
    sfdx force:apex:execute -f .\accounts.apex -u OrgAlias
    sfdx force:apex:execute -f .\opportunities.apex -u OrgAlias

    where orgAlias is the alias for your org you defined in Step 2.

    If you’re using a Mac, each command may look like:

    sfdx force:apex:execute -f /Users/Username/Documents/ForceeaScripts/accounts.apex -u OrgAlias

    When you write your Forceea scripts (e.g. your script in the accounts.apex file), you may have errors to correct. For example, you may have misspelled a field’s API name or your SDDL definition may have a syntax error (a very common source of errors is the effect of the Validation Rules and Triggers). Fortunately, the framework has an extensive debug log, with detailed error messages (see the User Guide, pages 44 – 50). You can activate these debug logs, if you insert the command obj.setVerbose(‘info’) or obj.setVerbose(‘debug’) after the first command of your accounts.apex or opportunities.apex script files.

    I suggest you initially execute your script files one by one.

    • If you already have inserted records, first execute the two delete-object files. Copy the “delete” commands from your execute-scripts.bat to your Command Prompt window and execute them. Then verify that records have been deleted successfully.
    • Copy the “insert” commands from your execute-scripts.bat file to your Command Prompt window and execute them one by one, verifying that records have been inserted successfully.
    • When you have verified that everything works as expected, you may just execute your batch file in the Command Prompt window: > execute-scripts.bat (Window users)

    If you are a Mac user, you could use a similar batch execution or just simply copy all commands of the execute-scripts file to the Command Prompt window and execute them at once.

    Because of this process, all lines of the execute-scripts file will be executed sequentially, each on its separate execution context. This is very important, since it will allow each sfdx force:apex:execute command to be executed on its own Governor Limits.

    Optional Step 6: Execute multiple scripts for the same SObject

    You may ask: Why create multiple script files for the same SObject? Well, we just mentioned that each script file (*.apex) is executed by the Salesforce CLI having its own limits. There are a lot of limits, but when you insert records you’re going to hate a limit called “Maximum CPU time on the Salesforce servers”, which is 10,000 ms (that is 10 seconds). In practise this limit may not allow you to insert more than 200 records in a complex implementation (with triggers, many validation rules and so on) or even no more than 50 records!

    So, let’s suppose that you try to insert 2,000 opportunities but the insertion fails because of this limit. What is the process you should follow?

    1. Try to execute the script file (sfdx force:apex:execute -f .\opportunities.apex -u OrgAlias) using 100 records, i.e. FObject(‘Opportunity’, 100)
    2. If your execution is successful, double the records (200), if not set the number of records to half (50).
    3. Follow the same logic, increasing or decreasing the number of records, to find an optimal maximum value. Take into consideration that Salesforce doesn’t always need the same time to execute your script, so it’s better to set a value less than the absolute maximum.

    For example, suppose that you find you can insert up to 250 records. It’s safer to decrease this by 10% and set 225 records.

    • Because you want to insert 2,000 records, but each script file will insert 225 records, you need to create 9 script files. The first 8 files will insert 225 records each and the last one will insert 200 records (225 * 8 + 200 = 2,000 records).
    • The second line of each script file contains the seed number (FObject.seed = …). Here we have something new: we’re going to use different seed numbers for the same SObject. You may use whatever numbers you want or something like 1,2,3, etc. So, the first file will have FObject.seed = 1, the second FObject.seed = 2, etc. Why do we set different seed values? If we don’t, Forceea will create the same (but random) values in each execution for this SObject (same Close dates, same Amounts, etc), something we don’t want at all! Of course, you may omit the seed command if you don’t want to have the same values whenever you execute your scripts.
    • Another important note is this: if you use seed numbers you should always delete the previously created records, unless the same seed number is never used again. For example, if you insert the 2,000 records using seeds from 1 to 9, if you insert new records using a seed between 1 and 9, these new records will be the same as some already created records (something BAD). So, you must use a new seed number (e.g. 10) or delete the records you inserted before inserting new ones.
    • Each script file may have the same or different field definitions. It’s up to you to decide what kind of data you want.
    • And a last tip: if any of your definitions uses the serial command (e.g. serial type(number) … in the Opportunity.apex), first insert the command obj.createRecords(numberOfNextrecord); before the final line obj.insertRecords(true); where numberOfNextrecord is the number of the next record to be inserted. For example, in the first script file it will be createRecords(1), in the second createRecords(101), in the third createRecords(201), etc – under the assumption that you insert 100 records in each script file. If you follow this tip, all inserted records will have a continuous serial number!

    Conclusion

    Congratulations! You finally managed to reach at the end of this step-by-step guide. I hope I convinced you that Forceea with Salesforce CLI will make your life much easier. After you create the set of your script files, you can automate the creation of all your SObjects using a unique batch file. CLI will execute your batch files line by line, creating and inserting your records, with each execution with new Limits (which is fantastic!!)

    It will be great to have your feedback after your try to create a few scripts in a Sandbox or Developer org. And don’t hesitate to send an email with any questions or issues you may have.

[Salesforce / Release Management] YOU SHALL NOT PASS! (Unless you pass the Quality Gates)

 

What happens if, once you learned how to walk, you start to run?

Well, you might stumble and fall.

Depending on how well you react you might get a bruise or a bloody nose.

What happens if you have a tool that can increase the speed of your releases?

Well, you might run into some issues upon releases.

Depending on if you are using version control, you might recover your work or not.

But from a project management perspective the main question is:
How do I avoid stumbling, falling and having a discussion about delivery capabilities with project stakeholders (aka “those who pay the bills”)?

Starting from the running example, we probably stumble because we do not control the movement at some point. Maybe, because we did not practice walking long enough or because the floor was uneven and “surprised” us. In any case, it is because we lost control.

Believe it or not, it’s similar in software development: If you lose control over what happens in your process ( = movement) you can damage the product you deliver.

We have learned how to “walk” with Copado in the first post of this series, we outlined how all team members contribute to an efficient movement in the second one, and started to “run” in the third post.

So before we even come close to falling, let’s talk about how to maintain control and achieve reproducible and predictable release outcomes.

Our final goal is to achieve that German thing everyone once in a while mentions: Quality.
(Hehe, World Cup 2018, that will stick for a while)

Quality gates are not there to annoy – they are a safety net

Working with Copado and having a seamless integration with Git in the background, we avoid a worst case scenario (fall on your face and damp the hit with your forehead) as we always have a way to roll back to a stable version.

But the process we introduced also contains two review points, which is something no release process should miss:

  • A review of your developments from a technical perspective by a peer or a lead developer. This will ideally prevent devs from introducing sketchy solutions and you get to keep your job.
  • A review of your developments from an end user perspective (Test). This will make sure end users don’t complain, and you get to keep your job.

There is a reason both steps are manual:

First of all, as of now, no AI will be able to understand how and why you developed your features. If a robot could review your code, then admit it, a robot can write your code and a lot of us would be out of business.

Also it is to ensure personal accountability for approvals, so people take it seriously.

If you work in an agile project environment the technical and business review might be detailed as a Definition of Done (DoD, aka “the list of things you need to accomplish to burn the story points”). A sample DoD can look like the following list:

  • Document your feature
  • Get peer approval
  • Ensure business test script is available
  • Deploy to QA
  • Test and approve story by business

So wouldn’t it be nice to tie the technical capability to move a feature to the next environment and release it based on the completion of your DoD/Quality Gates?

Validation rules & history tracking to save the day

Before we jump into any config work, let’s get an overview of what we need and what elements (fields, automations) Copado offers already:

DoD Element

Required

Available

To Configure

Document your feature

Field to indicate document location

Yes, but not in the way we would like it.

Create hyperlink field.

Validate, that the field is not empty.

Get peer approval

Field to indicate approval

Yes, but we don’t jump into pull requests. Maybe later. Start small now.

Create Checkbox.

Validate, that the field is checked.

Ensure business test is available

Indicator for approved test script

Yes.
But I would like to automate the checkbox, and also, I don’t like the current name.

Create Checkbox on User Story to indicate approved scripts.

Update the field on an approved test script.

Validate, that the field is checked.

Deploy to QA

Indicator for current org of a feature

Automated by Copado

Nothing to do.

Test approved by business.

Indicator for approved tests.

Yes, but the automation needs to be configured.

Create Checkbox on User Story to indicate a successful test.

Update the field upon a successful test execution..

Validate, that the field is checked.

To sum up, in order to implement our quality gates we need:

  • 4 fields
  • 4 validation rules
  • 2 processes

And to make sure we can track who changed the checkboxes, we will set Feed Tracking on all of them, so that we see a nice history of DoD on the chatter feed related to the User Story. Also we need to modify the layout to make sure fields are displayed.

Create the required fields

Starting with the fields, we create the following custom fields on the Copado User Story object:

  • PeerReviewPassed__c, Checkbox
  • TestScriptReady__c, Checkbox
  • TestScriptPassed__c, Checkbox
  • DocumentationLocation__c, URL

For those who need a deeper explanation, click here.

Ensure accountability through history tracking

Next, we will enable those fields in Feed Tracking (Setup → Customize → Chatter → Feed Tracking → User Story). Enable the Object Field tracking if required, and select the fields we just created. Add more fields, if you consider them worth tracking. Status is always a good one.

Enforce process adherence with validation rules

Next, we need to tackle the validation rules.

As explained in the first post, a user story is deployed to the next environment, when the “Promote & Deploy” checkbox is checked. Also, it can be selected for a manual promotion if you check the “Promote Change” checkbox. So our validation rules should fire in the following logic:

  • If the story is still in the Dev environment, fire when:

    • “Promote & Deploy” or “Promote Change” is checked
    • Documentation Location is empty
    • Peer Review Passed is unchecked
    • Test Script Ready is unchecked

  • If the story is in the UAT environment, fire when:

    • “Promote & Deploy” or “Promote Change” is checked
    • Test Script Passed is unchecked

Modify the layout to make it easy for users to follow

We added a lot of fields, so let’s make it better to manage for the end user and modify the layout. Copado has already some fields, which we do not use in our cases, such as Documentation Complete, because they are not entirely for the case (also it’s about showing what can be done, right?).

However, there is a field called “Apex Tests Passed”. It’s a checkbox and it is set automatically, if you hit the “Run Apex Tests” button on the story, and the classes in your User Story have sufficient coverage. Also, there is already a section called “Definition of Done”. We will just remove unwanted and add our new fields.

Looks nice, and has a certain logic. Let’s check the validation rule:

Perfect.

We are done here, so the only thing left is to set up the process builder automations and go for an after work drink with colleagues and/or friends.

Reduce redundant clicks with process builder

The key here is to fit into the Copado approach a little to get our automations started. Our favorite release management tool assumes, that a test script might not necessarily be written by a single developer, but also by a larger team, where a test script review process can be part of a test script creation. (Yes, those testers again…).

In order to indicate, that a test script is ready, the status needs to be marked as “Complete”. And that’s all the details we need, in order to create a process builder:

  • Object: Test Script (copado__Test_Script__c)
  • Event: On record creation or update
  • Conditions: Status equals Complete

As an immediate action, we want to update a record related to the record, which triggered the process. The object we want to update is the User Story, and the field we want to set is the Test Script Ready field, which should be checked ( = TRUE).

What we also could do is to set the status of the story accordingly (e.g. “Ready for Testing”), but that is not required for now.

For automating the check of the “Test Run Passed” object, we will create a different, but similar process.

  • Object: Test Run (copado__Test_Run__c)
  • Event: On record creation or update
  • Conditions: Status equals “Passed” or “Passed with Comments”

The immediate action, in this case, would need to update the Test Script Passed field on the related story. So it is more or less the same as for the process created before, just the target field changes to “Test Script Passed” = TRUE.

Done. Well, you should test it, of course 🙂

Try that with Jenkins. Or Bamboo. Or TeamCity.

Gosh, I love this tool.

That’s all nice, but what else could you do?

Although this is a rather simple scenario, it will help already any user to follow the process, although they did not study the process before intensively. Simply by setting up the tool correctly to support what we outlined with boxes and arrows and providing information on how to proceed.

We can now easily check on DoD status of stories with list views or reports to find gaps. If someone asks “Who approved this?” we just need to check the list of chatter posts generated by Salesforce. If we now start to discuss User Stories using the Chatter Feed, your team will be best buddies with any internal project audit initiative.

Going a step further, validation rules can help to cover more complex scenarios, e.g. allowing to validate, but not to deploy to a specific org.

And if your project has issues with code quality, a code analysis tool can be an enabler for your code review. Copado has a build in support for an open source framework to analyze Apex (PMD) but if your team is using CodeScan or Checkmarx for analyzing code, I have been told that CodeScan will be available in the next version (Copado v12) and Checkmarx integration is on the roadmap.

For those who want a more structured technical review process, Copado can be set up to mirror pull requests as records linked to the User Story, so with a checkbox, a process builder and a validation rule you would be able to prevent deploying stories, if a PR has not been passed yet.

I am aware that following a release process sometimes is annoying for developers, but there are good reasons for certain checks and why to perform them, even though the change seems small.

But thanks to tools like Copado following the required steps is a breeze and automating repetitive field updates or notifications, you can ensure frictionless releases.

[Salesforce] Mason Frank Salary Survey 2019 Edition: how to increase your earning potential in Salesforce

 
Given the rate at which Salesforce has grown over the last five years, sometimes it can be difficult for professionals to get a measure of where they fit into the ecosystem and what they are worth. What’s more, it’s important to be aware of what Salesforce’s vast user base is saying about the technology, so you can decide how to move forward in your career based on product adoption and patterns in the market.

The Mason Frank Salary Survey is the largest annual independent study of the Salesforce community. It is an invaluable resource for Salesforce professionals, partners, and customers looking to gather insights into the working culture of the technology ecosystem, and to benchmark salaries, benefits and market trends.

Here is a selection of findings from the 2018/19 survey report, with context on what this means for you as a Salesforce professional and how you can use the information to better your career standing.

An Italian in Salesforce

While commentary on Salesforce usually focuses on the USA and UK, the ecosystem extends all across Europe. Professionals working in Italy will be pleased to learn that their salaries are in line with the industry standard and, in some cases, are higher than one would expect in other major European countries.

For example, a junior-level technical/functional consultant in Italy can expect to earn around €34,000, which is the same as in the Netherlands, but €1,000 more than in Spain. However, it’s substantially lower than in Germany, where a junior technical/functional consultant can expect to earn around €62,000. If you’re willing to travel to find a new permanent contract, Germany would be a good place to look!

Specialist roles are very well paid in Italy. A junior-level Technical Architect can expect to earn around €40,000, which is €6,000 higher than in France. Solution architects are also clearly in high demand, as a junior-level profession of this specialism can earn up to €76,000. For perspective, a junior-level solution architect in the UK earns in the region of £60,000, which converts to around €68,000.

Which Salesforce product is the most in-demand?

One of the more exciting elements of working with Salesforce technology is the way the platform keeps evolving by developing new and innovative solutions for businesses around the world. The downside of this for Salesforce professionals is that if you don’t catch wind of industry trends, you can soon be left behind.

Salesforce is ultimately a sales-centric platform, so it may come as no surprise to learn that the most popular standalone Salesforce product is still Sales Cloud—82% of respondents to the Mason Frank Salary Survey reported proficiency in Sales Cloud, compared to Service Cloud (63%), Community Cloud (44%), and Marketing Cloud (31%).

The popularity of Sales Cloud shows no signs of dwindling, with 52% of respondents indicating that Sales Cloud was the most in-demand product over the last year. Despite being the least prominent of the major Salesforce products, Marketing Cloud was predicted to be the most in-demand product over the next 12 months. This could be attributed to Salesforce’s recent acquisition of Mulesoft, which will make it easier than ever to harness and utilize customer data across multiple Salesforce products.

Where do Salesforce professionals work?

With Salesforce being a cloud-based CRM, the ability to access data online makes it far easier to find remote permanent and contract roles. Despite this, 89% of respondents to Mason Frank’s salary survey were employed on a permanent, full-time basis. It’s an interesting finding given the value and accessibility of the contract market in Salesforce.

Salesforce is the world’s number one CRM for a reason, and there is a substantial number of businesses around the world now utilizing products from the Salesforce business suite. In fact, 50% of all respondents indicated they work for an end user/Salesforce customer, with 41% working for a partner.

What is the experience level of the average Salesforce professional?

Experienced Salesforce professionals are in high demand, with employers always on the hunt for skilled and experienced pros to lead projects and implementations. The majority of professionals working in the ecosystem have between zero and six years of experience; 37% reported 0–3 years’ experience, while another 37% reported 4–6 years of experience. Only 6% of respondents to the Mason Frank study have over 10 years of experience on the Salesforce platform. If you are one of these professionals, you are part of a very exclusive group!

Are you a Trailblazer? If so, what rank are you? Did you know that around 22% of Salesforce professionals hold more than 100 Trailhead badges? This demonstrates the success and growth of Trailhead, given that just 9% of respondents to Mason Frank’s salary survey last year reported holding over 100 badges.

As well as Trailhead, Salesforce professionals have also embraced the technology’s certification structure, with 77% of respondents to the survey now holding at least one certification. As you would expect, the most popular certification is the entry-level Salesforce Certified Administrator credential, while just 6% were a Marketing Cloud Certified Email Specialist.

If you are not yet certified, you may be interested in learning that 39% of respondents reported an increase in salary after gaining certification. This could be a fantastic way to increase your earning potential, particularly as 75% of certified respondents reported that their employer contributed to the cost of certification—it’s an even better investment if you’re not paying for it!

What to take from this information

We can take several things from these findings. Firstly, becoming a Sales Cloud expert is a safe bet—it’s the most popular standalone Salesforce product by far, and given its dominance in the CRM market, it’s never going to go away.

By contrast, Marketing Cloud is predicted to be the most in-demand product over the next 12 months, and given that only 6% of respondents were a Marketing Cloud Certified Email Specialist, this could well be a niche worth exploring if you haven’t yet settled on a specialism.

If you are already deep into your Salesforce career, always be mindful of how much your experience is worth. Download Mason Frank’s 2018/19 Salesforce salary survey in full for a detailed exploration of salaries, sorted by location, role, technology, and level of experience.

[Salesforce / Release Management] Automation for the win!

You hate manual tasks and you are working on a Salesforce.com implementation? Then get a pen, a piece of paper and install & set up Copado.

Why Copado? Because it’s a great solution to manage releases of and with Salesforce.

Why pen and paper? Because it’s a great and versatile tool for drawing your current process and highlighting automation possibilities.

Things are ok. But can we make it better?

A couple of weeks ago, we have installed and set up Copado to manage our release process.

Committing to and deploying based on Git version control turned out to be easier and more secure than working with change sets (finally you can track who screwed up your stuff and restore it).

Next, we took some time to think about the people involved in an implementation, and how projects can work better as a team to release faster and better.

So now, as our team is aligned and everyone has confidence in the process, during the retrospective, the team decided to further improve the process and automate some of the steps.

  • Avoid manual step after deploying a custom setting to change endpoints
  • Ability to commit and deploy dashboards with running users, because it is just annoying
  • Mitigate bad development practices hard coding IDs
  • Send a notification to testers, once a user story is in the test environment

Deploy the same, but different

There are items in software development, which need to be modified based on your environment. Typical cases are integration endpoints, which change depending on if you want to connect to a development, test, or production instance of e.g. SAP. In Salesforce, you can add further items to the list, like IDs, if you want to exept an admin profile users from a validation rule. You can hardcode it as part of the formula (bad, think about kittens and unicorns) or you can put the ID in a custom setting, which is better, but still requires a manual step after deployment, updating the setting record in the target org.

Here is where Copado can help you to automate those steps with the concept of Environment Variables.

If this is too technical and not emotional enough, we will get rid of any manual changes related to hard coded IDs or URLs. Regardless if they are part of a Custom Setting, Validation Rule, Visualforce Page or Class. Believe me.

How does it work?

If you define a specific string, Copado will recognize it and translate it to a variable name, which you define. And upon deployment, it will replace the variable with the string you defined for your target.

Setup Environment Variables

In our case, we will set up an enVar (Environment Variable) for an endpoint, a user and the Admin profile Id.

  1. Get a clear view on your current unique strings. A table works best. Feel free to use pen and paper, if you like.

  2. In Copado, go to your active Deployment Flow, and click on the “Manage Environment Variables” button.
  3. Create a new Variable with the name you prefer. To keep an overview, I prefer to use a naming convention: elementType_usageOrItem
  4. Populate the string per environment or copy&paste from your table to Copado.

Follow the same steps for the other strings, and you will end up with something like this:

Use Environment Variables

So, let’s go ahead and deploy those items. The running dashboard user is part of the xml file, so it’s ok if we just commit it. The same is valid for hard coded IDs in classes or validation rules. However, the custom setting is stored in a record, so it needs to be handled differently.

  1. Create a Copado User Story.
  2. Go to “Commit Changes”, select the dashboard, underlying report, endpoint custom setting (in case it is not deployed yet) and the validation rule with a hardcoded Id.

  3. Provide a commit message, and click on “Commit Changes” to finish the process.
    Take your time to review the commit and see, if items have been added to Git as expected. On the dashboard, you will see that the Running User tag has been replaced with the variable name. The same happened with the Id in the Validation Rule.

  4. Ok, so commit is done, but we still need to account for the custom setting. On the User Story, scroll down to the “Deployment Tasks” related list and create a new task: after deployment, type: “Custom Setting”, select your setting, and click on “Get Custom Setting Values”
  5. Once you have the list, select the setting records you need, and save the step.

Well, this is the moment!

Will it work, will it deploy and replace?

Check the “Promote & Deploy” checkbox on the story to see Copado Magic at work.

Deployment Done.

Log into UAT.

A quick check…

All items were resolved. Perfectly!

Apart from deploying the custom setting, Copado has moved the setting entry, and exchanged the URL in the Target field correctly.

The Id in the Validation rule was replaced:

The Dashboard in UAT has the expected CEO running user:

As Copado applies this mechanism to all files, with a single entry we can account for hard coded IDs or URLs in all Salesforce Metadata, including visualforce pages or classes.

Process Automation

Ok, now the deployment is done, the user story is in UAT, and although we don’t have to update IDs, we still need to notify the tester that the story is now available for review.

Easy, because we are working on the Force.com platform, and Copado provides all the information required.
When a story is deployed to the next environment, the Field is updated by Copado automatically (Dev1 → UAT in this case). Also, there is a Test-Script Owner field on the Story, which is linked to a user record.

In technical terms: We have a DML operation and an email on a lookup parent record, so we have tons of options.

Which salesforce automation tool do you prefer? We can use Workflows, Process Builder, and Apex to fire an email to the user story tester or to a generic email address of the test team.

But email? This is so SAP. What about a chatter message instead?! Process it is.

Create a new Process on Creation or Edit of the story record, to fire for all Stories where:

  • The “Test Script Owner” field is not empty (Test Script Owner → User Id).
  • The “Environment Name” field equals “UAT” (Environment → Environment Name).

Next, create an immediate action of type “Post to Chatter”.

To get the notification right, you only need to consider, that @mentions from process builder require square brackets: @[ mergeFieldOfAUserId ]

If you cannot find the Chatter action on the User Story, enable it for the User Story object in Setup → Feed Tracking.

From now on, when we deploy a user story to UAT, there will be a chatter message on the record and the tester will get notified too (also via email, depending on the settings).

Copado & Force.com: A lot of value for little time invested

Now you might want to know how much time and effort it really takes to set up this type of automations.

To be honest, it took me longer to go through all environments and get the correct values than to set up the environment variables. But in most cases, projects have this information as part of their org-refresh steps documentation.

The main “difficulty” setting up the process was getting the @mention syntax (you are welcome 🙂 ) and improve on some type-os.

It is so incredibly easy to automate even complex scenarios that I set up another action for user stories in UAT to get ahead of my team requirements: Run all unit tests in UAT. But not as part of a deployment, because it’s too easy and this might slow down the deployment. Instead, it should happen after the deployment is finished successfully.

The only thing to do here is to create another condition in our Process (Environment = UAT), and create an action of type “Apex”.

Copado provides a set of helpful methods, which can be triggered in Apex or from the Process Builder, and the one we pick is “Invoke Run All Apex Tests for an Org”. As a parameter, we provide the Org Credential Id of the user story.

Now all apex tests will be run, once a story is successfully in UAT.

Done. It took longer to write about it, than to actually set it up.

One platform. A lot of possibilities

Usually, the tools for committing, deploying, tracking/managing stories and testing are separated. But Copado puts all of it on the highly flexible Force.com platform, so that users can tweak it how they like.

  • Automatic deployments to Stage once testing is done? Create a Process Builder to check “Promote & Deploy” once there is a successful test execution record.
  • A nightly validation deployment of all stories in Stage to Prod, just to check if there would be any issues? Well, you would need Apex to bundle the user stories and fire the deployment. Basically Query & create records.
  • Auto-execute regression testing after a deployment? Record your Selenium Script and add it to be executed after deployment to a certain environment.
  • You can even go crazy, read the information on committed metadata and auto-deploy only if less critical items such as Report Types have been committed. Dev to Prod including a sync back to Dev2 and the only human intervention would be the commit process (include an approval on QA though. We still have to follow the process, and you don’t want testing to be mad at you).

    If this is too technical, and too little emotion, maybe this explains better how it feels now to release features:

[ORGanizer Sponsorship Program] Panaya joins the ORGanizer sponsors family

 

#SalesforceOhana greet our brand new ORGanizer sponsor Panaya!


Panaya - A powerful solution for admins and developers to understand the scope and impact of planned changes and ensure risk free Salesforce deployment


Admins and developers with complex orgs, lots of custom and third-party components, and their related inter-dependencies, struggle to understand the scope and impact of planned changes.

With Panaya Release Dynamix gain a full view of change dependencies and usage statistics so that you can understand the impact of all code developed before going to production.

With automatically generated tests, based on an analysis of the chosen components and a list of related testing entry points, Release Dynamix for Salesforce helps to ensure safe deployment to production.

Panaya will keep company to you in the next months on the ORGanizer main page.!


If you are interested in joining the program, leave a message on the ORGanizer Sponsorship Program form.

May the Force.com be with you all!

Mason Frank 2018 Salesforce Salary Survey is OPEN!

 

Have your say on the Salesforce community!

The annual Mason Frank salary survey is now open and waiting to hear from Salesforce professionals like you.

The survey examines the salaries, benefits, market trends, and developments across the entire ecosystem, combining the anonymous thoughts and input from members of the Salesforce community, as well as info from Mason Frank’s customers.

For anyone working with Salesforce, this is a valuable resource, and your input helps to make the survey as accurate and reflective of the community as possible. Last year just under 4,000 people responded to the survey, further proof that Salesforce professionals care about the community their part of!

It takes about 15 minutes to complete, and there’s a chance to win an iPad, a Nespresso Pixie, or a Google Home device too.

The results of the survey will be released at Dreamforce 25–28 September 2018, but if you can’t make it, the full report will be available to download shortly after the event.


Have a read at last year Italian Salesforce market analysis post for 2017 MasonFrank Salary survey.

5 ways to command a higher salary in the Salesforce ecosystem

 
Are you looking to increase your Salesforce salary? Chris Thompson from Salesforce recruiter Mason Frank International gives his top five tips to maximize your earnings in the Salesforce ecosystem.


Salesforce is the number one CRM platform in the world, powering small and large companies with its expansive suite of business products. Given the popularity of this technology, the demand for qualified Salesforce professionals has never been higher and, as a result, the Salesforce Ohana has never been more valuable.

But how do you go about getting that all-important pay rise?

As a specialist Salesforce recruiter, Mason Frank knows exactly what employers are looking for on a resume, what makes you a stronger candidate at face value, and what you can do to increase your salary in your current job role.

Here are our five tips for commanding a higher salary in the thriving Salesforce ecosystem.

Become an expert in a niche or focused industry

Salesforce is a technology that services a huge range of industries, and branches even further when taking into account the many individual Salesforce products and modules. One way to make yourself an in-demand asset, and a high earner as a result of that, is to refine your skillset to such a degree that you are considered the authority in a specific niche.

Who does a toothpaste manufacturer go to when they need someone to manage their email marketing campaigns? Who does a large energy supplier go to when they need to train their huge workforce to navigate a custom Sales Cloud build? Everybody has an area of focus and expertise, and if you can find yours, you could earn a lot of money out of it.

Get Salesforce certified

Salesforce certifications not only endorse you as a talented Salesforce professional, but also offer the opportunity to enhance your knowledge of a specific area of the Salesforce platform. Some employers have unique build projects, and as such require specific certifications when recruiting. Others won’t even consider a candidate unless they have at least an ADM201 Salesforce Admin Certification.

The only downside of Salesforce certification is that the training and exam fees can be somewhat costly. If you’re fairly new to the Salesforce ecosystem and are looking for a way to gain three fully funded Salesforce certifications, you should check out our Mason Frank Tech Academy. We offer expert training to prepare you for your certification exam, and even give you hands-on experience working for Salesforce Partners—a great route into the Salesforce ecosystem that will automatically increase your potential earnings.

Compare your salary to the industry average

One of the simplest ways to highlight that you deserve to be paid more is to compare your wage to the industry average. Find an independent study on Salesforce salaries and use it in your next performance review to leverage a pay rise. Our Salesforce Salary Survey contains remuneration statistics from major countries across the globe, and even breaks some countries down by region and state, so you can see what you should be earning based on your local economy.

Become a contractor

Given the scope of Salesforce implementation and development projects across the globe, sometimes it makes no sense for a business to take on a permanent staff member to administer its CRM; this is where it pays to be a contractor.

If you are an expert in your field, geographically flexible, and have excellent project management skills, becoming a contractor is a serious option for you. Not only is the complexity of your work taken into consideration with your salary, but also the need for you to pick up and temporarily relocate, and all the rigmarole that comes with it. This equates to huge earnings. Check out our salary survey to compare permanent and contract rates for your job role—some Salesforce daily rates are eye-watering.

Grow your personal brand and become an influencer

Salesforce is a very community-driven ecosystem, and there is a lot of merit in sharing your knowledge to enrich your peers. This will not inherently increase your billable value as a Salesforce professional, but the networking element of this is invaluable, especially if you use your position of influence to work with partners and ISVs to develop, release, and promote new Salesforce products.

Your motivation should always be to enhance the Salesforce community, and you may even be given recognition for your hard work by being awarded Salesforce MVP status. The Salesforce Ohana is set up in such a way that the more you pay into it, the more you will get out of it, which is a great deal for dedicated Salesforce professionals who plan on enjoying a career in the ecosystem.

So to leave you with five simple things you can do today to increase your earning potential:

  • Identify a focused career path and work to become the go-to professional in that niche.
  • Pursue Salesforce certification, utilizing free training and support.
  • Use independent salary research as a benchmark when negotiating.
  • Become a contract worker.
  • Leverage your blog or social media to increase your visibility in the Salesforce community.

Page 1 of 17

Powered by WordPress & Theme by Anders Norén