Skip to main content
01 Separation of ConcernsChapter 04 of 2020 Force DI
Chapter 04 · Annotated

The fflib_Application Class

The abstract factory class that the other layers rely on.

22 min readVideo 32:15Annotated template

What is the fflib_Application class?

The fflib_Application class is around to allow you an abstract/flexible way of creating new instances of your unit of work, service layer, domain layer and selector layer in the Apex Common Library through the use of the factory pattern.

Most importantly though, if you understand how interfaces, inheritance and polymorphism work implementing this class allows you to write very flexible Salesforce implementations, which we'll discuss more in the sections below.


The creation of Application classes is not mandatory!

In earlier versions of this guide it was stated that the use of an Application class was mandatory to take advantage of these libraries. It is not. If you want to purely leverage these libraries for unit tests/mocking, for instance, the creation of an application class is entirely optional. If you would prefer to not create and utilize Application classes that is totally fine, however, it is a very powerful tool and there are lots of advantages to leveraging it, so this guide will commonly reference them and examples will utilize them. For even more in depth information on when you might want to use an application class and when you might not, please take a look at this blog post elaborating on it

Why is this class used?

Ok, understanding the power behind the use of an application class requires us to take a step back and formulate a real-world Salesforce use case for implementing it... hopefully the following one will be easy for everyone to understand.

Say for instance you have a decent-sized Salesforce instance and your business has a use case to create tasks across multiple objects and the logic for creating those tasks is unique to every single object. Maybe on the Account object we create three new tasks every single time we create an account and on the Contact object we create two tasks every single time a record is created or updated in a particular way and we ideally want to call this logic on the fly from anywhere in our system.

No matter what, we should probably place the task creation logic in our domain layer because it's behavior relevant to an individual object, but pretend for a second that we have 20 different objects we need this kind of functionality on. Maybe we need the executed logic in an abstract "task creator" button that can be placed on any lightning app builder page and maybe some overnight batch jobs need to execute the logic too.

Well... what do we do? Let's just take the abstract "Task Creator" button we might want to place on any object in our system. We could call each individual domain layer class's task creation logic in the codebased on the object we were on (code example below), but that logic tree could get massive and it's not super ideal.

Task Service example with object logic tree

public with sharing class Task_Service_Impl
{
//This method calls the task creators for each object type
public void createTasks(Set<Id> recordIds, Schema.SObjectType objectType)
{
if(objectType == Account.getSObjectType()){
new Accounts().createTasks(recordIds);
}
else if(objectType == Case.getSObjectType()){
new Cases().createTasks(recordIds);
}
else if(objectType == Opportunity.getSObjectType()){
new Opportunities().createTasks(recordIds);
}
else if(objectType == Taco__c.getSObjectType()){
new Tacos().createTasks(recordIds);
}
else if(objectType == Chocolate__c.getSObjectType()){
new Chocolates().createTasks(recordIds);
}
//etc etc for each object could go on for decades
}
}

Maybe... just maybe there's an easier way. This is where the factory pattern and the fflib_Application class come in handy. Through the use of the factory pattern we can create an abstract Task Service that can (based on a set of records we pass to it) select the right business logic to execute in each domain layer dynamically.

Task Service example with the factory pattern (example with a ton of comments explaining this here)

//Creation of the Application factory class
public with sharing class Application
{
public static final fflib_Application.ServiceFactory service =
new fflib_Application.ServiceFactory(
new Map<Type, Type>{
Task_Service_Interface.class => Task_Service_Impl.class}
);

public static final fflib_Application.DomainFactory domain =
new fflib_Application.DomainFactory(
Application.selector,
new Map<SObjectType, Type>{Case.SObjectType => Cases.Constructor.class,
Opportunity.SObjectType => Opportunities.Constructor.class,
Account.SObjectType => Accounts.Constructor.class,
Taco__c.SObjectType => Tacos.Constructor.class,
Chocolate__c.SObjectType => Chocolates.Constructor.class}
);
}
//The task service that anywhere can call and it will operate as expected with super minimal logic
public with sharing class Task_Service_Impl implements Task_Service_Interface
{
//This method calls the task creators for each object type
public void createTasks(Set<Id> recordIds, Schema.SObjectType objectType)
{
fflib_ISObjectDomain objectDomain = Application.domain.newInstance(recordIds);

if(objectDomain instanceof Task_Creator_Interface){
Task_Creator_Interface taskCreator = (Task_Creator_Interface)objectDomain;
taskCreator.createTasks(recordIds);
}
}
}

You might be lookin at the two code examples right now like wuttttttttt how thooooo?? So let's figure that out together. Thanks to the newInstance() methods on the fflib_Application class and the Task_Creator_Interface we've implemented on the domain classes, you can dynamically generate the correct domain when the code runs and call the create tasks method. Pretty wyld right? Also if you're thinkin, "Yea that's kinda nifty, but you had to create this Application class and that's a bunch of extra code." you need to step back even farther. This Application factory can be leveraged ANYWHERE IN YOUR ENTIRE CODEBASE! Not just locally in your service class. If you need to implement something similar to automatically generate opportunities or Accounts or something from tons of different objects you can leverage this exact same Application class there. In the long run, if implemented appropriately this will likely result in less code that is much easier to maintain.

If you want a ton more in depth explanation on this, please watch the tutorial video. In it, we build an example together to help explain this concept. It's certainly not easy to grasp at first glance.


The whole Application class, line by line

To the right is an example of an Application class you might build in an org.

01The shelllines 1-2

It's just a class you write yourself

The first surprise is that fflib_Application isn't something you extend or instantiate. You write your own class - conventionally called NameOfYourApplication_Application - and hang four static factories off it. No registration, no metadata, no setup. The class is the configuration.

02Unit of Worklines 3-13

The list is dependency order, not preference

The constructor for the unit of work takes a List<SObjectType> and the order of that list is important! When commitWork() runs on your unit of work (which we will go over soon) it does object DML in the order they appear in this list, which is how a Contact can be registered before its Account exists in the code and still get the right AccountId when the unit of work gets committed (again we will cover this in much more detail soon).

Get this wrong and

You'll see INVALID_CROSS_REFERENCE_KEY at commit time, on a line that looks completely unrelated. Most "the Unit of Work is broken" reports turn out to be a child listed above its parent here.

03Servicelines 15-22

A home to register all the services relevant to your application

This constructor takes a map of the services that are relevant to your application. Unlike the unit of work it does not matter which order you place these in. Additionally, services can be mapped to themselves like this Task_Service.class => Task_Service.class or they can be mapped to interfaces like this Task_Service_Interface => Task_Service.class. There is no right or wrong, it just depends on what you actually need for your code to run appropriately and to be able to implement the separation of concerns design principle.

04Selectorlines 24-32

A map of SObjectType to its selector class (the class that holds its SOQL)

Selector classes are mapped to the SObjectType of the Salesforce object they are querying. Its job is to easily provide you access to the right selector for an object when you need it. Another important thing to note here is that the domain factory needs this selector to be present to work. So if you add domains to your application class make sure you have a selector created for the object that domain represents and the selector factory declared in your application class as well.

05Domainlines 34-44

A map of SObjectType to its Domain constructor, with the help of the selector factory

Look at the first argument the DomainFactory takes: Application.selector. The domain factory is the only one that requires the existence of another factory, and we'll discuss why below.

When you call Application.domain.newInstance(recordIds) (which we'll discuss more soon enough) you're handing it a set of ids - not records. Before it can decide which domain class to construct, it has to query those ids to find out what SObject they are. So it needs a selector.

The map values are Constructor.class, not the domain class itself, because Apex can't reflect over constructors. That inner class is the workaround, and chapter 11 shows how to write one and discusses how it all works in more detail.

Application.clsapexlines 1–2
public with sharing class Application{    // The Unit of Work factory. The list below is the DEPENDENCY ORDER:    //   Accounts insert before Contacts, Contacts before Cases.    public static final fflib_Application.UnitOfWorkFactory UOW =        new fflib_Application.UnitOfWorkFactory(            new List<SObjectType>{                Account.SObjectType,                Contact.SObjectType,                Case.SObjectType,                Task.SObjectType            }        );
    // The Service factory. Maps an interface to its implementation,    //   which is the seam Apex Mocks needs to substitute a stub.    public static final fflib_Application.ServiceFactory service =        new fflib_Application.ServiceFactory(            new Map<Type, Type>{                Task_Service_Interface.class => Task_Service_Impl.class            }        );
    // The Selector factory. Maps an SObjectType to the selector that    //   queries it, so other factories can requery records by id.    public static final fflib_Application.SelectorFactory selector =        new fflib_Application.SelectorFactory(            new Map<SObjectType, Type>{                Account.SObjectType => AccountsSelector.class,                Case.SObjectType    => CasesSelector.class            }        );
    // The Domain factory. It takes the SELECTOR factory, because    //   newInstance(Set<Id>) must query the records before it can    //   decide which domain class to construct.    public static final fflib_Application.DomainFactory domain =        new fflib_Application.DomainFactory(            Application.selector,            new Map<SObjectType, Type>{                Account.SObjectType => Accounts.Constructor.class,                Case.SObjectType    => Cases.Constructor.class            }        );}

fflib_Application inner classes and methods cheat sheet

Inside the fflib_Application class there are four classes that represent factories for your unit of work, service layer, domain layer and selector layer.

Let's go over them and how they work:

The Unit of Work Factory

Inside the fflib_Application class there is the UnitOfWorkFactory class. Let's first figure out how to instantiate this class:

//The constructor for this class requires you to pass a list of SObject types in the dependency order. So in this instance Accounts would always be inserted before your Contacts and Contacts before Cases, etc.
public static final fflib_Application.UnitOfWorkFactory UOW =
new fflib_Application.UnitOfWorkFactory(
new List<SObjectType>{
Account.SObjectType,
Contact.SObjectType,
Case.SObjectType,
Task.SObjectType}
);

After creating this unit of work variable above ^ in your Application class example here there are four important new instance methods you can leverage to generate a new unit of work:

  1. newInstance() - This creates a new instance of the unit of work using the SObjectType list passed in the constructor.

newInstance() Example Method Call

public with sharing class Application
{
public static final fflib_Application.UnitOfWorkFactory UOW =
new fflib_Application.UnitOfWorkFactory(
new List<SObjectType>{
Account.SObjectType,
Contact.SObjectType,
Case.SObjectType,
Task.SObjectType}
);
}

public with sharing class SomeClass{
public void someClassMethod(){
fflib_ISObjectUnitOfWork unitOfWork = Application.UOW.newInstance();
}
}

  1. newInstance(fflib_SObjectUnitOfWork.IDML dml) - This creates a new instance of the unit of work using the SObjectType list passed in the constructor and a new IDML implementation to do custom DML work not inherently supported by the fflib_SObjectUnitOfWork class. More info on the IDML interface here

newInstance(fflib_SObjectUnitOfWork.IDML dml) Example Method Call

public with sharing class Application
{
public static final fflib_Application.UnitOfWorkFactory UOW =
new fflib_Application.UnitOfWorkFactory(
new List<SObjectType>{
Account.SObjectType,
Contact.SObjectType,
Case.SObjectType,
Task.SObjectType}
);
}

//Custom IDML implementation
public with sharing class IDML_Example implements fflib_SObjectUnitOfWork.IDML
{
void dmlInsert(List<SObject> objList){
//custom insert logic here
}
void dmlUpdate(List<SObject> objList){
//custom update logic here
}
void dmlDelete(List<SObject> objList){
//custom delete logic here
}
void eventPublish(List<SObject> objList){
//custom event publishing logic here
}
void emptyRecycleBin(List<SObject> objList){
//custom empty recycle bin logic here
}
}

public with sharing class SomeClass{
public void someClassMethod(){
fflib_ISObjectUnitOfWork unitOfWork = Application.UOW.newInstance(new IDML_Example());
}
}

  1. newInstance(List<SObjectType> objectTypes) - This creates a new instance of the unit of work and overwrites the SObject type list passed in the constructor so you can have a custom order if you need it.

newInstance(List <SObjectType> objectTypes) Example Method Call

public with sharing class Application
{
public static final fflib_Application.UnitOfWorkFactory UOW =
new fflib_Application.UnitOfWorkFactory(
new List<SObjectType>{
Account.SObjectType,
Contact.SObjectType,
Case.SObjectType,
Task.SObjectType}
);
}

public with sharing class SomeClass{
public void someClassMethod(){
fflib_ISObjectUnitOfWork unitOfWork = Application.UOW.newInstance(new List<SObjectType>{
Case.SObjectType,
Account.SObjectType,
Task.SObjectType,
Contact.SObjectType,
});
}
}

  1. newInstance(List <SObjectType> objectTypes, fflib_SObjectUnitOfWork.IDML dml) - This creates a new instance of the unit of work and overwrites the SObject type list passed in the constructor so you can have a custom order if you need it and a new IDML implementation to do custom DML work not inherently supported by the fflib_SObjectUnitOfWork class. More info on the IDML interface here

newInstance(List<SObjectType> objectTypes, fflib_SObjectUnitOfWork.IDML dml) Example Method Call

public with sharing class Application
{
public static final fflib_Application.UnitOfWorkFactory UOW =
new fflib_Application.UnitOfWorkFactory(
new List<SObjectType>{
Account.SObjectType,
Contact.SObjectType,
Case.SObjectType,
Task.SObjectType}
);
}

//Custom IDML implementation
public with sharing class IDML_Example implements fflib_SObjectUnitOfWork.IDML
{
void dmlInsert(List<SObject> objList){
//custom insert logic here
}
void dmlUpdate(List<SObject> objList){
//custom update logic here
}
void dmlDelete(List<SObject> objList){
//custom delete logic here
}
void eventPublish(List<SObject> objList){
//custom event publishing logic here
}
void emptyRecycleBin(List<SObject> objList){
//custom empty recycle bin logic here
}
}

public with sharing class SomeClass{
public void someClassMethod(){
fflib_ISObjectUnitOfWork unitOfWork = Application.UOW.newInstance(new List<SObjectType>{
Case.SObjectType,
Account.SObjectType,
Task.SObjectType,
Contact.SObjectType,
}, new IDML_Example());
}
}

The Service Factory

Inside the fflib_Application class there is the ServiceFactory class. Let's first figure out how to instantiate this class:

//This allows us to create a factory for instantiating service classes. You send it the interface for your service class
//and it will return the correct service layer class
//Exmaple initialization: Object objectService = Application.service.newInstance(Task_Service_Interface.class);
public static final fflib_Application.ServiceFactory service =
new fflib_Application.ServiceFactory(new Map<Type, Type>{
SObject_SharingService_Interface.class => SObject_SharingService_Impl.class
});


After creating this service variable above ^ in your Application class example here there is one important new instance method you can leverage to generate a new service class instance:

  1. newInstance(Type serviceClassType) - This method sends back an instance of your service implementation class based on the interface you send in to it.

newInstance(Type serviceClassType) Example method call:

//This is using the service variable above that we would've created in our Application class
Application.service.newInstance(Task_Service_Interface.class);

The Selector Factory

Inside the fflib_Application class there is the SelectorFactory class. Let's first figure out how to instantiate this class:

//This allows us to create a factory for instantiating selector classes. You send it an object type and it sends
//you the corresponding selectory layer class.
//Example initialization: fflib_ISObjectSelector objectSelector = Application.selector.newInstance(objectType);
public static final fflib_Application.SelectorFactory selector =
new fflib_Application.SelectorFactory(
new Map<SObjectType, Type>{
Case.SObjectType => Case_Selector.class,
Contact.SObjectType => Contact_Selector.class,
Task.SObjectType => Task_Selector.class}
);

After creating this selector variable above ^ in your Application class example here there are three important methods you can leverage to generate a new selector class instance:

  1. newInstance(SObjectType sObjectType) - This method will generate a new instance of the selector based on the object type passed to it. So for instance if you have an Opportunity_Selector class and pass Opportunity.SObjectType to the newInstance method you will get back your Opportunity_Selector class (provided you have configured it that way in the Application class map passed to the class).

newInstance(SObjectType sObjectType) Example method call:

//This is using the selector variable above that we would've created in our Application class
Application.selector.newInstance(Case.SObjectType);

  1. selectById(Set<Id> recordIds) - This method, based on the ids you pass will automatically call your registered selector layer class for the object type of the set of ids. It will then call the selectSObjectById method that all Selector classes must implement and return a list of sObjects to you.

selectById(Set<Id> recordIds) Example method call:

//This is using the selector variable above that we would've created in our Application class
Application.selector.selectById(accountIdSet);

  1. selectByRelationship(List<SObject> relatedRecords, SObjectField relationshipField) - This method, based on the relatedRecords and the relationship field passed to it will generate a selector layer class for the object type in the relationship field. So say you were querying the Contact object and you wanted an Account Selector class, you could call this method, pass the list of contacts you queried for and the AccountId field to have an Account Selector returned to you (provided that selector was configured in the Application shown above in this chapter).

selectByRelationship(List<SObject> relatedRecords, SObjectField relationshipField) Example method call:

//This is using the selector variable above that we would've created in our Application class
Application.selector.selectByRelationship(contactList, Contact.AccountId);

The Domain Factory

Inside the fflib_Application class there is the DomainFactory class. Let's first figure out how to instantiate this class:

//This allows you to create a factory for instantiating domain classes. You can send it a set of record ids and
//you'll get the corresponding domain layer.
//Example initialization: fflib_ISObjectDomain objectDomain = Application.domain.newInstance(recordIds);
public static final fflib_Application.DomainFactory domain =
new fflib_Application.DomainFactory(
Application.selector,
new Map<SObjectType, Type>{Case.SObjectType => Cases.Constructor.class,
Contact.SObjectType => Contacts.Constructor.class}
);

After creating this domain variable above ^ in your Application class example here there are three important methods you can leverage to generate a new domain class instance:

  1. newInstance(Set<Id> recordIds) - This method creates a new instance of your domain class based off the object type in the set of ids you pass it.

newInstance(Set<Id> recordIds) Example method call:

Application.domain.newInstance(accountIdSet);


  1. newInstance(List<SObject> records) - This method creates a new instance of your domain class based off the object type in the list of records you pass it.

newInstance(List<SObject> records) Example method call:

Application.domain.newInstance(accountList);


  1. newInstance(List<SObject> records, SObjectType domainSObjectType) - This method will create a newInstance of the domain class based on the object type and record list passed to it.

newInstance(List<SObject> records, SObjectType domainSObjectType) Example method call:

Application.domain.newInstance(accountList, Account.SObjectType);


The Convenience newInstance() Helpers

One thing you'll notice quickly when using the factories: every call site has to cast. Application.domain.newInstance(caseIds) hands you back an fflib_ISObjectDomain, and Application.selector.newInstance(Case.SObjectType) hands you an fflib_ISObjectSelector, so any time you want to call one of your methods you're writing (Cases) or (Case_Selector) in front of it. Multiply that by every call site in the org and it gets old.

The near-universal convention in real fflib codebases is to add a static newInstance() helper to each domain and selector class that does the factory call and the cast in one place:

//In your Cases domain class
public static Cases newInstance(List<Case> records){
return (Cases) Application.domain.newInstance(records);
}

public static Cases newInstance(Set<Id> recordIds){
return (Cases) Application.domain.newInstance(recordIds);
}
//In your Case_Selector class
public static Case_Selector newInstance(){
return (Case_Selector) Application.selector.newInstance(Case.SObjectType);
}

Which turns every call site from this:

Cases cases = (Cases) Application.domain.newInstance(caseIds);
List<Case> cases = ((Case_Selector) Application.selector.newInstance(Case.SObjectType)).selectOpenCases();

Into this:

Cases cases = Cases.newInstance(caseIds);
List<Case> cases = Case_Selector.newInstance().selectOpenCases();

Critically, these helpers still route through the Application factories - so setMock (below) still works, and every benefit of factory-created instances is preserved. It's purely a readability win, and it's one your whole team will thank you for.


The setMock Methods

In every factory class inside the fflib_Application class there is a setMock method. These methods are used to pass in mock/fake versions of your classes for unit testing purposes. Make sure to leverage this method if you are planning to do unit testing.

A point of precision worth making here: you'll sometimes hear that the factory approach "eliminates the need for dependency injection". It's more accurate to say the Application class is your dependency injection mechanism - it's factory injection rather than the constructor injection you may know from other languages. Your classes ask the factory for their dependencies instead of receiving them through constructor parameters, and setMock is the seam through which tests swap in fakes. The trade-off versus constructor injection: the factories are well-known and shared across the whole codebase (no constructor-parameter plumbing on every class), and the factory can do polymorphic instantiation tricks (like the domain factory routing by SObjectType) that constructors can't. There are examples of how to leverage this method in the Implementing Mock Unit Tests with the Apex Mocks Library chapter of this guide. And if the "the Application class is really a DI container" framing intrigues you, chapter 18 takes that idea to its logical conclusion with the force-di library.