John Daniel, who joins to talk about Unit Of Work, is a Salesforce MVP, Technical Architecture, Open-source active contributor.
John was on show #13, talked about Monolithic to Modular.
Sponsors
This episode is sponsored by FormAssembly.
FormAssembly and Salesforce eBook – Find out how FormAssembly helps Salesforce customers optimize their data collection.
Main Points
- John’s self-introduction
- The definition of UoW
- How does UoW handle DMLs in a transaction?
- What would happen if the DMLs in UoW fail partially?
- How does UoW make the code cleaner and more business-oriented?
- What to do when we find bugs when using the open-source libraries?
- What is the benefit to convince the team to use Apex Common library where UoW is included?
- Are there situations where multiple UoW instances are needed?
- What are the limitations of UoW?
- The news that FinancialForce will hand the fflib ownership over to the open-source community.
Links
- John’s Twitter
- John’s LinkedIn
- Unit of Work defined by Martin Fowler
- Apex Enterprise Patterns Open Source
- Apex Common repo (file search enabled)
- Andy Fawcett’s book – Salesforce Lightning Platform Enterprise Architecture
- Several blogs from Andy Fawcett touch on the Unit Of Work concept
Video Teaser
Contact Me
If you enjoy this podcast, please reach me out to let me know your thoughts or simply say Hello. My (Xi’s) contact info:
Take care, until next time :)!
Transcript
AI-generated, unedited.
[00:01] I'd like to welcome our sponsor, Form Assembly. Form Assembly's all-in-one web form platform lets you create forms for just about any use case. From contact forms to donation forms, all while taking advantage of useful features such as notifications, e-signatures, and more. Not only that, but you can also connect data to systems you already use. FormAssembly integrates with Salesforce, Podio, PayPal, and many other common solutions. You can find out how form assemblies help Salesforce customers optimize their data collection in a free ebook that we've linked in today's show notes. Whatever your data collection needs are, you can be sure that Form Assembly keeps your data secure with encryption at rest and in transit on all plans. Plus compliance with GDPR, CCPA, and more regulations. At the end of the day, formas simply helps you save time, money, and effort while getting the maximum benefit out of the data you collect. And I'd remind you, when you support our sponsors, you support the show.
[01:28] Hey everybody! This is Xi Xiao. This is yet another new episode of Salesforce Way podcast. Today I'm sitting with the returning guest. His name's John Daniel. Hello, John. Really nice to see you. Good to see you, Xi. Thank you very much for the invite. Good to be back. Yeah. So one year ago we had the conversation. I remember it's about our managed package or something like that. The second generation packaging, right? It was really generation packaging. Yeah, it was really famous. A lot of listeners, you know, we got and the people appreciating for that. So today I want you to return here, talking about a interesting topic. It's called unit of work. Just listening to this term, if you haven't heard about it before, probably have no idea what we're talking about. What is unit of work? So would you mind to really define what is unit of work? Sure, absolutely. So, unit of work is nothing more than a software design pattern, and that's really all it amounts to. You know there are various software design patterns out there. This one has been around, I think, somewhere between fifteen and twenty years, I know of. I first heard about it in the early 2000s, and the first place I originally heard it was by a gentleman named Martin Fowler. He's a technologist and a big thought leader in the world
[02:58] of just general programming and architecture. He wrote a book called Patterns of Enterprise Architecture. And it was, I think, it was chapter eleven of that book that went into depth about what this concept is. So, at the the simplest idea about what the unit of work is. It it allows you to simplify your code when you're dealing with lots of DML statements across multiple related data objects. So. Probably one the easiest example to think about is, you know, the data model in Salesforce has the Opportunity object, and that has the Opportunity line items. And then the opportunity line items has a price book entry, and price book entry has related product entries, and so you've got this interconnected data model. And you might develop a service, basically an Apex process or something like that, that has to create lots of records all at once. So without the unit of work, what you end up having to do is well, you have to insert all of your Product records, or excuse me, the opportunity records, and because you need you need to grab each one of those with their IDs, so that you know how to populate the opportunity line item records that are associated to the opportunity, and you you've got to be careful because. If you were just inserting
[04:29] every opportunity and then one opportunity at a time, and then inserting one opportunity line item at a time, then you'd quickly blow out the DML limits on an Apex transaction. So when you when you factor in the fact that you've got to make it all bulkified, then that logic is lots of lists, lots of maps, twisted logic, and all of that is strictly it's got nothing to do with your business logic. It's just how do I get all these data objects in there. It's a long definition. I think you have covered a lot of important information. Yeah, let's let's break it down. One thing I hear from you is the keyword related object. What if it's not related object? Does a unit of work really help us the design pattern? Yeah, I mean the unit of work is good because. You know, you don't have to worry about when do you insert object A versus object B. And again, you can just, you know, it's a good practice to keep all of that towards the the lat the end of your process. And so, just make it one simple area that where you do all the DML. And so, you always know exactly where to go look in your code for DML failures or or what that point is. So, yeah, it can easily keep track of unrelated objects. Sure, it's not as It's not always needed. It might be overkill, but it's again, it's the like all design patterns. They're just you get into habits of good practices, so it easily handles the bulkification process as well.
[06:00] You mentioned the unit work is a design pattern, and then there's a unit work library, right? Coming out from the AFAA library, so that's the implementation in the Salesforce world. Just make sure we understand. Okay, okay, and. In addition to that, you mentioned unit of work. How it really works is that we create an instance, and then we pass that instance into our transaction thread, into different classes, one after another. Somehow, I always think of it as the bucket. You pass that bucket into the classes. And then you collect the DML actions, right? You don't do the DML actions on the fly. You just collect those actions into the bucket, and in the end, when you pass out that bucket, and then you say, "Now let's make a commitment of all the DMLs." That's the time we make the commitment. Yeah, if you really do implement a large codebase and and really implement the concept of separation of concerns, what you're going to have is a lot of Apex classes. They have very discrete purposes. You might have some service classes that deal with larger transactions and orchestration of larger transactions. You might have Some domain objects that have very discrete operations that they'll do on specific records, and so while that is a very good practice to get into, you're
[07:31] you're also dealing with the question of well, as part of this entire. Transaction. I want to, you know, do some DMLs here. Want to do some DMLs in this object, and so it's a question of how do I thread all those DMLs from all those distinct classes together in some sort of organized fashion. So what the unit of work really does is, again, it's it's like you said, it's an instance of a class, and you just basically pass it around all the methods that you are executing for the various things, and then usually it's created in the service, which is usually the beginning of this larger business transaction. And when at the when you're done calling all these different threads and domain objects and whatnot, then you the service just goes ahead and grabs the unit of work and just commit all the work, and it's at that point at the end of the business transaction when all the DMLs occur. And so, one of the nifty things about the the unit of work pattern is that it understands the data relationships between all the objects that you're dealing with. It understands the concept that the opportunity object has to be inserted before an opportunity line item. It understands that a price book entry has to be inserted before opportunity line item because it needs all that information and needs to. Do all the mappings at a run, and so it handles all that complexity at the at the end. Okay, so in the sense that it keeps the relationship, it keeps the order of the DML actions, and then you just say run, and then
[09:01] you do execute one after another. Just out of curiosity, what if some of the records failed? What would happen? Would the whole trans transaction roll back, or are you able to define?
[09:14] So, um. In the default implementation of the unit of work class, what you'll see is that at the at the if you really go look into the bowels of the default implementation of the unit of work, what you'll see is eventually you come to the standard Apex insert statement, the standard Apex insert up update and and delete statements, and so those standard statements basically are all or nothing transactions. And so what you end up doing is is if any one of the records, maybe you have ten, if if one of them fails, then the entire group is going to roll back. The entire group won't be inserted or updated, and all of the transaction, it it'll just bubble up a DML exception, and everything will stop. And so that entire transaction boundary, you know, everything will roll back and you'll be fine. The implementation, the unit of work implementation, has various hooks and techniques where you can override that. So if you're familiar with the Apex command, the database dot insert command. And the database dot update command and the database delete command. There is an optional flag on those methods that says, no, I don't want to make it all or nothing. I want to make it basically atomic transaction. So you could set up your UOW to just go and save and commit anything that it can, and give you the information back of the things that failed. So it's very flexible from that pers. Okay, and so you've got lots of control that
[10:44] you can exercise in whatever direction you want to go. Just to add my experience of using the service layer out of the separation concern concept. Is that usually when I use the unit work instance from the service layer, I wanted to go with this none or all. If something failed partially, I don't want it partial DML actions, right? And the next time, what what should I do? How do I know how many records were inserted in the last run? And now I do it again, so that makes the life really difficult. So if something failed, I want everything rolls back. So most of the time, that's that's the things I want to happen. Yeah, I mean, in the in the example with opportunities, if one of the opportunity line items fail, then sure, you want the opportunity line item. All the opportunity light items associated with that parent opportunity to all roll back, but there might be another opportunity with a whole another set of opportunity light items that you want to go ahead and let that go through if that saves correctly. That's a possibility. Again, it's it's all about what is your business use case and and what do you need from there. So okay, but I mean you know you know another thing is while this class is part of the Apex Common Framework, you actually don't need the full Apex Common Framework. To utilize this class, the class is very well written. It came from the guys over at Financial Force originally. It's part of the entire Apex
[12:15] Common Library. And their implementation is very tight, and you literally can take this class plus its associated test class, and just drop it into your codebase by themselves. There's no secondary dependencies on anything else. Okay. So if you only want to take advantage of the unit work, just drop that one thing in there and just use it. That's nice to know. Yeah. Take advantage of those kinds. Yeah. Okay, I got it. Another thing I heard from you is that you can reduce some intermediate code. Like the map, the list. When we do the DMLs, especially in Salesforce world, we want to bulkify. When we insert a lot of account records, for example, we want to create the list. We want to add them one by one into the list, and then do the insert. And the unit work can really save the code to make it more clean, more like business oriented. Absolutely, absolutely. Because it maintains the interconnection relationships between parent records and child records, and say grandchild records. What happens is it. It knows that say say you're dealing with the parent records in account record, and it knows that it can do in one DML one DML insert. It will insert all of those account records. Now they're not related to each other, but it does all of that S object and it drops them all as fast as it can. And then it knows the relationship to say child contact records or some other record, maybe a case
[13:45] record or something like that. And so it knows that it can go process those, and it still remembers each of the individual relationships. And so it maps the IDs from the parent account record down in there, and then it just does a bulk insert or bulk update or whatever of say the contact group of records. And so it goes through each of those stacks. So, the number, which is good, because it bulkifies, and the number of actual DML statements is drastically reduced. You know, it's not a concept where you're doing a single DML inside a for loop or something stupid like that. Yeah. Yeah, yeah. But you know, it definitely will optimize to as few DML statements as possible. Okay. You know. One of the benefits of using open source libraries that can reduce the, the codes, the unnecessary code you are writing. Right, you focus on the business requirement, but the thing is that I need to trust the code from the library. So what if sometimes I found some bugs and something doesn't work as as how I used to work? Like you just use the insert from the Apex, and then that makes the life of a consultancy difficult, right? It should work within a day of work, but now it has a bug. Then what should I do? Should I tweak or should I submit a request? That's usually I hear, you know, as a challenge for for the people using the libraries. Um. Well,
[15:15] I guess I mean that's true with everything, and um. So I guess you know it's it um it's it's difficult to respond to that. I guess you know if if you're finding problems with Salesforce, you know that's it's not open source, so you've got to call their support. Um, you've got to be you've got to open a case and get that done. With the open source libraries, it's very easy to. You know, go straight to the source code, fork that repository. I mean, all of these libraries live on GitHub, and specifically, they live under the the GitHub organization Apex Enterprise Patterns, and we'll talk about that a little bit later. But I mean. Fork it, and if you if you see where the the problem is, go ahead and fix it, and open up a pull request so that the maintainers of that repo can review. And you're just helping, you know, them get and everybody else really helping them get that quality even higher for these repos. So good comments. Yeah, you're. It's a community driven. It's community help. You know, it's it's one community member helping another community member, and so we're all in this together. And and you in like you said, you know the the frameworks solve a lot of the common problems and the common plumbing that we need. And you know, I I like to consider myself very. Ambitiously lazy when it comes to
[16:45] development. I don't want to, you know, do the stupid, you know, mind numbing, repetitive tasks. I want something that you know can come in and solve my problems, and then I can get into the more interesting aspects of my job and my development and projects. So you know, I don't want to reinvent the wheel all the time. So I just want it to work. In that sense, because Apex is still like a sibling of Java, and the the syntax is still a bit old, and definitely without the unit work, there's a lot of codes unnecessary code we need to write, like do a lot of for loop. Create a lot of lists and the maps just to fulfill the the the needs, but here, by using Apex, we can build additional layers on top of that to hide the complexities. Yeah, I mean, because again, if you're dealing with a very simple, uh, you know, a very simple controller behind a a Lightning page that does, you know, a very quick insert, well, okay, that use case is very simple and very easy to do. It's it's basically the hello world. But when you have, you know, a large enterprise or or larger organization, lot, you know. Thousands or millions of lines of code, you you've got to bring some organization to that code base. You've got to bring some consistency
[18:16] and some sanity to that code base. And so these frameworks definitely a step in the right direction. They help. They help new developers because I mean you got Salesforce. A lot of times, once I've met Salesforce developers, and this has been their only programming job, and and I find it interesting because, you know. They come and they learn and they and they get on Trailhead and they learn the basics about how to program. But you know they haven't had the experience of dealing with very large code bases and how to keep the the organization how to keep everything sort of interconnected but loose. You know these simple concepts like loose coupling and separation of concerns they've just never had that experience. And so these frameworks are a great way to learn those types of patterns that. You know, I learned about you know because I'm I've been around since dirt, but you know I I learned about it from in other languages. But then you've got people like Andy Fawcett. Who, with his book, the Salesforce Lightning Platform Enterprise Patterns book. Yeah, if you've got a developer out there who is serious about any kind of real development, they need to read that book, Salesforce Lightning Platform Enterprise Patterns, and and really that book is an adaptation of, like I said, Martin Fowler's Patterns of Enterprise Architecture. The these these concepts these design patterns have been time proven and time tested, and you know they they they these patterns keep sticking around because they're useful. They work. They simplify a lot of the maintenance and a lot of this the construction of this. And the UOW of pat
[19:46] the the unit of work pattern, excuse me, UOW. Is a beautiful example of this because it just makes life so simple. Yeah. Sorry, I'm just rambling. Yeah, it's fine. It's fine. I mean, since we're already sidetracked, let's talk a little bit about. Your working experience, so you, I think, you are definitely an advocate of effortful libraries and some other design patterns. So, during your work, if the team is not using those libraries, do you try to convince them to to use them and let them get the benefit out? Oh yeah. Okay. Yeah, I mean, because when you're dealing with teams, you you have to get you know you have to get the team unified in a single direction. Everybody has to know kind of where everybody else is going and how, you know, what what the the coding constructs are. If you don't have that, then the team synergy will not be there, and the teams won't be efficient. You know, there's so many different. Ways to do things, and and the you know yes like you say I'm I'm a big advocate of the enterprise patterns the Apex Common Framework the Apex Mox Framework the Force DI frameworks the At4DX frameworks all these different open source ones around enterprise patterns partly you know they definitely work they're not. I I never make the claim that they're the perfect solution
[21:17] all the time, but they are. Probably the most popular out there. They are probably the most prolific out there, and you know if you if you pick up experience in one job. Using these frameworks, it makes transitioning to the next job so much easier because you already have this experience. And you know, there was a gentleman that I worked with, and he had learned how to work with the Apex Common Framework in a previous job. And so I started talking to him about you know our designs for our project, and then I started using terminology that you hear in the Apex Common Framework. You know, service layer, domain layer, selector layer, the unit of work, and he immediately clued in and knew exactly where I was talking. So it fosters a good. Consistent vocabulary about how to express the design, and that is critical. You know, again, coding a solution is actually pretty simple in the grand scheme of things. You know, one of the the biggest struggles a lot of time for developers is expressing and articulating the solution to lots of different people. And so you know these types of patterns help you know young developers especially figure out how to talk about things in a consistent manner and and and view things in a consistent manner. And you know if they talk about all these different frameworks is is. A a tool to help teach things like bulkification, especially which is important in the world
[22:47] of Salesforce. But I mean, you know,
[22:51] yeah. So I can go. Yeah, yeah. Thanks for that. Let Let me drag you back a bit. So. The unit work. Let's say if I use the unit work instance in the service layer, I would assume usually we just create one instance and pass it in, right? Does it mean the whole transaction I only create one instance, or is there some situations that create multiple instances? There are. There are a couple of times where maybe two unit of works are needed. Maybe you have to cause a slight delay to let certain background processes run from the first commit. And then you will pick it up, requery the objects, and and utilize
[23:42] a second unit of work, a clean, fresh unit of work, and do a second commit of that work down the road. There's a couple of I'm trying to remember a specific example, but. Most of the time, a business transaction in Apex can be accomplished with one unit of work. It's very rare that it's not. But yeah, but there's nothing stopping you from instantiating two different versions, just passing the ones that you want around, and then just execute the commit in the order that you want. Usually, it's UOW one and UOW two, and I'm going to commit work on UOW one, and then come later I'll commit work on UOW two. Okay. After conversation with you and all these design things around the unit work, the thing is that I feel it's so simple to use. Everything is encapsulated. Everything is like taken care of for you. The relations, the DML actions, and you know all the orders. So you just. Push the things into the bucket, and in the end, they just make the commit. Basically, two things, three things you need to do: create the instance, push in the DMLs, make the commit, and in the end, right. But are there any things that the implementation of the unit of work in FFLP cannot really handle? For example, I heard. For example, if a relationship is a lookup field into yourself, there are some objects that are doing things like that,
[25:12] right? If you have a contact, you have field that lookup into yourself. So, yeah. If you have a recursive lookup, what you would end up having to do is have multiple unit of works, and so you would do the first. So the the parent record, you would go into the first unit of work, and then the child record would be set up for the second unit of work. Now it's a recursive back to the same object. And so that's and so the unit of work can't address the recursive nature of lookups, but you know lookups to other other objects it doesn't really problem. But yeah, that's a sort of a special case versus a normal type thing. But again, you know two or multiple unit of works will handle that just as fine. So basically, what do you mean is that really look into the code to see how it's implemented. If there is a limitation, you understand why there's a limitation, and then maybe you can easily find a workaround. That's a power of the open source. Yeah, absolutely. And I mean, like I said earlier, if you really, if you really open up the source code of the unit of work class and see how it really comes together. You'll notice where the hooks are to, in you know, adjust it. Maybe switch from all or nothing transaction to atomic transaction, or to address certain aspects. You know when platform events first emerged, we were able to code a additional piece of work logic, essentially. And add it to
[26:42] our unit of work instance, and because of the way the unit work was set up, we just said when you get to the end of the um the commit cycle, go ahead and process these platform events. Now, since that was about two years ago when that happened, but it was very easy to extend and plug in extra units of work into the the main unit work and and have it adjust and expand. Since then, unit of work has. Gotten first year support for platform events going forward because it was again it was something very simple and very we just opened up a pull request to the main repo and it was accepted and but yeah okay but you know it's that kind of things when new things come about it's very easy to add that's cool I didn't know it started to support the platform event. Cool. Yeah, and I mean when I say support, it just it handles the sequence of when it actually um uh puts them in. You know, we added a couple of hooks to say do it, do it, send a send these platform events if we got a DML trans uh exception. Ah, okay. You know that that'd be kind of cool. Now, now the platform you know does some of that now for us, but still back in the day it was good stuff, and it made it a very simple way to you know fork the logic based on what was going on. Cool. At the end of the session, let's talk a little bit about the news you want to announce. Would you like to start? Yeah. So the the unit of work is part
[28:12] of what is called the FF Lib Apex Common Framework, and that has the FF Lib Apex Common Framework was originally designed by the developers and development team over at Financial Force. They were gracious enough. They had built their accounting product on it, and they were gracious enough to expose it as open source. It has been a leading framework in the community for many many years now. There have always been other frameworks as well. Again, the Financial Force guys developed the ApexMocks framework, which was it was a it was absolute fabulous godsend when it comes to true unit testing and modular unit testing and mocking of objects. It's a fabulous framework that'll take you very easy to pick up and a lifetime to master. There have been some other frameworks that come about. You were talking about it earlier in this one around dependency injection. So Andy Faucet and Doug Ayers and myself created the Force DI framework. And there's other frameworks like the AT4DX framework, which is really it's a framework that sits on top of the first three, and it helps to add that final element to do large scale second generation package. Development, so you can and and you can sort of blend all these packages together in sort of a modern interlocking type way. So there's a lot of these different frameworks out there.
[29:43] What happened was right around Dreamforce 19 and around November of 2019, Financial Force agreed to transfer ownership of these of the repositories that they had to a group called a group now called the Apex Enterprise Pattern Open Source Group. And so what this is is just a collection of community developers, myself included, Andy Faucet, other people like Dave Esposito over at Patron Technology, and a few other people. And we, the group now maintains and owns the FFLib Apex Common, the ApexMocks, the Force DI frameworks, and there's a couple more frameworks. The AT4DX framework will be coming to them as well. And so it. It provide what the intention is. We're going to be community supporting this. You know, Financial Force was really great at being the steward and the owner of their repos. But there were so many community ideas, and and pull requests and enhancements to the framework. They just they were struggling to keep up with and needed some help. And so these are all just community volunteers. And so we took ownership of the various repos. We're dusting them off where they need to be dusted off a little bit. Give them some love. They will be converting to DX. They will be proper CI/CD or CI implementation soon on all these different
[31:13] frameworks, and they'll all. I think it's going to be a great value add to the community, and we're going to over the coming year. Consolidate all the different blogs and documentation and write up write ups that have been done on all these great frameworks, and we're going to put them in one specific spot. So there's a single place that everybody can go. It's GitHub.com/slash/apex-enterprise-patterns, and that's the GitHub organization for this group. And they'll be able to find all the different libraries, and pretty soon you'll be able to find all the documentation you ever need for And but again, you know, we still encourage anybody who has, you know, like you said, if there was a bug that you find in the in the framework, we'll pull, you know, fork that repo, fix the bug, and open a pull request, and we'll get it, you know, figured out. You know, a lot of times we'll bring those changes right through. A lot of times, there's sometimes we won't bring the changes through because you know it's it's again. You know, thinking about the larger implementations, thinking about the the larger focus of these repos and what they're trying to extend. So, but yeah, it's it's very exciting. So, excellent. Yeah, yeah, I think it'll be value add to everybody. Thanks a lot, John. Thanks for all the you know great work in the open source community, Salesforce world. Definitely, you know, need this open source ideas or this work you have done. Thanks, John. So. That's the all. So, talk you next time.