Episode 94: Joys of Apex with James Simone | Salesforce Developers Podcast

James Simone is a Senior Software Engineer here at Salesforce. He has done a lot of work around engineering for Agile teams which we are talking about today. Specifically, James and his team develop applications on the Salesforce platform with the goal of increasing the Agile health of software development teams.

James also has a blog called Joys of Apex which we are discussing in this episode. On his blog, he provides much-needed clarity for developers who are trying to work within Apex. Listen in to learn more about it and other great tips for working within Apex.

Show Highlights:

  • What James does in his position at Salesforce.
  • What made him want to write a blog about Apex.
  • What test-driven development is.
  • How James designs a failing test with no Apex to compare it to.
  • The benefits of using a mock system for testing.
  • Tips for making testing easier and quicker.
  • What inversion of control means and what it does.
  • What Invocable Apex is and how it works with Flow.
  • What a Singleton is and how it helps developers.
  • The benefits of using factory patterns.
  • How James and his team are keeping the joy in Apex.

Links:

Episode Transcript

James Simone:
I always knew that computers were my passion. I was building computers since the age of eight.

Josh Birk:
That is James Simone, senior software engineer here at Salesforce. I’m Josh Birk, your host with the Salesforce Developers podcast. And here on the podcast, you’ll hear stories and insights from developers for developers. Today, we sit down and talk with James about his work around engineering for Agile teams, as well as his blog, “Joys Of Apex.” We’ll start as we frequently do with some of his early years specifically, how he got that job.

James Simone:
I got lucky. Honestly, the original shop that I was working for was a hybrid.net and Salesforce shop at that point, after we’d made the migration over to Salesforce and I left that company to go work for another one that was really focused on test-driven development. And that’s where I had an amazing mentor who really shepherded me through not only what I would consider to be a traditional computer science curriculum, as he was also a self-taught programmer. But in addition to that, ingrained within me two things that were completely crucial toward me being hired here, which was test-driven development and that methodology including paired programming or extreme programming or now as we’re practicing on my team here ensemble programming, which is paired programming, but with others and swapping off fairly frequently, as well as CICD. And having that knowledge of pipelines and automating production deploys is something that was really crucial to me as a skillset as I moved around.

Josh Birk:
Got it. Got it. And how would you describe your current job at Salesforce?

James Simone:
That’s amazing. I love it.

Josh Birk:
I meant more like what’s your day to day job, but yeah, that’s awesome too.

James Simone:
Yeah. Sorry. After a couple of years of consulting and being by myself on a lot of different projects, including working with some amazing people, but I think for me, I learned that that wasn’t for me. Being on a team here now has been an amazing experience. But yes, we are developing a variety of applications that are on the Salesforce platform, specifically with an eye towards increasing the Agile health of software development teams.

Josh Birk:
Got it, got it. Now you have a blog, “Joys Of Apex.” It’s about a year old, pretty constantly updated. What made you wake up one morning and say, “I want to write a blog about Apex” and especially kicking that off with test-driven development?

James Simone:
Somebody asked me this question the other day online, and it’s pretty funny, the answer. When I was working, I had my own consulting company and I was tasked with delivering a proof of concept for a Shopify website total rebrand in two weeks. And I knew very little about Shopify development prior to starting that project, but I knew enough to cut my teeth with it and deliver a working prototype. But over that two-week period, I found myself constantly thinking about Salesforce and thinking about how… In my mind there are aspects of the platform that go completely under appreciated or taken for granted. And this isn’t to say anything bad about Shopify necessarily, but when you look at Salesforce’s documentation, there’s a lot of it. It’s constantly maintained. It’s the best documentation that I’ve ever worked with.

James Simone:
Developing on the Shopify platform, even simple things like getting up and running, I found to be considerably harder and making changes in an iterative fashion was challenging. And it really brought me back to the beginning of working with Salesforce and gave me this new found appreciation for these things that again, I feel as though it is possible in your day to day world, especially if you are a Salesforce customer, a developer working on the platform to take for granted. But in reality, there are a lot of platforms out there that either have shoddy documentation, out of date documentation, APIs that have changed. There’s all kinds of different things that you deal with as a developer that you, for the most part, never really experienced as a Salesforce developer with these stable releases each year.

Josh Birk:
And as you noticed in that first blog post, like I think one of the interesting relationships between developers and Apex and Salesforce is there are developers on one side of the spectrum, which kind of hate unit testing. I don’t want to be too accusatory, but like, they kind of see it like as a burden and a chore. And I remember having early conversations with people about like, “Why does Salesforce make this mandatory to people who have kind of, I want to say happier day jobs because they’ve embraced, if not even extended that.” So first of all, I think we’re going to do this a lot in this interview. It’s just because we’re going to be throwing a lot of phrases at people and I just want to make sure we’re level setting against them. So how would you define test-driven development?

James Simone:
test-driven development. You’re probably going to hear two different things, depending on the people that you ask. One would be the simple Red Green Refactor mantra, which is that in order to change production level code, you must write a failing test first, that’s the Red part. Then getting the test to Green entails making the smallest possible change to your production level code in order to get the test to pass. And in many instances, when you see test-driven development or TDD done in a pure fashion, that can be as simple as stubbing out a method in order to invoke that method within your test. And then say, “Okay, well, what I expected to happen was that it returns a value and here now an exception is thrown. So now I’m clear to proceed further with making changes to my production level code.”

James Simone:
And then that Refactor, the last part of it, really ties it all together and encourages you to keep things clean, to try to prevent unnecessary repetition in your code. And in that process, as you start to get comfortable with it and get accustomed to the flow of it, you find that architecture develops out of the business concepts that you’re encapsulating in your program. That’s one of the reasons that I love TDD it’s because instead of trying to top-down architect something, you find these concepts that accrue over time. And when you’re lucky on a good day, those are the things that actually represent the business domain are crucial to the company that you’re working for or with their processes.

Josh Birk:
Yeah. No, I very much agree. I think that was the fundamental flip for me because when you start with a quote unquote functioning Apex class, and then try to write a unit test to it, you’re kind of functionality driven, right? Like you’re trying to figure out how to get into that if loop kind of thing. But tell me a little bit more about that. Like when you’re designing a failing task, you have no Apex to compare it to, then what is the driving force? Like, how do you design that test to be what you expect to be successful?

James Simone:
Totally. I think for me, it all comes down to objects and the APIs that we are creating for objects. What I often heard as a junior developer in the first two companies that I was working for from people would be this phrase. It almost looks like an object is waiting to be born here. And what they would be talking about is something that they desired to test that wasn’t accessible. And that’s something that there’s so much flexibility on the platform that sometimes it can be a little bit too good, too good to be true, specifically test visible, being able to raise the visibility of a method just in order to test it. I try to stay away from things like that for the most part, because when you’re looking at business concepts as objects, the encapsulation of those things should make it so that the things that you’re testing are easily reproducible without you having to reach into the entrance of a class.

James Simone:
So when you’re setting up a test that you want to do for the first time on an object that you’ve already created, which could contain quite a bit of complexity, a lot of the times the thing that you’re trying to test is some nested or buried conditional. And that again, is evidence as cliche as this phrase may be, for an object waiting to be born.

Josh Birk:
Right. Right. Well, and I think you’ve either just now answered my next question or that’s a great segue to it because in that same post, you’re not just talking about kind of the pros of TDD style development, but also pairing that with mocking the data layer and using a mock system for testing. Like what’s the, tell me a little bit more about that and what you’ve learned from that.

James Simone:
Sure. The impetus came, as I describe in that first post, from extremely long deploy times that we were experiencing. And to some extent, some of these things have been alleviated over time. You see a lot of companies out there now doing incremental deploys, basically just in timing with only the changes that are applicable to incrementally improve their program. But in general, if you’re a big organization or you’re trying to do full deploys as a means of safely replicating everything that’s occurring in your CI pipeline or in your Sandbox or Scratch, or, that’s not unusual still to this day. And deploy times are chiefly gated by the amount of time that it takes for your tests to run.

James Simone:
Now, some of this is highly dependent on the nature of the testing that you’re doing, right? As you were alluding to earlier, there’s plenty of wiggle room when it comes to using code coverage as a metric for you to just invoke something. There’s no asserts, right? You’re just passing null or whatever, right. And like-

Josh Birk:
Right.

James Simone:
Sure. You’re probably, you don’t care about deploy time anyway, because everything’s running perfectly fine. But for those of us that are trying to create these highly detailed tests as close as possible as we can get them to mimic production level interactions, the database layer is the single slowest piece to being able to easily reproduce the setup that’s necessary for your test. So stripping that away really, I think, showcases the speed of the platform in a way that most people probably wouldn’t anticipate because when you don’t have the database directly interacting or minimally interacting with the unit test that you’re creating, the tests run fast.

Josh Birk:
And you kind of go one step further with that. And you describe not just mocking the data, but you’re mocking like DML itself. Like you’re mocking the interactions of DML. What brought you to add a layer like that together?

James Simone:
Testability. It all comes down to testability. We found from the get-go that it was painful, especially with cross object updates. And again, I just listened to your talk with Mitch that you had the other day with the Trigger Actions Framework. When you have these really complicated systems that are interacting with automations that are both declarative and code based, there’s a lot that you need to test for. And there’s a lot of setup that ends up being necessary in order to validate that you’re given a certain quantity of inputs, the output is what you expect. And being able to, instead of requiring cross object updates for true unit tests, which should be doing the smallest possible amount of work, receiving the smallest possible input in order to validate the output. Being able to remove those DML statements entirely and instead retrieve the items from memory instead of going to the database, that is where you get that huge speed increase and also the ability to easily test things.

Josh Birk:
Well, I think it’s also interesting that you kind of flipped that around at one point. You’re not just talking about testing, but that sort of object-centric view for functional Apex. A common thing in development these days is to use some kind of object-relational mapping, which is not anything baked into Apex or the platform at this point. But what kind of tricks and things can you do in Apex to kind of achieve that sort of thing?

James Simone:
Yeah. I’m a big fan of strongly typed queries. Not having an access to a traditional ORM layer in Apex was a big pain point for me. And that formed the second half of the coin in terms of being able to easily test things. If every time that we are fetching inputs, we also have the ability to mock out those SAQL calls by using an inversion of control pattern to stub in these fake repositories that return the data that you expect for the conditions that you’ve set up in your test, that is again, helping you both avoid DML and also to increase the testability by being able to not only assert that your queries are properly formatted, which isn’t a function natively out of the box, but also that given that records are returned and the query is the query that you expect it to be, that then again, the actions that you expect after that occur flawlessly.

Josh Birk:
Gotcha. I think it’s interesting that you just used that phrase inversion of control because it kind of comes up again in some more of your work. Let’s dig into that phrase a little bit. What specifically do you mean by inversion of control?

James Simone:
In a lot of other applications, you have the ability to register your dependencies at startup. And that’s something to some extent that also we can get into the generic side of the equation, which we also, for the most part, don’t really have access to in Apex. But strictly speaking from the process of creating objects, using the new keyword or even typedef for a name in Apex, there’s always going to be this underlying question of, if that object needs to get information, where does it come from? And so with the inversion of control, you are instead centralizing the place where those objects are being created so that you can pass them the dependencies that they need.

James Simone:
So you become responsible for feeding these objects the dependencies that they need. And specifically what I was talking about in those posts and in terms of SAQL mocking in particular, but also in DML mocking, it’s not just stripping away where inserts, updates, deletes, undeletes, that rare beast, the undelete…

Josh Birk:
That’s right.

James Simone:
And all the five times I used it in my career.

Josh Birk:
Exactly.

James Simone:
But also the queries. So if you have something that is specific to each SObject as a repository, that you can then quickly, only in tests, and I think that that’s a corollary that’s not necessarily part of the inversion of control principle, but it’s important to me personally, that you’re ensuring that in your production level code an object can only be set up in such a way that ensures that it’s always going to work the way that you expect it to in terms of issuing queries or performing DML. But in the test it allows you this fast path to swap those dependencies out in one particular place.

Josh Birk:
You know, it kind of occurs to me and this is sort of a… And I’m trying to think of how to frame this question, but like Apex is so almost uniquely designed to have the data layer just right there, right? Like the data layer’s such a first class citizen on the platform. How much of that do you think is like…? The general standard, when you see code in Apex, it’s like go to data, get data, get, do stuff. How much farther of the evolution are you talking about here? Do you just kind of have to ignore those instincts and have this sort of object-centric not SObject-centric concept in mind as you’re just sort of moving forward?

James Simone:
Well, it’s funny. I feel like the answer to that comes from the documentation and from of the things that we espouse ourselves. We coined the phrase bulkification. That word did not exist beforehand, and it’s a best practice that we are espousing. And I can tell you, outside of Salesforce, it’s incredibly rare for APIs to be designed well in a bulk fashion. It’s funny that you see this concept that it never existed before. It literally has been created out of clay and baked into being by our repetition of it over and over again, over the years, over the decades now. And in that same way, are you familiar with the phrase, any problem can be solved by adding another layer of indirection?

Josh Birk:
I think I saw that when I was reviewing some of your stuff, but is that like, kind of, because what we have been talking about this whole time is like add another layer that handles this interaction, or add another layer that handles controlling the dependency and stuff like that. Is that kind of the mindset that you’re talking about there?

James Simone:
It’s always a balance. And the corollary to that famous phrase is something like, except for the problem of adding too many layers of indirection-

Josh Birk:
Too many layers. Because I was going to say, we started talking about test-driven development as a way of trying to make sure… I might be reaching a little bit here, but one of the nice things is that it is sort of forces you to try to write as little code as possible. And now we’re adding layer on a layer to solve the problems.

James Simone:
Yeah. I mean the best thing that you can do, personally, for me, the best thing that I experienced is removing code. When you have a pull request that contains more deletions than insertions, that is the best feeling in the world. And that is a balancing act, especially, as you said, when it comes to TDD, we want to try to contain the proliferation other objects so that they, as much as is possible in any given domain, come to represent those core business concepts and the things that help those core business concepts succeed, without leading to an endless proliferation, as I said, of objects and in a hugely inflated class tree or dependency list.

Josh Birk:
Right. Right. And to be fair, you’re not just trying to resolve random problems or doing things because they might look cool. You’re trying to solve specific things like build times and how much time are you talking in the SAQL layer and things like that. And the article that I think first got me pointing to “Joys Of Apex” was actually the one that you were talking about when it comes to Invocable Apex for Flow and things like that. So actually once again, let’s level set, what exactly is Invocable Apex?

James Simone:
Sure. Invocable Apex is the decorator used when you are interacting with code from a declarative based tool, be it Process Builder or Flow in this case. So Invocable Apex exposes within the Salesforce GUI the ability to interact with prebuilt code routes. And so you give people inputs that can be supplied from the Flow engine, and then they get passed off to Apex. But one of the downsides of that and something that I talk about in that article that you’re referencing, is that those methods have to be static, and static, you often hear talked about using the nomenclature colored functions, which also people talk about in regards to async functions. But in general, once you have a static function, it’s difficult to break out of that static function.

James Simone:
So the article I’m talking about, what are some idiomatic ways within Apex that we can use to prevent static code from disallowing ourselves to keep our code dry, to prevent repetition and still espouse and conform to the best practice standards that we’d like to see throughout the rest of our code base?

Josh Birk:
Well, and you specifically call out that wonderful phrase, bulkification. What are some of the limitations of an Invocable Apex class that makes bulkification challenging?

James Simone:
Oh, gosh. That’s a good question.

Josh Birk:
Is that a whole new podcast?

James Simone:
That may be a whole new podcast. Specifically for me and the part that I’m really interested in as a developer is this union between the declarative and the code-based approaches. And in particular, I think that if you are somebody subscribing to the content on architect.salesforce.com, which was released last summer and now is showing the declarative way forward in tooling is Flow. So more and more people are noticing Flow. The feature parody between Flow and Process Builder is nearly complete. And the stuff that you can do in Flow for the most part is much more powerful than the stuff that you could do at any other point with point and click interfaces within Salesforce. That union between Apex and Flow encompasses pretty much everything else. Within Invocable, You can escape from the limitations that you might not be able to yet access within Flow. And I’m sure that some of these things will go away over time, safe harbor, like not having access to it to a map-like structure within Flow.

Josh Birk:
Right.

James Simone:
But giving people an easy seam into more powerful automation, I think is super powerful. And I think that I have noticed an incredible amount of interest and excitement in Flow, particularly over the last year because of that.

Josh Birk:
Yeah. So when Flow gets into that corner and calls the Invocable Apex, what are some situations, like where’s Invocable Apex getting in trouble when it comes to the request that it’s getting from Flow?

James Simone:
It’s more about where are you getting in trouble as an author of Invocable Apex, right?

Josh Birk:
Okay. Okay.

James Simone:
And again, this goes back to the colored functions thing. Once you are writing static-based code, you might say, “Well, I have an object that does something similar to this.” And the example that I use in the article is filtering items by keys and looking for certain values. So again, for loops, iterating through collections in Apex that’s every Salesforce developer’s bread and butter.

Josh Birk:
Right.

James Simone:
That’s part of every… No matter how it’s kicked off, every Trigger Handler framework is eventually going to be expecting that you are going to be iterating through those records and doing something with them. Right?

Josh Birk:
Right.

James Simone:
Whereas you might be tempted to repeat some of those commonalities in a static context, because you don’t have access or you feel like you don’t have access to those same objects. And so I point out something like the Singleton pattern, which again, Mitch brought up on your last episode, but I’ll repeat here again, because it’s useful in certain contexts, it also can be easily abused, I feel, but-

Josh Birk:
Yeah.

James Simone:
That’s one way that you can break out of your static context and return to this inversion of control principle that we’ve previously been discussing so that you can use your objects all the way down, so to speak.

Josh Birk:
So, first of all, I want to say that we were talking about Singletons. Mitch and I were talking about Singletons. I’ve now talked about Singletons more in the last month, month and a half than I think I’ve had in the last five years and I love that.

James Simone:
You love the Singleton. It doesn’t get a lot of love.

Josh Birk:
It doesn’t get a lot of love, but let’s jump into this really quickly. Give me the definition of a Singleton.

James Simone:
A Singleton is an object that is initialized once and only once across the entirety of a program’s lifetime. Now within Apex and Salesforce in general, that means within the scope of a single transaction. That object is initialized once. No matter how many times it is accessed or called, you are always interacting with and using the same version of the object. So it’s a way to prevent unnecessary heap allocations.

Josh Birk:
Gotcha. So within the process of the flow, from the beginning of the flow to the end of the flow, if you have created that thing, every time you ask that thing a question, it’s, and I’m trying to put this in very good non programmatic terms, but it’s literally the same. It’s the same book that you would hold in your hand. It’s not another copy of that book.

James Simone:
Exactly. And that’s important, especially if we were to go with this book concept. Imagine that you want to return books to the library and that’s something that is not possible within Flow. In this hypothetical example, you only want to return the books that you have. You don’t want to return several copies of the books that you don’t have, right? You don’t want to lead to garbage data or bad data because something was duplicated. The Singleton helps to keep that clean. And something that I see that people do quite a bit when they’re using Invocable Apex with Singletons is to do something like logging. So you’re creating different log messages and you’re queuing them up within your Invocable. In fact, they have many different log messages, all being queued up between Invocable and regular Apex, and then have one single log that’s created with all the different messages that you’ve accrued over the course of both a Flow and Apex based transaction, so that you can go and read a discreet summary of everything that’s happened from both a declarative and code-based automation path.

Josh Birk:
Gotcha. So I think what I love about that example, since we can now bring it back to a book analogy is like, if you’re trying to read your log of what happened from the beginning of that flow to the end of that flow, you only want that one transcription so that you can go through and know, this happened and this happened then, this happened then. And the Singleton means that the same book is being written in no matter which domain you’re talking to you, right?

James Simone:
Right.

Josh Birk:
Gotcha. Okay. I believe the other thing you really touch on in the Invocable article, we were describing before, but let’s be very concrete about it. How does dependency-based injection work and why would you want to use it?

James Simone:
Yeah, this is the part where I started laughing again, because we’ve sort of been circling around this-

Josh Birk:
Right.

James Simone:
This word and in the same way that I feel like Singletons don’t get a lot of love, the Factory pattern doesn’t necessarily get a lot of love either within the computer science community. But specifically within Apex, I think that the Factory pattern has quite a bit of merit in terms of being the single stop shop where your objects are created. And the reason why think that that’s important comes back to the TDD approach that we’ve been talking about this whole time. What you don’t want to do is constantly be setting up and stubbing out different objects across your code base. You don’t want to constantly be having to stub out HTTP calls. You don’t want to have to constantly be adding in interfaces just so that you can swap out in an objects constructor the dependency that you’re relying on. What the Factory pattern allows you to do is centralize the way that objects are created so that you can also centralize the way that they’re stabbed out and mocked.

Josh Birk:
Gotcha. I almost feel like we could have just maybe repeated that line about, every problem can be solved with another layer. Because it feels, I kind of feel like we’re coming back to that point. The code is so hard to visualize on a podcast. So obviously we’re going to point back to your articles and hopefully people can read the concrete examples. As I joked with Mitch, if you’ve heard Singleton for the first time during this episode, there’s nothing better than actually looking in to see how somebody actually constructs something like a Singleton. But I kind of want to go back to like, your, and we hinted towards this a little bit at the beginning. Your title, like “Joys Of Apex.” It’s like not an accident. You kind of have this goal that people should be happy with their work and not having their unit tests taunt them for the end of their days.

Josh Birk:
Talk to me a little bit about the style that you’re using, because you said that you’re kind of working with Agile for Agile. What are you kind of doing from a team point of view to keep that joy in Apex?

James Simone:
It’s a great question. I think that ultimately our journey is so personal that you have to find meaning and happiness in mundane things, in order to experience excitement in a reproducible fashion. There was a comment that a Redditer had made on that very first post that has stuck with me ever since, and I don’t even post on Reddit anymore and I announce these things. But like, I can’t forget this person because their response to that very first “Joys Of Apex” article was so incredible. And it was in response to somebody else who was basically saying like, “Great, another thing that I need to read. ”

James Simone:
And I came back to my computer and I saw this, that somebody else had responded in my absence and they said, “Imagine that you always wanted to eat broccoli, but you hated broccoli. And you told yourself every time that you were going to eat broccoli, that you were eating ice cream instead. That first time that you go to eat broccoli, you know that you’re not eating ice cream, right? But every time that you imagine yourself eating ice cream over and over again, you might find yourself actually coming to enjoy the taste of broccoli.” And I thought that that was just such a beautiful response and encapsulated the way that I feel about writing code and the way that I feel about life in general, which is that not only do you have to find joy in everything, and hopefully that is an iterative process itself in your own life.

James Simone:
But when you do approach things from the perspective of what, “Can we do to make this better?” Instead of, “How did this get to be so bad?” You find yourself answering that question with different solutions.

Josh Birk:
And that’s our show. Now we will have a link to James’s blog, the “Joys Of Apex” in the show notes. Highly recommend that you check that out. And before we go, I did ask after James’ favorite non-technical hobby. And if this is something that you’re interested in and you ever catch James in real life, you can ask him a lot about it because not only was it his hobby for a while, he was a trainer.

James Simone:
Rock climbing. That would be my number one passion outside of programming. I haven’t had a huge amount of time to exercise that passion in the pandemic, but looking forward to getting back out there.

Josh Birk:
I want to thank James for the great conversation and information. And as always, I want to thank you for listening. Now, if you want to learn more about the show, head on over to developer.salesforce.com/podcast, where you can hear old episodes, see the show notes and have links to your favorite podcast service. We’re on the big ones, Google, Apple, Spotify, and a whole bunch of the little ones too. And are also available on your smart speaker. Thanks again, everybody. I’ll talk to you next week.