Best practice with big classes Apex

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.


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.


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.