Sunday 17 February 2019

Apex Service Layer : Separation of Concerns


Separation of Concerns (SoC) (modularity,information hiding)

The most important principle of Software is Separation of Concerns(SoC).Software system must be decomposed into parts that overlap in functionality.

Separation of Concerns is a design principle for separating a program into different sections so that each section addresses a separate concern (information). A program which implements SoC is consider as modular program. Modularity is achieved by encapsulation. Encapsulating means information hiding. SoC results in simplified and easy maintenance of code which later help reusing the code and easy to upgrade, i.e. one can modify one piece of code without knowing the details of other section of code.

Good code benefits from careful design and foresight and complex code gets out of hand if you don't partition it properly. When code is heavily intermixed, it become error prone, difficult to maintain and hard to learn.

Benefits of SoC
At higher level, applications have three things: storage, logic and means to interact with them.  When you separate these things, you can start to define layers within your application, each with its own set of concerns and responsibilities to other layers and the application as a whole.


  • Evolution: over the time technical and functional requirements evolve, a layer might need to be extended, reworked, or even dropped.
  • Impact management: Modifying or dropping one or more layers should not impact other layers, unless this is the intention due to requirements.
  • Roles and Responsibility: Each layer has its own responsibility and must not drop below or over-extend that responsibility. If the lines of responsibility get blurred, the purpose and value of SOC are eroded and that's not good.
The Force.com platform has two distinct approaches to development, declarative (point-and-click) and traditional coding. You can use either method on its own or in conjunction. The two approaches fit into the standard SOC layers as outlined below.

Presentation:
  • Declarative: Layouts, Flow, Record Types, Formulas, Reports, Dashboards
  • Coding: Apex Controllers, Visualforce, Lightning Components

Business Logic:
  • Declarative: Formula, Validation, Workflow, Process Builder, Sharing Rules
  • Coding: Apex Services, Apex Custom Actions

Data Access Layer:
  • Declarative: Data Loaders
  • Coding: SOQL, SOSL, Salesforce APIs

Database Layer:
  • Declarative: Custom Objects, Fields, Relationships, Rollups
  • Coding: Apex Triggers


When some business requirement cannot be acheived via declarative way and you have to write code to achieve complex logic than we ends up using SoC using Apex, triggers etc.



Service Layer, "Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation." Martin Fowler / Randy Stafford, EAA Patterns

Service layer is a middle layer between presentation and data store. It abstract business logic and data access. A good Service layer:

1. Centralizes external access to data and functions
2. Hides (abstracts) internal implementation and changes.
3. Allows for versioning of the services.

The Service layer helps you form a clear and strict encapsulation of code implementing business tasks, calculations and processes. It’s important to ensure that the Service layer is ready for use in different contexts, such as mobile applications, UI forms, rich web UIs, and numerous APIs. It must remain pure and abstract to endure the changing times and demands ahead of it.


Design Consideration:

  • Naming conventions: Ensure that class, methods, and parameters names are expressed in general terms of the application or task rather than relating to a specific client caller.
  • Platform/Caller sympathy: Design methods signatures must support platform's best practices especially Bulkification.
  • SoC consideration: Service layer code encapsulates task or process logic typically utilizing multiple objects in your application. Think of this as an orchestrator. In contrast, code relating specifically to validation, field values or calculations, which occur during record inserts, updates, and deletes, is the concern of the related object. Such code is typically written in Apex triggers and can remain there.
  • Security: Service layer code and the code it calls should by default run with user security applied. To ensure that this is the case, utilize the with sharing modifier on your Apex Service classes.
  • Marshalling: Visualforce uses <apex:pagemessages>, and Schedule jobs will likely use emails, Chatter posts, or logs to communicate errors. So in this case, it is typically best to leverage the default error-handling semantics of Apex by throwing exceptions. Alternatively, your service can provide partial database update feedback to the caller. In this case, devise an appropriate Apex class and return a list of that type. The system Database.insert method is a good example of this type of method signature.
  • Compound services: Although clients can execute multiple service calls one after another, doing so can be inefficient and cause database transactional issues. It’s better to create compound services that internally group multiple service calls together in one service call. It is also important to ensure that the service layer is as optimized as possible in respect to SOQL and DML usage.
  • Transaction management and statelessness: Make the service stateless to give calling contexts the flexibility to employ their own state management solutions. The scope of a transaction with the database should also be contained within each service method so that the caller does not have to consider this with its own SavePoints. It’s best to encapsulate database operations and service state within the method call to the service layer.
  • Configuration: You might have common configuration or behavioral overrides in a service layer, such as providing control to allow the client to instruct the server layer not to commit changes or send emails. This scenario might be useful in cases where the client is implementing preview or what-if type functionality.
In below code method in controller represents the service operations, which access the information they needed through environment and parameters passed. The logic in the method updates the database or returns information in the method’s return type using custom Apex exceptions to indicate failure. The following example shows a service to apply a given discount to a set of Opportunities (and lines items, if present).

If you wanted to expose your service to external parties through an API, then simplest way to expose it to Apex developers is to modify the class and method modifiers from public to global. It's worth considering exposing your API for off-platform callers, such as mobile or IoT is via REST protocol.

Below code closes the Case and set reason for one or more given case records. Below CaseService class contains a static method which takes two parameters, set of Case Ids and a string parameter for close reason.

Below REST Apex class called CaseCloseReason with URI mapping /case/*/close (where * will be the Id) implements a HTTPPost method closecase which accepts a reason of type string and calls CaseService.closecases service method passing Id and reason.

Unit of Work Principles

When you're pulling data in and out of a database, it's important to keep track of what you've changed; otherwise, that data won't be written back into the database. Unit of work keeps track of everything you do during a business transaction that can affect the database. "A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done,
it figures out everything that needs to be done to alter the database as a result of your work."

The Unit of Work is a design pattern that reduces repetitive code when implementing transaction management and the coding overheads of adhering to DML bulkification through extensive use of maps and lists. It’s not a requirement for implementing a service layer, but it can help.

On Force.com platform this translates to the pattern handling the following use cases:
  • Recording record updates, inserts, and deletes to implement a specific business requirement
  • Recording record relationships to make inserting child or related records easier with less coding
  • When asked to write (or commit) to the database, bulkifies all records captured
  • Wrapping DML performed in SavePoint, freeing the developer from implementing this each time for every service method that is written
In OpportunitiesService we use Savepoint to encapsulate and wrap the database operations within a Service method. As per the design considerations, the SavePoint is used to avoid the caller catching exceptions (perhaps resulting from the second DML statement). That would then result in the Apex runtime committing updates to the opportunity lines (first DML statement), causing a partial update to the database.

Please refer Unit of Work  Principles of Apex on Trailhead for details and example.


References: Apex Enterprise Patterns: Service Layer, www.martinfowler.com


No comments:

Post a Comment