Authored by: Doug Surfleet, Nathan Bruhn, Cory Rehs, Keely Weisbeck, and Jason Halpern
FFLib as a framework for Enterprise Design Patterns
When we work with clients, one of the topics which comes up most frequently surrounds the supportability and scalability of their Salesforce implementation. It is common that they started out with the best of intentions, focused on clicks (not code!), and when they did have to write code, they did their best to document it and provide good testing coverage.
However, inevitably, things change over time, new features are needed, requirements change, and even the cleanest code bases can become complex, slow, and difficult to maintain without a good framework in place.
As your code base needs to continually solve the same problem over and over again, and you try to enforce what your developers should (and shouldn’t) do in your code, having a framework to assist with providing structure will avoid many common development issues on Salesforce. This is where FFLib comes in—an open source, widely adopted framework initially provided by FinancialForce.
At Atrium, we run much of our own business on the Salesforce platform, and eventually saw the need to implement a framework for our own Salesforce org. After researching numerous potential frameworks, as well as investigating designing our own, it was clear that the FFLib framework was already one of the most robust and widely-adopted frameworks in the ecosystem, and so we chose to migrate our own code base over to it.
Along the way, we developed a methodology for best utilizing FFLib as well as, critically, how to seamlessly migrate existing functionality over to the FFLib framework without interrupting end user functionality. We have been able to apply this methodology and series of best practice steps alongside our clients as well, allowing them to gain the benefits of moving to the FFLib platform without disruption to their business.
What is a FFLib service layer and what are the benefits?
The service layer within the FFLib framework is the layer of your application where your business logic will be placed. You can think of it as your conductor for the orchestra, making decisions about the sequence of operations, and calling the other layers as needed in order to meet business functionality.
Some of the benefits provided by utilizing the service layer are:
- Provides better organization for application business logic
- Makes it far easier to swap out a given service implementation
- Provides a repeatable template for implementing new services
- When properly written, service layer code is caller-agnostic, allowing for greater re-use and standardization within your code base
What is a domain layer and what are the benefits?
The domain layer is the part of your application where you are working on and modifying sObjects such as Opportunity or Contact (a “domain”). The purpose of the domain layer is to help centralize working with sObjects to reduce duplication and strongly encourage re-use of functionality across your application. The domain layer is also where triggers will re-route to when records are created, edited, or deleted, providing a simple way to manage trigger execution and further encourages re-use of domain logic when not inside a trigger context.
Some of the benefits provided by utilizing a domain layer are:
- Drives developers to follow best practices with regards to having a single trigger handler per sObject
- Easy interaction with the service layer
- Creates a self-documenting, easy to follow flow of logic through the trigger lifecycle
- Provides a central code repository for working on or modifying sObjects
- As a result, encourages code reuse of domain logic to other areas of the application
The domain layer provides a scalable, reusable framework for modifying sObjects (for example, requesting to mark all Opportunities as Closed/Won or updating activities). As a reminder, your business logic itself does not reside here—that is the service layer—but the code to actually perform the required data changes will be contained within the domain layer.
What is a selector layer and the benefits?
The concept of a selector layer is another key component of the FFLib framework. The purpose of the selector layer is to execute all of your database queries across your application from selector classes specific to a given sObject (such as Account or Opportunity). By centralizing the query logic for each sObject in a single class per object, developers are able to work with that sObject without having to write custom queries or ensure that all necessary fields are being returned, or even needing to understand the data model fully, as the authors and maintainers of the selector classes will ensure everything is being done in an optimal, performant manner.
Some of the benefits of using a selector layer are:
- Localize query logic for each domain (such as Contact or Account)
- Standardize field sets for predictable query results
- Built-in enforcement of security best-practices like CRUD and Field Level Security (FLS) validation
- Can bypass CRUD/FLS enforcement if the use case requires
- Easily add relationships to queries
Apex Mocks and unit testing
One of the most important aspects of any custom code implemented within your Salesforce org is proper unit testing. Achieving the 75% minimum code coverage required by Salesforce is fairly easy to do in simple implementations, but can rapidly become a burden to maintain and improve upon in medium-to-large scale programs.
The major challenge often is having to set up a tremendous amount of test data in order to test even a simple scenario due to the often highly interconnected dependencies within applications. As a result, unit tests are often complex and slow, and may not properly produce the intended results or test the right functionality. Some unit tests ultimately focus on providing the required code coverage, but do not provide as much testing value as they could.
The FFLib framework provides the concept of Apex Mocks, which is an implementation of the Mockito framework written in Apex. By adopting the unit testing framework, you prevent the need to set up test data and queries for each test method. This allows you to simulate or bypass the response of any query or selector layer method, instead returning a locally initiated response. This can significantly reduce the execution time of Unit Tests and avoids developers needing to untangle complex logic which may be embedded within larger methods.
By following these factory patterns within your unit tests, you gain the following benefits:
- Tests can mock the unit of work implementation to bypass execution of DML, which helps keep tests lean by not performing DML if the unit being tested doesn’t require it
- ApexMocks keeps the scope of the test local to the code in your ‘unit’, simplifying logic and improving performance
- With stubbing, you bypass the execution of dependent logic, which boosts unit test performance by only executing logic needed to verify the specific behavior that you’re testing
- Use mocking allows a developer to extend testing capabilities past the normal System.assert().
- Mocking can be used to verify whether certain methods were called (or not called) with certain arguments, not just ‘does expected value match actual value’
- Use mocking to ensure that bugs in dependent code don’t cause all of the related tests to also fail.
More reasons to follow Enterprise Design Patterns
When following Enterprise Design Patterns such as FFLib, it is important to organize code into units of work. This helps to enforce two key components of Enterprise Design Patterns: DRY (Don’t Repeat Yourself!) and Separation of Concerns (each method should only focus on one purpose and each class should have cohesion amongst the methods).
Following Enterprise Design Patterns greatly increases the readability and maintainability of your code. Even the most complex and extensive code bases can be organized into a framework, providing benefits such as:
- Significant reduction in ramp-up time for new developers
- Enforcing a single coding structure and naming conventions across the code base, speeding up debugging and analysis
- Increasing reusability of existing code, as all comparable code can be found in the same class and therefore more easily be altered to suit future needs
When code follows Enterprise Design Patterns and is organized into Units of Work, many benefits can be realized as your code base grows in size and complexity. A few of the most commonly cited benefits that we have seen in working with our clients to migrate to FFLib include:
- Aggregation/bulkification of DML— keeps all DML together to be executed at once, helping to avoid running into governor limits on the platform and seeing your code fail
- Wrap all DML logic in SavePoint logic for easy re-use, enabling developers to quickly write database interactions without implementing SavePoints every time
- Easily record relationships to help simplify creating parent and child records
- Transaction control provides more control over exactly when in a process DML actually occurs
Subscribe to our blog for more technical information and industry news.