Chapter 6. Application Domain Layer

The objects used by your application represent its domain. Unlike other database platforms where record data is, by default, hidden from end users, the Force.com platform displays record data through the standard Salesforce UI, reports, dashboards, and Salesforce1 mobile application. Surfacing the labels and relationships, you give your objects and fields directly to the end user. From the moment you create your first object, you start to define your application's domain, just as Salesforce Standard Objects represent the CRM application domain.

Martin Fowler's Patterns of Enterprise Application Architecture also recognizes this concept as a means of code encapsulation to combine the data expressed by each object with behaviors written in code that affect or interact with that data. This could be Apex Trigger code, providing defaulting and validation, or code awarding championship points to contestant records or checking rules compliance.

This chapter will extend the functionality of the FormulaForce application using the Domain layer pattern, as well as highlighting specific concerns, guidelines, and best practices, and how it integrates with both Apex Triggers and the application's Service layer code.

The following aspects will be covered in this chapter:

  • Introducing the Domain layer pattern
  • Implementing design guidelines
  • The Domain class template
  • Implementing the Domain Trigger logic
  • Implementing the custom Domain logic
  • Object-orientated programming
  • Testing the Domain layer
  • Calling the Domain layer

Introducing the Domain layer pattern

The following is Martin Fowler's definition of the Domain layer (http://martinfowler.com/eaaCatalog/domainModel.html):

"An object model of the domain that incorporates both behavior and data".

Like the Service layer, this pattern adds a further layer of Separation of Concerns and factoring of the application code, which helps manage and scale a code base as it grows.

"At its worst business logic can be very complex. Rules and logic describe many different cases and slants of behavior, and it's this complexity that objects were designed to work with. A Domain Model creates a web of interconnected objects, where each object represents some meaningful individual, whether as large as a corporation or as small as a single line on an order form."

Martin's reference to objects in the preceding quote is mainly aimed at objects created from instantiating classes that are coded in an object-orientated programming language, such as Java or .NET. In these platforms, such classes act as a logical representation of the underlying database-table relationships. This approach is typically referred to as Object Relational Mapping (ORM).

In contrast, a Force.com developer reading the term object will tend to first think about Standard or Custom Objects rather than something resulting from a class instantiation. This is because Salesforce has done a great job in binding the data with behavior through their declarative definition of an object, which as we know is much more than just fields. It has formulas, filters, referential integrity, and many other features that we have discussed in earlier chapters, available without writing any code.

Taking into consideration that these declarative features are essentially a means to enable certain behaviors, a Force.com Custom or Standard Object already meets some of the encapsulation concerns of the Domain layer pattern.

Encapsulating an object's behavior in code

Apex Triggers present a way to write code to implement additional behavior for Custom Objects (or Standard Objects for that matter). They provide a place to implement more complex behavior associated with database events, such as create, update, and delete.

However, as an Apex Trigger cannot have public methods, it does not provide a means to write code that logically belongs with the object but is not necessarily linked with a database event. An example of this would be logic to calculate Contestants championship points or checking compliance against the many Formula1 rules and regulations, which we will look at later in this chapter. Furthermore, they do not present the opportunity to leverage object-orientated programming (OOP) approaches, also discussed later in this chapter.

As a result, developers often end up putting this logic elsewhere, sometimes in a controller or helper class of some kind. Thus, the code implementing the behavior for a given object becomes fragmented and there is a breakdown of Separation of Concerns.

Lifting your Apex Trigger code out of the body of the trigger and into an Apex Class, perhaps named by some convention based on the object name, is a good start to mitigating this fragmentation, for example RaceTriggerManager or RaceTriggerHandler. Using such approaches, it then becomes possible to create other methods and break up the code further. These approaches are only the start in seeking a more complete interpretation of the domain model concept described in this chapter.

Using the Manager or Handler approach tends to attract logic relating to the Apex Trigger event model and nothing else, leaving other object-related logic to find less obvious locations in the code base.

Interpreting the Domain layer in Force.com

In this chapter, we look at the Force.com interpretation of the Domain layer pattern, one which ensures behavior invoked both through Apex Trigger events and through direct Apex method calls (from the Service layer and other Domain classes) are considered.

A single Domain class can be created to encapsulate all of the behavior and will begin to leverage OOP principles, such as interfaces, to further enrich the code for reuse and Separation of Concerns, which we will explore later in this chapter.

The following diagram illustrates two consumers of the Domain layer classes—the code from the Service layer and also direct interactions with objects resulting in Apex Trigger events, which will also be routed to the same Domain layer class:

Interpreting the Domain layer in Force.com

Domain classes in Apex compared to other platforms

As we have seen in earlier chapters, a Standard or Custom Object is exposed within the Apex runtime as a concrete type that can be instantiated to populate record fields for insertions in the database, or to determine which types are used to return records queried from it.

When considering the Domain pattern, the first inclination is perhaps to extend the applicable SObject such as Account or Race__c through Apex inheritance with the extends keyword. Unfortunately, the Apex compiler does not support this approach. Even if it were to support this, given best practices of bulkification, writing code that deals with a single record instance at a time will quickly lead to governor issues.

Instead, the Domain class implementation covered here uses the composition approach to combine record data and behavior. This is sometimes known as the wrapper class approach; it is so named because it wraps the data that it relates to as a class member variable.

The Apex implementation of the wrapper class is no different, except that we choose to wrap a list of records to enforce bulkified implementations of the logic within. The following pseudocode illustrates the instantiation of an Apex Domain class:

Race__craceRecords = [select Id, Name from Races__c where Id in :raceIds];

Races races = new Races(raceRecords);

Another implementation difference compared to other platforms, such as Java and .NET, is the creation of accessor methods to obtain related parent and child records. Though it is possible to write such methods, these are not recommended, for example, Contestants.getRaces or Races.getContestants.

This implementation avoids coding these types of accessors, as the SObject objects in Apex already provide a means to traverse relationships (if queried) as needed. The bulk nature of Apex Domain classes also makes these types of methods less useful and more appropriate for the caller to use the Selector classes to query the required records as and when needed, rather than as a result of invoking an accessor method.

To summarize, the Apex Domain classes described in this chapter focus on wrapping lists of records and methods that encapsulate the object's behavior and avoid providing accessor methods for query-related records.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.38.253