Monday, 3 January 2022

2021 Year in Review - Part 3

July

Another month, another new (and virtual) event. The first Consultancy Dreamin' took place on the Hopin platform. In a change of pace for me, I was looking after a cohort of speakers rather than running any sessions myself. I was also (and somewhat unexpectedly, as I'd missed the training session) facilitating a couple of panel sessions, which was great fun. Usually at these events I just have to worry about getting myself somewhere at the right time and not messing up my demo - it's a very different experience organising others, especially once the EMEA and US aspects of the event started to overlap!

July also saw my personal favourite event for the London Salesforce Developers - Discover a lightning fast way to debug in Salesforce with RFLIB. I've long been convinced that platform events are a great way to decouple automation from database transactions, and this is an excellent use of them.

The Salesforce acquisition of Slack finally went through, although it felt like it had already happened some time before. Almost simultaneously, a bunch of Trailhead badges for Slack went live and the hunt to get them all started up again. It wasn't all unicorns and rainbows though, as the Times New Express reminded us of the Salesforce execs that had departed to this point in 2021.

August

Salesforce launched Salesforce+ - the first (and only?) enterprise software company streaming service. While I've done some gentle mocking of this (here and here), I do think it's a great idea. It was also good to see Salesforce trying something different on the event front, albeit still trapped in front of a screen!

I reviewed Ahsan Zafar's book on Salesforce Data Architecture and Management - a good book tackling a tricky subject. Remote working was also something I was spending a lot of time thinking about, with particular reference to returning to something like normality.

An old friend, and former leader, of the London Salesforce Developers - Anup Jadhav - returned to tell us all about OmniStudio. This was an extremely well attended session, second only to Erika McEvilly's trigger session that kicked the year off. 

September

Dreamforce was back. Sort of. The events around the world had disappeared and San Francisco was now 1,000 attendees over 2 days, but it did happen and people were there. It was streamed on Salesforce+ rather than trying to recreate the physical event on a virtual platform, which made a bit of a change, but still kept us in front of our screens. The London Salesforce Developers had another virtual virtual watch party, but we were seeing the numbers drop as people were becoming zoomed out.  This chart of our attendance figures shows the decline - it was slow, but definitely heading down aside from the occasional event.

for this reason we'd decided to go back in-person in October. Exciting times!

Related Posts 

Sunday, 2 January 2022

2021 Year in Review - Part 2


The lockdown locks before and after!

April

Lockdown finally started to ease in the UK, with non-essential retail starting to open up and overnight stays away from home allowed again. Outdoor mixing was allowed, but with a maximum of six people from two households, so we didn't feel it made a lot of sense to move the London Salesforce Developers back in person just yet.  My fellow co-organiser, Amnon Kruvi, gave a well attended virtual talk on the Salesforce Security Review. Judging by the questions, there are clearly a lot of future ISVs among our members.

The rumour mill suggested that Salesforce were committed to an in person Dreamforce in 2021, which turned out to be accurate, although calling what happened Dreamforce seems a bit of a stretch when only a small number of people from the US were allowed to attend. I guess it was important to be seen to be holding it, but it's hard to agree with "Dreamforce is an annual event that brings together the global Salesforce community" when the vast majority of said community have to watch on a streaming platform.

Summer 21 Pre-release signups opened up, reminding us that we are never more than a few months away from a Salesforce release.

I also reviewed Tameem Bahri's book: Becoming a Salesforce Architect - I liked it then and I still like it now!

May

While you might never be more than a few months away from a Salesforce release, when it's May you also appear to be at the most risk of an outage, and 2021 continued the trend with a DNS issue. While the issue took the trust site down, it was good to see Salesforce continue to send people there to maximise their frustration. Why limit yourself to unhappy customers when you can turn them incandescent with rage?

Paul Battisson joined the London Salesforce Developers to tell us how to improve the performance of our Apex code by turning it up to 11.

Continuing with the performance theme, this month also saw the publication of one of my most popular blogs of the year - The Impact of System.Debug, which garnered close to 3,500 views, several comments and a new Apex PMD rule!

June

After 15 months without letting any scissors near me, the lockdown locks finally went, freeing me up from several minutes of grooming every week and raising over £500 for charity. They'd provided a lot of pleasure for a lot of people, mostly in the form of pointing and laughing, but their day was done.

The Summer 21 release hit production, and Salesforce published the root cause analysis of this year's instalment of the May outage. There was a new Event Bus on the way, with talk of a new pub/sub API. Six months later there's a few references to a pilot and a guide, but the marketing seems to have been dialled right down. Shades of Evergreen/Functions maybe?

Although countries were starting to open up, the virtual events kept coming, with the trailheadx developer conference. Scheduled with an eye on San Francisco local time, the near to 5pm start wasn't ideal for those of us in the UK, so I mostly caught up on the content over the next couple of months. Mostly, because the London Salesforce Developers ran a viewing party for the keynote, where we all joined a video call to watch a keynote on video. Very meta. To ensure everyone paid attention we had a word hunt, where spotting common terms from Salesforce keynotes (awesome, 1-1-1, you know the kind of thing) earned swag. An unexpected side effect of this was the entertainment of people joining an hour into the session and hoping they were the first to hear 'awesome'. Entertaining for me, as I wasn't running the competition!

Dreamforce was announced as a series of in-person events around the world, although everything outside of San Francisco quietly disappeared over the next few months. 

Related Posts

2021 Year in Review - Part 1

Wednesday, 29 December 2021

2021 Year in Review - Part 1

London's Calling Caricatures - 1 year and zero haircuts apart

London's Calling Caricatures - 1 year and zero haircuts apart

2021 began in the UK as we spent quite a bit of 2020, in lockdown (Lockdown 3, just when you thought it was safe to go inside someone else's house again) and doing everything over videoconference, which was starting to get a bit samey. 

January

Those of us that had submitted London's Calling presentations heard back, and I was relieved to see that I'd made the cut. 

The London Salesforce Developers held two events in January - the first for the graduation of another round of Speaker Academy candidates, and the second for Apex Trigger Essentials courtesy of my fellow co-organiser Erika McEvilly. The combination of Erika and starting from the ground up with triggers clearly resonated, as we had a record 163 signups for this event. 

I made a bold, and incorrect, prediction that there wouldn't be an in person Dreamforce in 2021. I got it right that Salesforce wouldn't bring 100k+ people to San Francisco from all over the world, but got it wrong that they'd be happy with a 5k event.

February

The Spring 21 release of Salesforce went live, including an update that corrected the CPU tracking for flows - this is enforced in the Summer 22 release, so if you haven't tested with the new behaviour the clock is ticking. As as the tradition, here at BrightGen we ran our release webinar and gave everyone a chance to spend more time in front of a screen, but at least not on camera. Yay!

London's Calling ticked ever closer, and session recording got underway. In keeping with the scale of the thing I was accompanied by a member of the content team and an AV specialist to keep things on track. I have to say I still prefer the adrenaline rush of doing everything live - there's nothing like wondering if the wifi will hold up to get the heart racing. That said, from the point of view of the organisers I can see that trying to co-ordinate a ton of speakers to present live from around the would be a total nightmare.

The London Salesforce Developers were treated to a session on respecting data protection laws in Salesforce - a dry topic, but also an important one that isn't going away.

I also launched a Substack in February, which is proving invaluable for reminding me what was going on back then!

March

The wait was finally over and London's Calling was here - another chance to spend a whole day in front of a screen! As always it felt like the hardest thing to recreate online was the expo, but at least we at BrightGen had the caricatures which do translate pretty well, as you can see at the start of this post. My session was on Org Dependent Packages, which I still think are pretty awesome, especially for large enterprises with mature orgs. You can find recordings of all of the sessions on the youtube channel, and there is some great stuff there, so it's well worth a few hours digging around. 

When it's London's Calling month, we at the London Salesforce Developers try to keep our event lightweight as we feel like there's plenty of learning around already. To this end we decided to crowd-source our member's favourite Spring 21 features, which didn't get a huge take-up. To punish them, I did most of the presenting on my favourite features, which should motivate people to either get more involved or not show up in the future!

In an unexpected turn of events, the data recovery service came back from the dead, having been retired in July 2020. A fine example of listening to your customers. There were also rumours that Marc Benioff was considering stepping down and handing over to Bret Taylor. Not entirely wrong as it turned out, but not exactly correct either.

March also marked a whole year fully remote - little did I realise that there was plenty more of this to come.


Sunday, 5 December 2021

JavaScript for Apex Programmers Part 2 - Methods and Functions


(for the full Gertrude Stein quote on art having no function and not being necessary, see : https://www.scottedelman.com/2012/04/26/art-has-no-function-it-is-not-necessary/)

Introduction

In the first part of this occasional series on JavaScript for Apex Programmers, we looked at my chequered history with JavaScript, then the difference between Apex and JavaScript types. In this instalment we'll look at methods and functions.

Definitions

A method is associated with an object. It's either part of an object instance (non-static) or part of the class that objects are created from (static method). A function is an independent collection of code that can be called by name from anywhere. These are often used interchangeably (by me especially!) but the difference is important when considering JavaScript and Apex.

Apex

Apex only has methods. All Apex code called by its name is either a method being invoked on an object instance (that you or the platform created) or a static method in a class.

...

Almost all Apex code.

...

Apart from triggers. 

...

Here's an account trigger with a named collection of code that I can call later in the trigger:

trigger AccountMethod on Account (before insert) 
{
    void logMessage(String message) 
    {
        System.debug('Message : ' + message);
    }
    
    logMessage('In account trigger');
}

And if I execute anonymous and insert a trigger, I see the message appear as expected:



While this might look like a function, it's actually a static method on the trigger, as I found out by changing the use to this.logMessage('In account trigger');



It's not a useful static method though, as it can't be called from outside of this trigger. I suppose it could be used to organise code in the trigger to be more readable, but code shouldn't live in triggers so you'd do far better to put it in a utility or service class.

That interesting digression over with, as far as we are concerned Apex has methods in objects or classes, and I'll proceed on that basis.

If you want to pass some Apex code to be executed by another method, you have to pass the object to the method. An example of this that we come across pretty often is scheduled Apex:

MySchedulable mySch = new MySchedulable();
String cronStr = '21 00 9 9 1 ?';
String jobID = System.schedule('My Job', cronStr, mySch);
The platform will call the execute() method on the mySch instance of the MySchedulable class that I pass to it.

 

JavaScript

JavaScript, as I find so often the case, is a lot more powerful and a lot more confusing. JavaScript has both methods and functions, but under the hood methods are functions stored as a property of an object. 

Functions are also actually object instances - every function you create is actually an instance of the Function object.  Which means they can have properties and methods like other objects. And those methods are actually functions stored as properties. And so on.

The good news is that you don't need to care about most of this when using JavaScript in Salesforce. In my experience, what you really need know is:

Functions are First Class Citizens

In JavaScript, functions can be assigned to variables:

let log=function(message) { 
                console.log(message);
        }
   
log('Hello');

Hello

passed as parameters to other functions:

let consoleLogger=function(message) {
               console.log(message);
               }
               
let log=function(logger, message) {
             logger(message);
}

log(consoleLogger, 'Message to console');

Message to console

and returned as the result of a function;

function getConsoleLogger() {
    return function(message) {
        console.log(message);
    }
}

let consoleLogger=getConsoleLogger();

consoleLogger('Message for console');

Message for console

Functions can be Anonymous

When you create callback functions in JavaScript for very simple, often one-off use, they quickly start to proliferate and become difficult to distinguish from each other. Anonymous functions are defined where they are needed/used and don't become a reusable part of the application. Using a very simplistic example, for some reason I want to process an array of numbers and multiply each entry by itself each entry. I'm going to use the map() method from the Array object, which creates a new array by executing a function I supply on every element in the source array. If I do this with named functions:

function multiply(value) {
    return value*value;
}
let numbers=[1, 2, 3, 4];
let squared=numbers.map(multiply);
console.log(squared);
[1, 4, 9, 16]

If I don't need the multiple function anywhere else, it's being exposed for no good reason, so I can replace it with an anonymous function that I define when invoking the map method:

let numbers=[2, 4, 6, 8];
let squared=numbers.map(function(value){return value * value});
console.log(squared);
[4, 16, 36, 64]

My anonymous function has no name and cannot be used anywhere else. It's also really hard to debug if you have a bunch of anonymous functions in your stack, so exercise a little caution when using them.

Arrow Functions improve on Anonymous

Especially for simple functions. Arrow functions (sometimes called fat arrow functions) give you a more succinct way to create anonymous functions.

numbers.map(function(value){return value * value});
I can lose a lot of the boilerplate text and just write:
numbers.map(value=>value*value);

Breaking this down:

  • I don't need the function keyword - I replace it with =>
  • I don't need parenthesis around my parameter, I just put it to the left of =>
    Note that if I have no parameters, or more than one, I do need parenthesis
  • I don't need the braces, as long as the code fits onto a single line
  • I don't need the return statement, again as long as the code fits onto a single line. The result of my expression on the right hand side of => is implicitly returned
Thus arrow functions can look pretty different to regular functions:
let multiply=function(value) {
    return value * value;
}

let arrowMultiply=value=>value*value;

or quite similar

let addAndLog=function(first, second) {
    let result=first + second;
    console.log('Result = ' + result);
    return result;
}

let arrowAddAndLog=(first, second)=>{
    let result=first + second;
    console.log('Result = ' + result);
    return result;
}

Arrow functions have a few gotchas too - the major one is 'this' always refers to the Window object, regardless of how you might try to change it. 

Functions have a Context

There's quite a bit to this (pun intended!) and as I mentioned in the first instalment, this isn't intended to be a JavaScript tutorial, so I can't see any point in replicating the Mozilla Developer Network content. Instead I'll just point you at it. The key thing to remember is 'this' depends on how the function is called, not where it is declared, so if you pass an object method as a callback function, when it is invoked 'this' won't refer to the original object, but whatever object is now invoking it. I'd recommend spending some time getting to grips with the context, otherwise you'll likely spend a lot more time trying to figure out why things don't work.

Related Posts

JavaScript for Apex Programmers Part 1 - Typing

Sunday, 28 November 2021

Salesforce++ Holiday Highlights

With the holiday season fast approaching, it's time to take a look at the feast of programming coming in the next few weeks, starting with one from my side of the pond.

The Great British Break Point


Amateur developers compete for the crown of Britain's Top Debugger. This week focuses on the user experience, where the breakers are tasked with crafting the perfect break point to identify why a user cannot successfully create an opportunity and its related products in a single transaction. Judges Paul Cricklewood and Prue L33t are on hand to deliver the verdict. 

On your marks ... get set ... break!

Bob and Mate: Plus 8


Introduction to simple formulas featuring me, Bob Buzzard, and an acquaintance from the Salesforce ecosystem. December's episode shows how to add 8 to various numeric fields, either directly or by calculating the value 8 using advanced mathematical operations like addition and multiplication. 

Licensed at First Sight


Five prospect companies who have never seen Salesforce before are matched up to license packs by a team of experts. Cameras follow the users as they get their first sight of the system on go live day. Look out for the follow up program in 8 weeks time, when the prospects decide if they want to stay licensed or break up their contract. 

Unlike other matchmaking shows, there is no cash prize for prospects who stay with their licenses - quite the reverse as they are then liable for the full cost of the license pack, even the ones they don't want!

Batched


Follow two Apex specialists as they remedy extreme asynchronous processing gone wrong. Whether it's a maximum scope of 1 record, or exceeding the 50 million records per day processing limit, there's always hope.

Film of the Month  - Hidden Triggers (2019)



Documentary featuring the unsung trigger heroes that keep enterprises moving. Whether it's overcoming limitations with roll up summaries, or simply copying an updated field from one sObject type to another, if these triggers fail then western civilisation would quickly grid to a halt. Filmed over five years with unparalleled access to version control, see for the first time how updates to these triggers are deployed and tested. 

Contains scenes of mild jeopardy and swearing at failed deployments.

See Also


If you enjoyed this post, you might like Salesforce++ Top Picks. And you might also like to question some of your life choices.

Sunday, 24 October 2021

London Salesforce Developers - Back in Person



20th October 2021 was a momentous day for the London Salesforce Developers Trailblazer group, as we met in person for the first time since 12th February 2020 - 88 weeks later!

We've still been running our events - like most of the developers around the world we had switched to Zoom, but fatigue was hitting, and the excitement of having people join from around the world was fading fast. After the September Dreamforce viewing party event, we organisers felt that enough was enough and it was time to go out into the world and once again mingle with the three-dimensional people.

Cloud Orca were our generous hosts, in the Loading Bay event area of their Techspace offices in Shoreditch: 

Your organisers and Cloud Orca CEO Ed Rowland (right)

It was wonderful to see everyone, and very strange to be in such proximity again. Dare I say it felt like we were returning to normal, although it will take a few more of these before it starts to feel normal again. Luckily we humans are nothing if not adaptable, so I'm sure by early next year we'll have forgotten what a virtual event feels like.

One thing we were fairly sure of what that people wanted to talk to each other rather than listen to us, so we kept the presentation side of the evening short and sweet.  Amnon kicked us off minimum slides to welcome everyone back, and call out some key community news, including :

then a few minutes from yours truly on the key developer features from the Winter 22 release

As part of my talk I gave a demo of dynamic interactions - while this wasn't recorded, you can find the code in my Winter 22 Github repository. I may write up another blog post about this, although there wasn't an awful lot more ground covered than my last post on the topic, aside from a slightly more plausible use case! It did feel good to be demoing to a live audience again - demoing virtually is fine, but you do feel somewhat removed from the audience.

Not quite Rick Wakeman - photo posted by Louise Lockie on Twitter

The RSVPs were a little lower than before the pandemic, which isn't surprising as not everyone is keen to start mixing again. Dropouts were way down though, so thus far it looks like those who sign up to come along aren't doing so lightly. 

If you are interested in coming along to our next meetup, make sure to join our Trailblazer Community Group, and if you'd like to see what we've got up to in the past and receive future recordings, follow our Youtube channel.  


 

Saturday, 2 October 2021

Transaction Boundaries in Salesforce (Apex and Flow)

Introduction

Winter 22 introduces the capability to roll back pending record changes when a flow element fails at run time. I had two reactions to this - first, that's good; second, how come it didn't always do that? It took me back to the (very few) days when I did Visual Basic work and found out that boolean expressions didn't short circuit - it's something that has been such an integral part of other technologies that I've worked with, it never occurred to me that this would be different.

The original idea for this post was to call out the roll back only applies to the current transaction, and tie in how Apex works as a comparison. But then it occurred to me that in the Salesforce ecosystem there are many people teaching themselves Apex who could probably use a bit more information about how transactions work, So, in the words of Henry James wrote in his obituary for George du Maurier (referring to the novel Trilby):

"the whole phenomenon grew and grew till it became, at any rate for this particular victim, a fountain of gloom and a portent of woe"

Transactions

A transaction is a collection of actions that are applied as a single unit. Transactions ensure the integrity of the database in the face of exceptions, errors, crashes and power failures. The characteristics of a transaction are known by the acronym ACID:

  • Atomic - the work succeeds entirely or fails entirely. Regardless of what happens in terms of failure, the database cannot be partially updated.
  • Consistent - when a transaction has completed, the database is in a valid state in terms of all rules and constraints. This doesn't guarantee the data is correct, just that it is legal from the database perspective.
  • Isolated - the changes made during a transaction are not visible to other users/requests until the transaction completes. 
  • Durable - once a transaction completes, the changes made are permanent. 

Transactions in Apex


Apex is different to a number of languages that I've used in the past, as it is tightly coupled with the database. For this reason you don't have to worry about transaction management unless you want to take control. When a user makes a request that invokes your code, for example a Lightning Web Component calling an @AuraEnabled method, your code is already in a transaction context. 

When a request completes without error, the transaction is automatically committed and all changes made during the request are applied permanently to the database.  This also causes work such as sending emails and publishing certain types of platform events to take place. Sending an email about work that didn't actually happen doesn't make a lot of sense, although this caused us plenty of angst in the past as we tried to find ways to log to an external system that a transaction had failed (Publish Immediately platform events finally gave us a mechanism to achieve this).

When a request encounters an error, the transaction is automatically rolled back and all changes made during the request are discarded. Often the user receives an ugly stack trace, which is where you might decide that you need a bit more control over the transaction.

Catching Exceptions


By catching an exception, you can interrogate the exception object to find out what actually happened and formulate a nice error message to send to the user. However, unless you surface this message to the user, you have changed the behaviour of the transaction, maybe without realising it. For example, if you catch an exception and return a message encapsulating what happened:
Account acc=new Account(Name='TX Test');
Contact cont=new Contact(FirstName='Keir', LastName='Bowden');
String result='SUCCESS';
try {
   insert acc;
   cont.AccountId=acc.Id;
   insert cont;
}
catch (Exception e) {
    result='Error ' + e.getMessage();
}

return result;
In my dev org, I have a validation rule set up that one of email or phone must be defined, so the insert of the contact fails and I see a fairly nice error message:


Unfortunately, this isn't the only issue with my code - as I caught the exception, the request didn't fail so the transaction wasn't automatically rolled back. While from the user's perspective the request failed, the first part of it succeeded and an account named TX Test was created:


and every time the user retries the request, I'll get another TX Test account and they will get another error message.  

Taking Back Control


Luckily Apex has my back on this, and if I want to (and I know what I'm doing) I can take control of the transaction and apply some nuance to it, rather than everything succeeding or failing.

Savepoints allow you to create what can be thought of as sub or nested transactions. A savepoint identifies a point within a transaction that can be rolled back to, undoing all work after that point but retaining all work prior to that point.  Changing my snippet from above to use a savepoint and rollback, I can ensure that all of my changes succeed or fail :
SavePoint preAccountSavePoint=Database.setSavePoint();
Account acc=new Account(Name='TX Test');
Contact cont=new Contact(FirstName='Keir', LastName='Bowden');
String result='SUCCESS';
try {
   insert acc;
   cont.AccountId=acc.Id;
   insert cont;
}
catch (Exception e) {
    result='Error ' + e.getMessage();
    Database.rollback(preAccountSavePoint);
}

return result;
The user's experience remains the same - they receive a friendly error message that the insert failed.  This time, though, there is no need to rid my database of the troublesome account. Prior to carrying out any DML I have created a Savepoint, and in my exception handler I rollback to that Savepoint, undoing all of the work in between - the insert of the account that was successful.  Note that rolling back the transaction has no effect on my local variables - prior to the return statement I have an account in memory that has an Id assigned from the database, but that doesn't exist any more. Of course this also leaves any other work that happened in the transaction outside of my code in place, which may or may not be what I want, so taking control of transactions shouldn't be done lightly.

Savepoints are also useful if there are a number of courses of action that are equally valid for your code to take. You set a Savepoint and try option 1, if that doesn't work you rollback and try option 2 and so on. This is pretty rare in my experience, as usually there is a specific requirement around a user action, but it does happen, like when option 2 is writing the details of how and why option 1 failed.
 
You can also set multiple Savepoints, each rolling back less and less work, and choose how far rollback to in the event of an error. Your co-workers probably won't thank you for this, and are more likely to see it as combining Circles of Hell into your very own Inferno.  If you do choose to go this route, note that when you rollback to a savepoint, any that you created since then are no longer valid, so you can't switch between different versions of the database at will.

Savepoints only work in the current transaction, so if you execute a batch job that requires 10 batches to process all of the records, rolling back batch 10 has no effect on batches 1-9, as those took place in their own transactions which completed successfully. 

Rolling Back Flow Transactions

After that lengthy diversion into Apex, hopefully you'll understand why I expect everything to rollback the transaction automatically when there is an error - it's been a long time since it has been my problem.  Per the Winter 22 release notes, flow doesn't do this :

Previously, when a transaction ended, its pending record changes were saved to the database even if a flow element failed in the transaction

and bear in mind that is still the case - what has been added is a new Roll Back Records element you can use in a fault path. Why wasn't this changed to automatically roll back on error? For the same reason that Visual Basic didn't start short circuiting boolean expressions - there's a ton of existing solutions out there and some of them will rely on flow working this way. While it's not ideal, nor is introducing a breaking change to existing customer automation. 

Something else to bear in mind is that this rolls back the current transaction, not necessarily all of the work that has taken place in the flow. Per the Flows in Transactions Salesforce Help article, a flow transaction ends when a Screen, Local Action or Pause element is executed. Continuing with my Account and Contact approach, if you've inserted the Account and then use a Screen element to ask the user for the Contact name, the Account is committed to the database and will persist regardless of what happens to your attempt to create a Contact.  Much like the batch Apex note above, rolling back the second (Contact) transaction has no effect on the first (Account) transaction as that has already completed successfully.

Enjoying Transactions?

Try distributed transactions:

And then scale them up across many microservices.

Many years ago I used to have to manage transactions myself, and in one particular case I had to work on distributing transactions across a number of disparate systems. It was interesting and challenging work, but I don't miss it!

Related Posts