Loading ...

Designing Reusable Business Logic with Abstract Graphs in Acumatica

In real Acumatica projects, it’s very common to have multiple screens that behave similarly at a high level while still requiring their own business rules. One screen might validate and process documents, another might do something almost identical, but the rules and conditions differ. When developers copy and paste this logic across graphs, the code becomes hard to maintain, changes become risky, and small differences over time create bugs that are difficult to trace.

From both an Acumatica and .NET perspective, this is a clear case for abstraction. The goal is to centralize the shared workflow while still forcing each screen to implement its own business logic. The best approach in this scenario is to create an abstract base graph that encapsulates common behavior, and then derive concrete graphs that implement the screen-specific rules.

 

Why Helper Classes Are Not Enough

Helper classes are often the first thing developers try, and they can reduce duplication. However, they usually fall short in Acumatica because most real business logic depends on graph context. A helper class does not naturally participate in the graph lifecycle, and it becomes awkward when logic needs access to views, actions, caches, and events.

Even more importantly, helper classes do not enforce implementation. A developer can forget to call a validation method or skip an important step, and there will be no compile-time feedback. Abstract graphs solve this by keeping the workflow inside the graph and enforcing required business logic through abstract methods.

 

The Core Concept

The idea is to define a base abstract graph that contains the shared workflow. This base graph defines what happens and in what order, but it does not define the business rules. Instead, it exposes abstract methods like Validate and ApplyBusinessLogic, which must be implemented by derived graphs.

Each concrete graph then inherits the shared behavior and provides its own implementation. This ensures consistency across screens while keeping business rules isolated, readable, and easy to evolve.

 

Creating the Abstract Base Graph

The abstract graph encapsulates the processing flow and defines extension points for business logic.

This design gives you a consistent execution pipeline and guarantees that key steps are always present. A derived graph cannot compile unless it provides implementations for the abstract methods, which means your business rules are not optional or easy to forget.

 

Implementing Screen Specific Business Logic

Now each screen inherits from the base graph and implements only what is unique to that screen.

Another screen can reuse the same workflow while enforcing completely different rules.

Both graphs share the same processing behavior, but their rules remain isolated and explicit. This makes future changes much safer, because updates to the workflow happen once in the base graph, while business rules stay specific to each screen.

 

Why This Approach Is a Best Practice

From an Acumatica perspective, this pattern keeps business logic where it belongs, inside the graph. It also creates predictable behavior across screens, which helps debugging and reduces surprises for anyone maintaining the customization later. It aligns well with the way Acumatica is designed, where the graph is the unit of orchestration and business operations.

From a .NET perspective, this implements the Template Method pattern. It improves separation of concerns, reduces duplication, and uses compile-time enforcement to guarantee correct implementation. Your shared workflow is stable and reusable, while business rules remain flexible and easy to replace.

 

Extending the Pattern with Events

This pattern also works well with events. The base graph can define shared event behavior, and derived graphs can override only what they need.

When to Use Abstract Graphs

This approach is ideal when you have multiple screens that share a workflow but differ in business rules. It is especially useful when you expect future screens to follow the same general flow, because adding a new screen becomes straightforward. You inherit the base graph, implement the required methods, and you instantly get the same consistent behavior.

It is less useful for single screens, very small customizations, or cases where the logic is truly identical and does not require per-screen variation.

 

An Alternative Approach Using Composition

While abstract graphs provide a clean and powerful solution, inheritance is not always the right tool. In Acumatica, especially when working with Graph Extensions or when inheritance chains become deep, composition can be a better architectural choice.

Composition focuses on sharing behavior through dedicated components instead of shared base classes. Instead of inheriting a workflow, the graph owns a behavior object and delegates work to it. This keeps graphs independent while still reusing logic.

This approach aligns well with the principle of favoring composition over inheritance, particularly in systems that evolve over time.

 

 

 

Defining a Reusable Processing Component

With composition, we move shared behavior into a standalone class that is graph-aware but not a graph itself.

This class contains no business rules. It defines the workflow and requires the caller to provide validation and processing logic explicitly.

 

Using Composition in a Graph

Each graph creates and uses the behavior component, while keeping full control over its rules.

Another graph can reuse the same behavior without inheriting anything.

Here, the workflow is shared, but each graph stays fully independent.

 

Comparing Inheritance and Composition

Both approaches solve the same problem, but they excel in different scenarios.

Inheritance with abstract graphs provides strong guarantees. The workflow is enforced at compile time, and every derived graph must implement the required business logic. This makes it ideal for full graphs where you control the design and want strict consistency across screens.

Composition offers flexibility. Graphs are not tied to a base class, which makes this approach safer when working with existing screens or Graph Extensions. It also avoids deep inheritance hierarchies, which can become difficult to manage in large solutions.

 

Which Approach Is Better for Full Graphs

For full custom graphs, abstract graphs are usually the better choice. They provide a clear contract, enforce correct implementation, and make the workflow obvious. When you are designing a family of related screens from scratch, inheritance gives you structure and predictability.

Abstract graphs also integrate more naturally with shared event logic and common actions, which keeps the design cohesive.

 

Which Approach Is Better for Graph Extensions

For Graph Extensions, composition is almost always the better approach. Extensions cannot change inheritance, and forcing inheritance through refactoring often leads to brittle designs. Composition allows you to inject shared behavior without fighting the framework.

With composition, extensions can reuse logic while remaining loosely coupled. This is especially important when extending multiple standard Acumatica screens that were never designed to share a base graph.

Be the first to rate this post

  • Currently 0.0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5