[MUSIC]
Speaker 1: Because future looking statements are inherently subject to risk
and uncertainty, our reminder is that you should make any purchasing decisions,
or investment decisions based on products that are currently commercially available.
Chris Peterson: Good afternoon everyone, thank you for joining us at TrailheaDX.
My name is Chris Peterson, Director of Product Management for Apex at Salesforce.
And joining me today is Kevin Poorman, a senior developer evangelist at Salesforce.
And today, we'd like to talk to you about improving the quality of life.
Apex updates to ship better code faster.
So today, we'll be taking a look at a new Apex language operator that's coming in
the winter release, the safe navigation operator.
I'll be handing things off to Kevin to do a fairly advanced demo of the transaction
finalized as open pilot, including a very exciting framework that's been built on
top of it, that mimics JavaScript Promises.
And then we'll be rounding things out at the end, with a peek at the apex roadmap
for any and all feedback that you'd like to throw our way.
And with that, what is Apex?
Many of you already know the answer.
Lots of interesting updates about Apex and its history for
those of you who already know the basics.
Apex is really the solution for
writing code, server side, that runs on the Salesforce platform.
If you want to write a database trigger, if you want to write a batch Apex job.
If you would like to write scheduled Apex, if you'd like to write an LWC controller,
or an controller, a Visualforce controller, an email service.
Or even features that integrate programmatically with declarative,
like flow in vocable actions, Apex is really the solution for you.
At the moment, Apex is running over 105 billion requests per month
across all of Salesforce's production fleet.
And to make sure that Apex is a robust and stable solution for you to do
all of your programmatic development on, we run a process called hammer.
Which takes every test our customers and partners have written, and
runs them every release.
At last count for the summer release that's rolling out right now,
we ran 240 million of your tests, to make sure we didn't break anything.
And yes, they did actually catch a couple of regressions that we fixed before you
ever got to know about that.
So, thank you all for your help in making Salesforce successful.
Beyond that, I'd also like to highlight that Apex was first released in 2006.
And impressively is still able to run the code from 2006.
Between API versioning and things like hammer,
we've managed to maintain strict backwards compatibility that whole time.
So I like to think of Apex as a wonderful tool for writing code.
That, while I'm not going to say needs no maintenance,
needs very little maintenance compared to other programmatic
solutions that are available in the enterprise software space.
So, with that introduction out of the way,
we'd like to dive right into the meat of the presentation today.
The Safe Navigation Operator.
So, if you are familiar with kotlin or C+, a number of other languages,
have similar constructs, then you'd already be familiar with this.
If you're not, what it does is,
if the left hand side of the expression is not null, then does whatever dot would do.
That can be invoke a method, do reference a property, or a field, etc.
And if it is null, just returns null.
No null pointer exceptions, no try catch, no need for explicit null checks.
And so this is a really beneficial quality of life improvement,
as I'll show you in just a second.
Because what used to require multiple explicit is not null checks,
can really be simplified down and inlined.
No tries, no catches, no conditional blocks, into something that's
much more graceful, and really just saves you a lot of boilerplate code.
Which is the theme that you've seen in many of my conversations lately.
So how does this work?
Here on screen, you'll see a class called Character.
We see one noteworthy method in this class, getCharacterHobbiesFromCache.
You'll notice that we're using platform cache.
And we are fetching our partition dynamically.
So, anytime we're doing anything dynamically,
we really should be prepared for it not to exist.
That's exactly the first thing you see here.
If the partition doesn't exist, we bail out and return null.
Following that, we actually fetch in a complex Apex type from the cache,
and then again, we handle null.
If you look at this code, you see a recurring theme.
The vast majority of this method's complexity and verbosity,
is in null handling.
So, let's take a look at how we could use safe navigation to really simplify things.
So, let's be bold, let's make this a one liner.
Let's start with a return statement.
So, we know that cache is namespace and org is a class, those won't be null.
So, we don't have to worry about safe navigation off of those.
So, let's get partition call as fine as it is.
So, we add a safe navigation call, and get rid of this whole block of code.
Just delete that right out of the way.
We remove our cast, because we still do need the cast.
We would over here, nested some parentheses, and
right after the get call,so get rid of part.
We don't need to store that in a local variable anymore.
And what do we have?
Well, not quite the final implementation.
Because we want to return the hobbies, not the complex character details type,
but you can imagine where we're going next.
Let's get rid of all this code.
That's glorious, to delete that much code,
get hobbies, Chris Peterson: Gone.
And just like that, we've refactored that whole method into a single line.
Admittedly, a longer line than you might like.
But at the end of the day, what did we do?
We got rid of multiple explicit null checks in our method.
We made sure that we kept the same guarantees about safe handling of dolls.
But we did it in a way where we didn't have to write multiple extra conditionals,
and where the only extra syntax, there's really two question marks.
We got rid of multiple local variables.
So, we dramatically simplify the experience of developing this code.
And we hope that that's exactly what will happen in practice in your code
bases as well.
Is that the level of complexity, and time, and
thought you put into handling knowles will drop dramatically.
With that, I'd like to hand things off to Kevin,
to talk about transaction finalizers and the Promises framework.
Kevin Poorman: All right, thanks, Chris.
I'm really looking forward to using the safe navigation operator,
though I think we should call it the maybe operator.
What do you think?
Let me know.
I want to show you a feature that's currently in open pilot,
called Apex finalizers.
Open pilot means you can use it in your scratch orgs, but not in production.
Finalizers solve one of the biggest pain points with asynchronous code and
development, making sure that that code is executed in order.
Finalizers also offer us an elegant way to build Promises in Apex.
If you're not familiar with Promises from other languages,
they're a way of providing flow control and error handling to asynchronous work.
Let's build a finalizer that we can use with Promises.
All right, you can see that I've stubbed out these classes,
I've got one called chain.
This is our actual finalizer that we're going to be reusing to implement Promises.
So, if you look here, you can see that it implements finalizer.
And to implement finalizer,
you have to have an execute finalizer contacts method, right?
So, we got that here, there's no logic.
And you can see I've also got a constructor that accepts
a list of Promises, or an array of Promises, and a pass through object.
We'll get to that here in a bit.
But that array of Promises is really important.
Because arrays are ordered, we're going to use that
ordering of arrays in order to provide and ensure that our Promises,
or pieces of the Promise chain, are run properly in order.
All right, so let's look at filling out this execute.
Now, I want to do something clever with this.
I want to see what happens if I can specify
when it succeeds versus when it fails.
And to do that, I'm going to do a switch statement,
which is still one of my favorite things, switch on.
And then I'm going to call our context objects that we get .getResult.
And I'm going to say when, and these are so success,
like that success, just success and make that pretty.
I'll say, if we have another one.
So if this.promises.size is greater than 0.
So, if we have another promise in our chain,
then we're going to immediately pop it off.
So, we'll say promise, we call it next is
equal to this.promises.remove 0.
Now remove is similar to pop in other languages.
And then we're going to say next.promises.
So, we're going to set the next promises array is equal to,
and it's going to be this.promises, so whatever is left.
And then we're going to say next.passthrough,
is equal to passthrough object, like that, okay?
Now, here's the magic, because in a finalizer,
we can enqueue one, another batch job or queueable, etc.
And we're going to turn around and
use this to enqueue the next Promise we just pulled off.
So to do that we'll say, system.enqueueJob,
and we'll say next, like that.
And that's how we handle the success portion of it.
Now, if we wanted to, we can also do when,
it's actually called unhandled exception,
UNHANDLED EXCEPTION.
Kevin Poorman: And here, we're just going to do a system debug for right now.
We'll say, parent queueable had an exception.
And then we'll just put in that exception, and
to do that we're going to do context.getException.
And then we'll do .getmessage.
Kevin Poorman: That, all right, so we can save that.
And that's going to actually handle the, this is our finalizer that's handling
the bit of starting the next one in the chain, okay?
So now, we need to work at a class that will orchestrate all of this.
Now to orchestrate all of this in conjunction with
that finalizer called chain, I've got a classical Promise.
Now, you notice is an abstract class, because I expect other people,
other developers, to be able to take and derive from this, to extend it.
And I'm going to have this class implement queueable and
database that allows callouts.
So from a Promise implementing class, I can queue it, and I can also make call up.
Now, you'll notice this looks very familiar to what we had in the chain.
We've got a list of Promises,
and we're going to guarantee that it's always at least an empty list.
And then we've also got the passthrough object..
We've also got an abstract public void execute method, more than that in a bit.
And then we've got this.
This is our syntactic sugar that makes promises incredibly useful to follow and
understand.
And that is the then method.
And the then method is really simple.
And all it's going to do is,
it's going to add an object to our list of promises to execute, okay?
So when you say then, we pass it in an instance of a promise conforming class,
and it will be added to our list of promises to be executed.
So, while this is terribly simple in terms of what it does, it actually
provides a lot of syntactic sugar that makes it much easier to read the code.
Now, this class also has to have an execute, because it implements queueable.
So, let's look at what we're going to do here.
And the first thing we're going to do, is call the execute method.
Now, what's up with that?
Well, what we're doing is, we're calling the execute method that the developers
who are using this promise, have extended and written themselves.
And we've made that required by saying abstract rather than virtual.
Now, we've also got the finalizer here.
And this is where we're going to take and attach a finalizer to our queueable.
This is the step that you can use, regardless of whether or
not you're using promises.
When you have a queueable that you want to add a finalizer to,
you have to call this system.attachFinalizer(chain).
Now, this is one of the key gotchas with finalizers.
You can only attach one finalizer per queueable.
You can reuse that finalizer, and
you can have multiple queueables with different finalizers.
But one queueable per finalizer.
Now, if we look here, you're going to see that I'm going to call the chain, and
I'm going to pass in the current values of promises, and pass through to that chain.
And that is what's going to pass that back into our chain object,
which will then say, okay, this one succeeded.
I'm going to pop this one off and go to the next one.
So, let's save this, and let's look at what it looks like to actually run that.
Kevin Poorman: This is a Demopromise class.
As the name implies, it just demonstrates how promises work, and
how everything comes together.
You'll see that it extends promise,
which is our orchestration class that we will get just before.
It has a constructor that just takes in accountId.
And then it has an execute method.
That execute method is required because it derives from, or extends queueable.
So, as we look through here, we can see that we're just doing a bit of work by
grabbing an account, and incrementing its account on that account.
So, not a lot of work there, but it's something we've done it synchronously.
And, if we switch over to the task force, we can see how it does things in order.
So, let's look at this here,
and we can see here, that we gotta a test called thenTest.
Now, I've got my account that I'm going to grab,
I am going to create a new denoPromise with the account ID.
And then I'm going to set my passthrough integer to 0.
That passthrough integer is a way to pass in information into the queueable chain.
So, we're going to set it to 0, and then we're going to call the then method,
with a new demoPromise account ID.
So the same thing but again, and then we're going to change it by saying,
then with a new demoPromise with the account ID.
So, we're going to be doing this three times 0,1 and 2.
And what we're going to do is, we're going to queue that first job and let it run.
Because our chain automatically runs the next one.
And because Promise automatically attaches the finalizer, we now have a very nice
step by step process, where we go through the array one by one.
So now we can go at the end of this, we can look and see what this runs.
You see the first time our account runs, or account was created as 0 for
the shipping street, or excuse me, yeah, shipping street.
Now, it's going to be incremented three times,
because we ran that promise three times in a row.
Pretty cool.
Thanks for tuning in to hear all about the new Apex features.
I'm sure with safe navigation operator and
Apex finalizers, you'll be able to write safer code faster.
One last thing.
I'd like you to go KickTheTires a bit.
Go play with Apex finalizers.
See how Promises work.
Are they good use case for what your company's doing?
Give me a shout out, hit me on twitter at codefriar.
Chris Peterson: Thanks for that, Kevin.
And jumping over to the last thing I promised you'd see today.
A peek at the Apex roadmap.
You'll see a number of other items identified as coming soon.
Really, winter 21, unless something changes.
I'll refer you back to the forward looking statements slide at the beginning of
the presentation.
Coming up, a number of items that we expect to be able to do in the one or
two releases following that, so spring or summer 21.
And then, longer term is really what's on the back log after that.
Things that we haven't identified, explicit blockers too, and
expect to start working on in earnest, as we have capacity for it.
And beneath that, list of things that we're exploring, things that we
have identified blockers to, and we're starting work on mitigating those, so
that we can really deliver the features that you're looking for.
We'd love your feedback, feel free to share it.
And with that, I'd like to thank you for joining us trailheaDX, and
enjoy the rest of your day.
[MUSIC]
David Chestnut: Accenture has always made our people a top priority.
With over 20,000 Salesforce professionals,
traditional training methods just weren't enough.
Combining research strategy and technology,
we created our foreveralone forever learning program.
We use tools like my trailhead, and with a global network of champions, mentors,
and study squad, Accenture is transforming our learning culture.
Culture change starts with a conversation.
To learn more about bringing forever learning to your company,
visit accenture.com/salesforce.
[MUSIC]
Gino Ramos: Did you know most of the time we all have positive intentions?
But sometimes, it's the impact of our actions and
the words that can do harm to others.
We all make mistakes, but we can commit to remembering it's the impact,
not the intent that matters.
Scaling up on equality makes us a stronger community.
Learn more on trailhead and earn the inclusive marketing practices badge.