Episode 106: FFLib and Apex Design Patterns with Eric Kintzer | Salesforce Developers Podcast

Eric Kintzer is a Salesforce Architect over at Helix. Today I talk with him about FFLib and Apex design patterns. We discuss how his discovery of Andrew Fawcett’s book on the topic changed his entire perspective on architecture and development.

Eric describes himself as an all-singing, all-dancing Salesforce developer, architect, and admin. He has had to identify business needs, architect around them and then develop the solution himself. As a result, he has a very interesting journey and unique insights to bring. Tune in to learn more from him.

Show Highlights:

  • Eric’s Salesforce journey.
  • His approach to Apex and other complex programs.
  • How Andrew Fawcett’s design architecture book changed Eric’s career and life.
  • The four key design patterns in that book.
  • How enterprise patterns impact testing. 
  • What a mock object is.
  • How the FFLib project works and its many advantages.
  • How to migrate to FFLib well.
  • Why FFLib is important if you care about your craft as a developer.
  • How Eric got involved with Stack Exchange.

Links:

Episode Transcript

Eric Kintzer:
There was barely a security and it never got this stuff right. It took forever for us to get anything implemented. And I was just like national team. And then when I got onto the Salesforce platform, it was like, “Oh, this platform as a service, Salesforce does all the stuff.”

Josh Birk:
That is Eric Kintzer, a Salesforce architect over at Helix. I’m Josh Birk, host of the Salesforce developer podcast. And here on the podcast, you’ll hear stories and insights from developers for developers. Now, before we get on with today’s interview, this episode was supposed to air early in November. And through the month of November, Salesforce developer marketing is running the Salesforce developer survey. We would love to hear from you, get your feedback and opinions, and that is going to help us shape our tools, our resources, and our assets, provide you a better experience. You can find that at SForce.co SF Devs Survey. That devs is plural, and it is a capital S capital F capital D and a capital S for the survey. Now, today we sit down and talk with Eric about FFLib, Apex design patterns and how it kind of changed his world of development and architecture. We’re going to start with how he got into those particular roles.

Eric Kintzer:
I’d say I was a business analyst because I had to figure out what the user requirements were and all that kind of stuff. Then I was an architect of my own destiny, and then I had to implement it. And then it went through in life cycle management. And then I worked at VMware on their Salesforce sales cloud implementation. I built a quote to cash implementation for Zimbra, which is a email vendor. And then I moved to Helix, which was doing Genoa direct to consumer applications. And that was mostly architecture initially and then implementation.

Josh Birk:
Got it. So it sounds like you’ve had a kind of a unique life cycle with Salesforce because you sort of were your own business client that you had to architect and then actually develop too, as opposed to a lot of developers go the other way around.

Eric Kintzer:
Correct. It might be on my LinkedIn profile or my blog. It’s something like I was the all-singing, all-dancing Salesforce person.

Josh Birk:
I like it. Nice. How would you describe your approach to Apex and kind of handling complex projects before you got introduced to projects like FFLib and design patterns?

Eric Kintzer:
Sorry, I had to laugh. I guess the one word answer might be amateurish. I started off writing triggers. And so I wrote triggers in the way initial Salesforce programmers write them, which is sort of scripts. The trigger’s very long and all the business logic’s there. And I can even remember one project where I stayed up till three in the morning after I deployed something to production because it wasn’t working and it took forever. I finally realized that you can’t have two triggers on the same object because what they don’t order execution, it’s not deterministic. And so that’s why I say amateurish. It’s like I made all the mistakes.

Eric Kintzer:
And then of course you evolve to other things like, “Well, if you were writing logic about an opportunity, there should be an opportunity object in your Apex code base.” But there’s no concept of an opportunity object you can write methods on so you have to create a wrapper object to write methods on it. And then go, “Oh, service classes also has good ideas, let me have some service classes.” And so you stitch all these together and then test factories. I read assiduously online as best practices and what people were doing and sort of custom-built all my own solutions for that in those cases. Anyway, it reached a point where I knew that this wasn’t good. It was acceptable, but not good. It didn’t make me proud.

Josh Birk:
You knew some layers had to get added in somewhere to do some things and they got the job done, but you weren’t really happy about it.

Eric Kintzer:
Yeah. Long time ago, I read those books on design patterns, I’d read Martin Fowler’s book about business architecture patterns. And so I knew there were good ways to do things but I hadn’t quite figured out how to translate that all to the Apex platform.

Josh Birk:
Got it. Well, then the followup to that I think is when did you get introduced to Andy Fawcett’s design architecture book?

Eric Kintzer:
There was a Dreamforce I attended. It was probably my first one. The facts here are a little hazy. He probably had a presentation and his book was being sold in the bookstore. And I went to the presentation. I went, “Well, this is actually right up my alley. This addresses all my misgivings about my own work.” And I bought the book with my own money. No soft copy, hard but the soft cover book. I sat on the train as I trip home to Menlo Park. And I read the book on the train and I said, “This is going to change my life.” This is kind of weird, but I would curl up in the chair with the dog at my feet and a pencil.

Eric Kintzer:
And I went through every page of his first edition book, looking at the code samples, trying to figure out what he was trying to do and I’d make annotations. Not quite marginalia, but that kind. I said, “This is the solution.” And I wanted to understand it in every single detail so that I could implement it with confidence so that it wasn’t just… Because it was a big conceptual change from what I’d been doing before.

Josh Birk:
That’s interesting because you had already read Fowler’s book and it didn’t change your life. You read Andy’s book and it does change your life. Was the distinction because Andy had put it into pure Salesforce-centric, Apex-centric terms?

Eric Kintzer:
Yes. Absolutely. For sure. Not only that, but there was a GitHub library to download that provided the implementation framework.

Josh Birk:
That was going to be my followup question. I remember that Dreamforce. I do find it very strange that we’re having a conversation about a book that I believe I wrote the foreword to.

Eric Kintzer:
You did. I remember that.

Josh Birk:
Every now and then I’m in a meeting with Andy and I’m like, “People will remember that. His book is that famous.” It stands out in everybody’s mind.

Eric Kintzer:
But only to people who’ve read it. For a lot of people who haven’t read it, ignorance is bliss for now.

Josh Birk:
Right. Okay, so let’s walk through some of the basics of these design patterns. What are the patterns that are laid out in the book from a high level?

Eric Kintzer:
Okay. So there’s four key patterns. The first one is the selector pattern. The selector pattern tells you to put all of your SOQL queries into a separate class, generally one class per object. And the selector pattern solves a couple of issues, three issues, really. One, it allows for a query builder pattern so you can compose a query with not just the fields on the object you care about, but the related objects. And you can reuse those elements over and over again at different queries. So you don’t have to do what you would do in a classic static SOQL world, which is think about, “Which fields do I need?” and then, “Which related fields do I need?” And then you have SOQL queries scatter all of your code, some of which are sort of like the other, not quite, they’re all sort of custom tailored to every specific use case, when you really should just have select opportunity by close date or select opportunities by account select contacts by email.

Eric Kintzer:
If you have a set of standard reference queries that your code can use over and over again, then you don’t have to write the SOQL more than once. So that’s one big advantage of selector pattern. And the other one is it’s markable, which we can get into later. We’ll talk about Apex marks. So that’s one layer. The second one is the domain layer. So this gets back to my comment about most people quickly realize you want to write methods on standard or custom objects but there’s no Apex class that you can do that with. So the domain pattern, essentially events, the domain, the opportunities domain, the context domain, the quotes domain allows you to not only put all your trigger and/or logic in there, but also other methods that are relevant to that object as a domain. So that’s super-useful. It’s immediately bulkified and eliminates creating these weird opportunity wrapper objects.

Josh Birk:
Yeah. Well, I was going to say this one sounds kind of profound for how you were describing the layers you were adding before. This one sounds like it’s the mature approach to what you were looking for.

Eric Kintzer:
Yes, correct. Absolutely. And it also addressed the… Everyone knew you needed a trigger handler and you just realized that the integration of the trigger handler with the domain was the right answer. So then the third part of the pattern is the service layer. So the service layer is where you implement most of the business logic and you do it in a way that it’s invokable from different clients. And so the clients would be domains. The clients could be Apex REST clients. They could be Apex invocables, they could be controllers, time visual force controllers. And the service layer was sort of agnostic as to how it was called, usually passed IDs in. And then the service layer would do whatever logic needed to be done, perhaps calling other services, but essentially encapsulating your Apex logic and well-defined layers and methods.

Eric Kintzer:
And then lastly, you have the unit of work layer. This was the hardest one to understand initially. Unit of work layer was a way to abstract out the set of DML that needed to operate together as a transaction and that could be potentially rolled back if any part of it failed. But the bigger advantage, at least in my opinion, the far and away bigger advantage of the unit of work pair is it allows your services or anything else that’s doing DML with the unit work pattern, the unit of work can be mocked and you can then verify that you’re updating or inserting or deleting objects without ever having to do the real DML in your test methods. And this is huge. It’s just so important. So the unit of work pattern to me, its biggest advantage was in testing.

Josh Birk:
Interesting. Walk me through that a little bit, because I feel like developers often have kind of a contentious relationship when it comes to sharing rules and making sure that the DML is not as simple, it’s as robust as it needs to be and things like that. So how does that impact testing to that important of a degree?

Eric Kintzer:
With all testing, in some part of your testing, you have to actually do the DML because otherwise the validation rules never execute and some other things like mixed DML errors will resurface. But most business problems are testing that you’re updating a record with the fields that you’re expecting to update it with, or you’re inserting record with the fields you expect to happen. And so when you do a unit of work, it’s hard to do this orally, but you effectively say you need to work with local variable.register new parentheses, and then the S object that you want to insert. Or unit of work.register dirty parentheses the S object you want to modify. And because the unit of work can be mocked, you can verify that the S object you registered is equal to an expected S object that you think you should have registered. And you don’t have to query the record in the database to find out if you updated it correctly.

Eric Kintzer:
So when you have lots of business logic that has all these various use cases that you’re testing or that you should test, you can create your unit test with mocked objects, and then verify that the DML that you would do matches other expected S objects and you simply avoid the need to re-query the objects to find out if they were updated right. And when you have a lot of test methods, this is, I guess the other key point. When you have a lot of test methods, which you should, when you do run all tests and in a dev environment or in the CIO or wherever, then you can take a long time. In my orgs, 30, 40 minutes. If I didn’t do mocking, then the length of time for the tests goes off even longer because you’re spending time in the database either updating or querying it. And the enterprise patterns essentially allow you to sidestep a lot of that for use cases that you don’t really need to do the DML or the querying and/or that can prove that your code worked.

Josh Birk:
Let’s dig into mocking a little bit since we’ve been talking about it a lot. So give me the technical definition of what a mock object is.

Eric Kintzer:
Okay. The technical definition would be if you’re querying an object, if you would do a SOQL query, the mocked object is what the SOQL query would return as S objects without doing the actual query. So if you have a query that’s select contacts by email, the mocked object is a list of contacts with whatever fields you care about for a unit test and including the email. And your unit tests never had to query the actual database. Instead, it calls the context selector and the mock implementation of that returns a list of S objects that you need for your test, rather than having to insert contacts and accounts with the values you care about such that when you query them, you can get back those values.

Josh Birk:
Got it. So between the selector layer and the unit of work pattern in a mocked object, you have a layer of data, which is basically ephemeral, not an ephemeral, I guess, but it’s just what the logic needs to talk to without actually… You don’t talk to the database until you absolutely have to.

Eric Kintzer:
That’s correct. The selector layer allows you to mock the results of queries without having to insert records to start with so that you can then query them with SOQL.

Josh Birk:
So let’s talk a little bit about the code itself. I was trying to remember that year that Andy had the book and did the presentation and I was getting familiar with what he was talking about, but FFLib existed back then. It was a companion to the book and to the presentation. So walk me through a little bit of the FFLib project and how does it make it easier to implement all of this?

Eric Kintzer:
Well, first you install it.

Josh Birk:
GitHub clone, yes.

Eric Kintzer:
And then you look at your business logic and if you’re doing, let’s say opportunities again, you figure out what queries that your application’s going to need and you write, you define a class called opportunities selector. It extends the FFLib as objects selective class, which provides a set of common methods that you can exploit like the query builder methods. And then you code a method for each of your query, so you would have a method called select opportunities by account, for example, and it would be passed in a set of account IDs. And that method then composes a query. You can do it in static SOQL if you want but I always use the query builder, which define the fields I cared about from the opportunity. For every opportunity you select or query, it would always return the same set of fields.

Eric Kintzer:
And then if I needed to get the parents like the accounts of the opportunity, then it would call the account selector, which also knew which fields it always returned. And that composition would generate a SOQL query that included my opportunity fields and my parent account fields. I’m simplifying this, but that’s how you would do a selector. And then you’d have many of them. And if you did batch jobs, you could write selectors that would return query locators.

Josh Birk:
Got it. Okay. And you used this and you went back to, and correct me if this statement is incorrect, but I believe when we talked previously, you said that you went back and started refactoring all of your orgs to start using these patterns. First of all, why did you feel it was like that important and how hard was that process in general?

Eric Kintzer:
It was important because of two reasons. One, I was sort of embarrassed by my previous work. Most software developers are craftspeople, so they should be proud of their work. And I’d seen a better way to do it and I was not happy with what I had before. I was maintaining this code too. It wasn’t like I was a fly-in consultant tossing some Apex and then fly out and let some other poor bastard maintain it. This was my work so I cared about it. How hard was it? You took one object at a time and you took the easier ones first to make sure you understood to work the patterns properly. And it got easier as you did one object after another, you sort of realized where the pitfalls were. What you had to learn, the gestalt you had to understand really. That’s true of any pattern that you adopt, it expects you to think in a certain way and once I thought that way, then it became easy.

Josh Birk:
So it sounds like it was kind of a gradual process. You had your old code still running and then you just slowly picked parts of what you… You kind of just slowly layered, the sentence sounded like.

Eric Kintzer:
Yeah. I guess it was probably some story that was motivating me to have to go in by the code base or specifically some objects that were going to have to be a touch. Let’s make this the initial use case for FFLib.

Josh Birk:
Got it.

Eric Kintzer:
Let me just finish here. Once you started on this, you realized that you were on this trail. I wanted to get the whole org converted as fast as I could. I didn’t want to have two styles of implementation in the code base.

Josh Birk:
Got it. Do you have any words of advice for people looking to do the same thing?

Eric Kintzer:
It depends on whether you’re a sole practitioner or you’re working on a team. If you’re a sole practitioner, you should do it sort of the way I did. Pick an object that still doesn’t have too many methods that you have to implement, learn the pattern and make it happen and then you’ll realize how to migrate the rest of your code base. If you’re working on a team, oh boy, I have done this. What happens is if not everyone has bought into the FFLib style and you’re fighting architecture wars, or it’s almost like fighting coding style wars, where should your left curly brace be on the line? It’s mentally draining. So in that case, I’d say somebody has to make a decision that FFLib’s going to be the pattern and then people just have to suck it up and sort of make it happen.

Eric Kintzer:
But it won’t work if it’s just your part. If you’re on a team of three people and you’re responsible for one part of the system and the other members of the other part, you do an FFLib and they don’t, I think that’s a mistake. Unless you think they’re going to leave and then you’re going to take [inaudible 00:23:21].

Josh Birk:
I think you kind of touched on this a little bit earlier, but is that because you’re kind of defeating the purpose of FFLib if it’s not universally accepted.

Eric Kintzer:
Yes, that’s right. Or at least does it represent the core aspects of your business application? It shouldn’t be peripheral. This is what I think people don’t get with FFLib is first of all, it’s very well-constructed. And the advantages of using all of it, it’s like a network effect. You get more advantages the more you use all of it. If you just adopt a little bit of it, you don’t get that much advantage, but you see, particularly in the testability of things, that adopting the whole pattern yields enormous benefit.

Josh Birk:
And tell me a little bit about the other side of those architecture wars. What’s some of the fights you’ve seen? Are these people who either have a competing design pattern, which I’m not familiar with many competing design patterns, which is one of the reasons I ask, or is it like their custom-built design pattern that’s like their pet project and that’s why they don’t really want to hear about competing patterns?

Eric Kintzer:
Yeah. It’s the custom-built design pattern. Almost everyone you meet in the Salesforce Apex world has worked somewhere else, has sort of developed through organic methods a way that they found comfortable for solving problems on the Apex platform. And it’s very hard to get people to move off of that.

Josh Birk:
So I hear in my head two things that I think go through developer’s minds when they start hearing about things like concepts like this in general, and then also like going to develop them. First of all, a developer might think, “Well, I’m not really an architect. I’m not like this kind of computer science nerd who’s gotten into Martin Fowler’s book.” and things like that. So if I’m not Andy Fawcett, should I bother even trying to understand this kind of stuff?

Eric Kintzer:
Well, let’s look at it this way. Apex developers are familiar with SOQL, for sure. They have to be. They, no doubt have realized that their code base, if they’re on a sufficiently large code base, is littered with SOQL all over the place. So consolidating all of that into a selector layer is not that big of a leap. Services, unless Apex developers are just trigger happy and that’s all I know, most Apex developers have figured out that a service class is useful. So adopting the service layer isn’t that complicated. The domain trigger handlers, everyone knows they need a… I won’t say everyone. If they’re even listening to this podcast by this point, they should know that they should have some sort of trigger handler pattern. And we have many examples of those out there. So once you realize that you can combine the trigger handler pattern with the need to write methods around the objects themselves, which is almost inevitable that you will, then the domain pattern’s pretty easy to understand.

Eric Kintzer:
And if you sit down with Andy’s book, which I certainly recommend, I have bought all three editions, and you look through his examples, you’ll realize why the unit of work pattern is particularly useful. I think the harder thing for developers to learn is Apex marks. I think that’s a bigger leap. The FFLib pattern is not that hard to understand. The domain perhaps has also been tricky because people want to write wrappers around single objects so a single opportunity object. The concept of writing a wrapper around a collection of opportunity objects and treating it as a domain just like the trigger is on a collection of opportunities. That’s a little bit harder for people to get, but once you do it makes perfect sense.

Josh Birk:
So it’s kind of like a slippery slope. Developers eventually are going to figure out they need some kind of trigger frameworks. They’re going to eventually figure it out they need some kind of object handling framework. They’re going to eventually figure out they need some kind of query framework, so why not use these? Is mocks harder because that eventually isn’t really true? Some developers just don’t realize that they don’t need to talk to the database all the time.

Eric Kintzer:
I think that’s a great comment. You can obviously test an Apex application by inserting test objects and querying for them after you do your code under test. You don’t need mocks. Mocks are there to, as I said earlier, reduce the amount of time it takes to execute your code and when you run all test methods and be, and it also tends to also save elapsed time, an easier way to test all the variations of minor code paths that you have to implement and verify in a typical business application. You don’t get the examples that they post on Dreamforce and stuff like update the close date or the opportunity. That’s the only field you’re updating. Real business applications are never that simple. And they involve all sorts of if this, then that, many branches of special case. Mocking makes that a lot simpler to test so you don’t have to implement lots of test, concrete objects.

Josh Birk:
And I think there’s also an argument I’ve heard, or maybe it’s bounced around my own head, which is kind of like, “When I’m writing, it isn’t that complex so why should I bring bare all of these framework-type of thing in order to just get these few things done?”

Eric Kintzer:
Yeah. This falls into the category of creeping incrementalism. I was like that too back in 2009, ’10, ’11, ’12 period. If you’re not going to be living with a code base for a while and/or… This was certainly true when I was at Helix. If you’re not in a culture that values engineering, then I could see why developers would say why bother. But if you’re a crafts person, and this is the message maybe I want to leave with listeners, is if you care about your craft as a developer and you want to build things that will last as much as possible, and you expect to be maintaining this for many years, then doing it right the first time saves time and money in the long run. If you’re a hired gun dropping in and out and you don’t care about what you’ve left behind as long as the client sort of signed off on the work, well then sure. Don’t use FFLib.

Josh Birk:
Got it.

Eric Kintzer:
If I were an ISP, which was what FinancialForce was when they built FFLib, that’s code-base that you’re going to maintain year after year so why not?

Josh Birk:
Right. Why wait for the complexity to begin itself? Why not be prepared for it?

Eric Kintzer:
Exactly. And one of the things that I didn’t say earlier, but I think is super-important is FFLib means most design decisions just drop out as what you should do, where do your queries go? They go in a selectable layer. Where do your services go? You write services. Where does your domain logic go? You write domain classes. And they all talk to each other and you don’t have to invent any other concepts, that’s it. Three concepts for your code.

Josh Birk:
Okay. Changing gears a little bit. When did you start getting involved in Stack Exchange?

Eric Kintzer:
When I was a product manager back at that ringtone company, when we had so many problems, when things wouldn’t work, I developed an in-house application that essentially was a database, it’s like a company FAQ. If you get this error message, this is what the solution is and this is how you work around it, because we’d see the same problems over and over again over the course of years. So when you work the Salesforce world, and of course you have questions, you type into Google and Stack Exchange comes up as answers, and you realize A; it’s curated, B; it’s curated way better than the Salesforce developer forum was at least at the time.

Eric Kintzer:
And you don’t have answers where people are hawking for if you liked this answer, please like this because they’re trying to build up reputation for some job interview they were working on. So Stack Exchange was much more professional. And the people who were contributing to it at the time, people like Bob Bazaar, [Kera 00:33:30]-

Josh Birk:
[Kera Boden 00:33:31].

Eric Kintzer:
[Kera Boden 00:33:32], right. He was a big contributor. Andy Fawcett was a contributor then. I think Peter Knowles was a contributor. These guys were smart. Brian Fear, SFDC Fox was a contributor. So they were smart guys writing really clear, concise answers and I liked that. So I would start answering questions because I knew the answers to some of the things. And you do get reputation points for it and you see that people appreciate your answers. And so you realize, “Hey, I can contribute back to the community because I’ve learned a lot about Salesforce myself so why not help others?”

Josh Birk:
That’s our show. Now, we will have links in our show and the various resources we’ve been talking about today in case you too would like to have a life changing event with Apex design patterns. We will also have a link to the Salesforce developer survey. Once again, Salesforce developer marketing would love to hear from you so that we can provide you the best developer experience possible. That survey ends November 30th, 2021. So if you are hearing this before that date, please fill it out. And if you’re hearing it after that date, well catch us next time. So before we go, I did ask after Eric’s favorite non-technical hobby and it’s a pretty unique one.

Eric Kintzer:
My favorite non-technical hobby is I do fine scale modeling.

Josh Birk:
Really? Like what kind of models?

Eric Kintzer:
Things about my family, so family history things. My mother-in-law’s boyfriend flew as the wireless operator in a fairy swordfish on the attack on the Italian fleet at the Toronto Harbor in 1940. So I built a model of that swordfish airplane.

Josh Birk:
I want to thank Eric for the great conversation and information as always. I want to thank you for listening. Now, if you want to learn more about this 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. Thanks again, everybody. I’ll talk to you next week.