15

We've got this recommendation from Salesforce after an audit

Class Complexity:

• Refactor complex classes and methods into more manageable classes. Consider the use of Process Builder to move piece of code that can be built with Process Builder.

• Best Practice:

  • Classes < 400 lines

  • Methods < 100 lines

I wonder if does this have anything to do with performance or something else other than the readability of the code ?

  • 9
    I can tell you that PB will REDUCE performance when compared to the same thing being done in code. Take their response basically (if you remove them pushing their technology) to be boiled down to Separation of Concerns. – Eric Mar 24 '17 at 16:09
  • @Eric I know they kinda marketing the new Magical Process Builder in Audits – benahm Mar 24 '17 at 16:11
  • @benahm, They might be marketing, but its not that bad. It cuts down a lot of code, is configurable and quite powerful. – Raul Mar 24 '17 at 16:37
  • 8
    @benahm PB is all fine and dandy until you realize that it can't trigger CPU or heap exceptions, which will cause you to tear your hair out in frustration trying to figure out why your trigger keeps throwing CPU limits even though it only uses 2 seconds of the total transaction time. – sfdcfox Mar 24 '17 at 16:46
  • 1
    Our support calls increased dramatically and were > 50% of our support queue when PB was released and is still a high percentage of the SF support we see. Main cause is Limits and choking on criteria that a WFR or code would easily handle. Not to mention the other "quirks". If nothing else PB was a great way for SF to push their support onto ISV vendors as we get the calls when it fails as our code it what reports the error. For critical data, PB is just not there yet. It will be, but not yet – Eric Mar 24 '17 at 16:58
20

There are a couple of non-readability considerations. The primary reasons are for legibility, though. Once you're nearing 100 lines of code, that means that you have to keep track of 4 pages worth of code in your head. This isn't particularly practical, as our brains simply don't work that way. I usually limit my methods to 1-2 pages (25-50 lines of code).

One rare limitation you have probably never seen is that methods are limited to 65,536 bytes of compiled bytecode. In practice, any method that is nearing this limit will probably be impossible to debug accurately, and is probably at risk of throwing CPU or heap governor limits. That said, there is still a hard limit on the size of each method. A related limitation is that the stack is limited to 1000 method entries. This is pretty hard to reach in normal cases, but be aware of using recursion-based methods. For example, if you wrote the following method:

public Integer sumDivergent(Integer total) {
    return total > 0? sumDivergent(total-1) + total: total;
}

subDivergent(5) would be 15, but sumDivergent(1000) would be an exception. In this case, you'd have to write it as a loop:

public Integer subDivergent(Integer total) {
    Integer result = 0;
    while(total-->0) {
        result += total;
    }
    return result;
}

Second, all of your code is being frequently compiled as it is invalidated from the two cache systems that are in place. This invalidation occurs, for example, when a related class is changed, or certain types of metadata are modified. Once invalidated, the system waits until the next time the class needs to run before compiling the code again, which means, for example, a Visualforce page will take unusually long load, or a record might take longer saving. Having your code be as concise as possible will reduce these periodic startup issues.

17

Classes with large amounts of code or business logic are what architects and developers refer to as God Classes. This is an anti-pattern. It also makes your code use more memory when it loads. The complexity makes it difficult to maintain, test, and frequently creates unnecessary dependencies.

By breaking the logic in God classes out into smaller classes:

  • The God Class uses less memory (heap) when it loads

  • All code is easier to maintain

  • Testing is simplified

Your code should preferably be factored into smaller functional "chunks" related to a specific object or as code that performs a specific service/purpose. This makes your code more reusable by allowing you to call it from other classes that need the same functionality.

We want to take this approach for many reasons, one of which is to take advantage of design patterns. Another is separation of concerns. Here are some of the advantages of this approach:

  • Small classes can easily be referenced from "Factory" classes or "Templates" in creational patterns.

  • Small classes are much easier to test.

  • If written properly, small classes can be decoupled from other classes.

  • If decoupled, when methods are revised, there won't be dependencies that require you to make changes in other classes (use abstractions & interfaces where appropriate).

  • Code becomes more reusable and gets cached by platform if frequently accessed.

    1. As a simple example, there's no need to include a wrapper class in a large class when you can have a class that can be reused by many classes of the type "wrapper(Id,sObject)". Instead, you can call the same generic wrapper without repeating that code in numerous classes.

    2. Similarly, there's no need to repeat certain types of queries or CRUD operations that can be factored out into service, selector or domain classes.

I'd encourage you to go through the newest Trailhead modules on the Apex Enterprise Patterns that cover the Domain and Selector Layers and the Service Layer. If you really want to understand these principles, I'd further encourage you to read Force.com Enterprise Architecture by @andrefawcett and also Apex Design Patterns by Jitendra Zaa.

  • 1
    Everything else you are saying makes sense, but "heavy to load" and "light to load" should be removed or explained in more detail. Do larger classes take a disproportionate amount of time to load? – Jagular Mar 24 '17 at 19:43
  • 1
    @Jagular Thanks, have edited to be more clear on meaning. Was referring to memory/heap. – crmprogdev Mar 24 '17 at 19:59
10

This question is extremely broad and opinion based, and should probably be closed. But here's my two cents.

Separation Of Concerns

The basic point here is that you almost certainly aren't separating your concerns when your class and method definitions grow large. Your two biggest wins in applying a philosophy of Separation Of Concerns (SOC) are testability and maintainability.

When your classes and methods become monolithic, it becomes increasingly likely that they are doing too much in one go. Consider the term Unit Test. What I was taught during code review was that we should strive to keep our tests atomic. These terms reinforce the SOC paradigm. I was once told:

A single unit should be one how or many whats.

It may be an over-simplification, but again SOC is about reinforcing a paradigm. It should almost never take 100 lines to lay out a single how. And unless you have a great many whats, the limits they've laid out should cover the vast majority of code scenarios.

A few common examples of conflating too much code in one method:

  • Complex logic within a loop
    • Move the processing out into its own function and pass in necessary state
    • If there is a great amount of relevant data in scope, taking a more OOP approach may help maintain state
  • Co-mingled filters with actions
    • Often with triggers, for example, you will see an action method written to also perform the necessary filters. This conflation makes the data much more complicated to set up and verify.
  • Long if/else chains
    • Most of the time such logic can be moved to a Map.

Efficiency

Note that while it is still likely that using Process Builder will perform slowly when compared with well tuned, perfectly optimized Apex code, not all Apex is created equal, and there may be some correlation between the size of your methods and classes, and the performance they obtain.

  • 3
    It is a very broad question but I think what you said about separations of concerns is extremely important when it comes to the concept of MVC and other aspects of OOP. I believe a lot of people are getting into Salesforce/Apex Developement without having the background of an OOP. So sure this should of been closed, but I believe there is an issue in SFDC developers (myself included) in understanding how we should handle OOP in our orgs – EricSSH Mar 25 '17 at 6:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.