Skip to main content

Salesforce DX Packages - simple recipe to remove apex classes dependencies

With the recent release of Salesforce DX and the package development model it got me thinking how to avoid dependencies so I can isolate my packages. 


Business case

The major pain point I saw in the past was around "how to split the metadata so separated teams can work in parallel". For instance, a team can be one line of business or a stream in a project or a feature. 

In the old monologic development approach (AKA "the happy soup") we used to have these big merge sessions in order to integrate and some times re-write incompatible solutions written in parallel by separated teams (I won't miss those long nights with cold pizza)

Due to several comments of the merge complexity, Salesforce decided to invest in a better way to allow teams to split their work and this is where the new unlocked packages come into place.

However, in order to fully benefit from the advantages of unlocked packages we have to deal with dependencies between packages. Let's keep in mind that the goal is to be able to create and release isolated packages by Team without depending on each other's features. Without that, we would end up having a single big package and the same merge issues seen in monologic release models

The packaging dependency can be seen from several angles, here I will give a recipe that I normally use to deal and solve the dependency between Apex classes. 

Firs at all, what is a dependency?


In object-oriented programming, a dependency is a relationship between the classes in your application (see reference). 

Let's Image we have two classes: our controller that calls a service class (AKA a "helper") to execute some business logic.

In this case, LB_DemoControllerDependent class creates an instance of  LB_ServiceLogic on line 4. This reference creates a dependency because the class LB_ServiceLogic must exist in order DemoControllerDependent to be compiled.

Let's put it simply if class A needs class B to compile, we can say class A depends on class B. 

From a diagram point of view, we can see that dependency as an arrow between the classes. 


Figure 1: Dependant Classes

How to solve dependency?

I won't give a long explanation about dependency injection or Inversion of control there is plenty documentation out there that you can read if you are interested about the topic (a helpful reading topic for those nights where you have issues falling sleep ;-) ). 

Here I will focus on proving a "simple recipe to remove apex classes dependencies". 

  • The goal: remove that line (dependency) that we saw in figure 1 between our controller and the specific service logic. 
  • The reason: we want to place our controller on a separated unlocked packaged so it can be deployed without having our service class in the same package or already present in the Salesforce Org.

Create an Interface class. An interface is a contract between two classes. This way your controller doesn't need to know the exact class with the business logic, it just needs to know the "contract" that the service class will follow. 



Create a custom metadata type: The custom metadata allow us to specify (or Inject) the name of the real class we wont to use on real-time. Here I will use a simple metadata structure (just a simple text field). 

However, you can have a more sophisticated logic where you, for example, you can specify the order or execution to have a flag to activate and deactivate entries. 

metadata image.
Update your controller class: Update your service class so your class becomes "Independent". To do so your controller class will now leverage the Interface created on step 1 and the custom metadata created on step 2 in order to indirectly call the service class.

Please also note that we are using a for loop, this will allow the controller to call than more one service class if required. 


Update your service class: Similarly, your service class should implement the interface, that way your teams can work independently of the caller class.  



Create a metadata entry
metadata entry image

Putting everything together:





Packaging 

Based on the approach our new class diagram looks like this:



As we see both the class and the service depend on the interface. My recommendation is to:
  • Place the interface in the "core" package: This is the package that must be installed first and is the core foundation of your release. 
  • Place the controller in the "base" package: Similar to the core package this package normally have some base logic like controllers, triggers and base info.
  • Place each service class on each team (Line of business, project or feature) package.
Remember that package the package structure in your decision and it will be based on your own reality. I will be posting a new blog entry with my ideas about about how to details with packages. 

Further reading

Here are some interesting links and videos about this topic.

Next improvements 

I will be creating a follow-up blog post and video about how to create unlocked packages for this example ... stay tuned for that. 





Comments

Popular posts from this blog

Salesforce ListView as a Home Page component.

Display ListView as a Home Page component. In this show an example to use the a pex:enhancedList  VisualForce component in order to display a ListView in a VisualForce Page, and then embed this as a Home Page component. The final result should be something like this: Step 1: Create a ListView I suggest doing this with a ListView, as we left the control of which records list will be filtered to Administrators or End users. First step its to create a list view with the data that you want to show: Step 2: Create a VisualForce Page  Go to  Setup -> Build --> Develop --> Pages --> New. And create a new Page with this sniped of code: The page is using an  enhancedList Visualforce Component, for more details about this component here is the documentation: http://www.salesforce.com/us/developer/docs/pages/index_Left.htm#CSHID=pages_compref_composition.htm|StartTopic=Content%2Fpages_compref_composition.htm|SkinName=webhelp   The par

How to ByPass and Apex Triggers and Avoid Loops

How to ByPass and Apex Triggers and Avoid Loops Sometimes, when developing a trigger from some reasons we need to by pass the a trigger, may, as I mentioned in my previous post " System.LimitException: Too many SOQL queries: 101 ", sometimes we have loops in our triggers logic.  In Other occasions we just want to bypass because records were processed previously. Our first approach for bypassing its to execute an SOQL query to see if record need to be processed or use fields in the object. trigger TriggerTest on User (before insert. before update) { //First go to Database Set ids = Trigger.newMap.keySet(); List relatedObjs = [SELECT Id,Name FROM relatedObject__c WHERE parent__c in :ids]; //Here check which users need to be processed. List UsersToProcess = new List (); for(User usr: Trigger.new){ //Use the values on relatedObjs to validate UsersToProcess.add(usr); } //Process the records if(UsersToProcess.size() > 0){

Dynamic Section on a VisualForce Page

This will be an small example to show how to create dynamic content inside a Visual Force Page, particularly in a table. Additionally the idea that I wan to introduce here its the use of a Wrapper Class , This class will help us to control the User Interface behavior without having the need to have a new field (Persistent data) back into the database. This we we can "Wrap" the database information into another object, use it in the Interface and them just save back the important information. Something important to consider when using a wrapper class, its there is not automatic field type binding in the VisualForce page to not persistent objects, therefore we need to use fields like "<apex:inputText  /> " Instead of  <apex:inputField /> and validate the format of the data that we collect from the view. The requirements: Have a table that show basic account information. When the checkbook "Configure SLA" its selected allow user to chang