Abstract classes in Constellation are not a best practice

For sometime, circa Infinity version 8, Pega’s wizards in App Studio and Dev Studio have only created Concrete classes, even if it did not have records, it has been a concrete class. With the introduction of Blueprint and the Blueprint Import capability, this practice has continued and we now see this question more and more. Where is the Abstract class? Why is it missing? @Kamil Janeczek , @BraamSmithCLSA, @PauloTonin and myself have long discussed if this was deserved of its own Constellation 101 - there are a few details out there but this tends to be hard to find, or lost in all the other features and docs.

Hopefully, this article highlights this important concept with our community, and changes in practices when it comes to this new Architecture.

Why? Delivering working software quickly.

Constellation follows a “Center-out” approach focused on business outcomes and customer journeys rather than traditional technical components. Concrete classes align better with this philosophy and the Case Designer’s data modeling capabilities.

Abstract classes and Constellation

Abstract classes are not recommended in Constellation, utilising an abstract class will introduce several functional limitations that impact the user experience and data handling capabilities.
• No search and select support, which restricts data interaction
• Limited field support – only query fields work without manual configuration
• Breaks from Constellation’s design defaults optimized for concrete classes

When is it acceptable? Migrating from Traditional UI
Only as a workaround when migrating an existing Data Model to Constellation. If absolutely necessary, you’ll need a multi-stage configuration process including:

  1. Creating the empty abstract class
  2. Configuring it specifically for Constellation
  3. Adding and configuring single-page Data Pages for single-record reference fields
  4. Adding and configuring list Data Pages for list-of-records reference fields

See Defining abstract classes in Constellation

Conclusion

Use concrete classes for Data Objects. This is Constellation’s default design pattern and provides full out-of-the-box support for all data model features.

See more details

Pega docs and expert circles.

Constellation 101 Series

Enjoyed this article? See more similar articles in Constellation 101 series.

@MarcCheong

Thanks Marc Cheong & Team for sharing this best practice. Agree this was/is a debatable decision point when designing data type and nice to see this coming from Pega representatives.
So for constellation applications, we no more talk about Abstract / Concrete data types instead we just see the SOR pattern. Data objects that need to be persisted (define local or external SOR) Vs Data objects that need to be embedded (not persisted, so we mark just define data source later, so technically it uses pr_other table).

One more important thing to clarify on this line is - Even for the traditional UI design from App studio we face a similar situation, why not apply this same best practice for traditional UI as well (food for thought). For time being we can safely say this is applicable only for Constellation applications but still lot of projects do traditional UI design using app studio. Do we need to change the class to abstract in this situation? Hopefully at some point this best practice becomes applicable to Pega platform as whole not just specific UI design system.

Hope the documentations and Pega Academy carefully give verdict for these debates! (I have to update my content as well :sweat_smile:)

@MarcCheonghow does this tie in with concepts of inheritance for reusability, enterprise grade architecture and optimization against redundancies?

@Premkumar You’ve raised an excellent and insightful point. Thank you for elaborating on it.

You are correct that for quite some time, the wizards in App/Dev Studio has generated concrete classes for data objects, regardless of whether the UI is built using the traditional architecture or Constellation.

Personally, I feel the primary reason this best practice is now explicitly highlighted for Constellation is due to the immediate and tangible impact on the user experience that abstract classes can cause. In a traditional UI architecture, the drawbacks are often less visible to the end-user and are primarily felt by the development team through increased complexity, longer development cycles, and potential refactoring efforts down the line.

Your observation also perfectly aligns with the broader strategic direction of the Pega platform. The emphasis is increasingly on accelerating the delivery of value and working software. We see this in the evolution of features in Constellation, the removal of concepts like temporary cases, and the overall vision for Pega Blueprint and Blueprint-delivered. The goal is to lean into the lowest-code offerings provided by the platform, as these represent the fastest, simplest, and most accessible path to implementation.

This isn’t to say that more advanced implementation patterns are no longer possible or have been deprecated. However, the platform’s “path of least resistance” is intentionally being aligned with best practices to ensure that the default, out-of-the-box approach is also the most efficient and scalable one.

It’s a great discussion to have, and you’re right to point out the need for this to be a consistent message across the Pega platform and its documentation.

I want to zoom out a bit and look at this topic through a wider industry-adoption lens, comparing how different platforms and programming languages handle similar design trade-offs.

In classical OOP languages like 𝗝𝗮𝘃𝗮 and 𝗖#, 𝘢𝘣𝘴𝘵𝘳𝘢𝘤𝘵 classes are a 𝘭𝘢𝘯𝘨𝘶𝘢𝘨𝘦-𝘭𝘦𝘷𝘦𝘭 𝘤𝘰𝘯𝘴𝘵𝘳𝘶𝘤𝘵. The 𝗰𝗼𝗺𝗽𝗶𝗹𝗲𝗿 𝗽𝗿𝗲𝘃𝗲𝗻𝘁𝘀 𝗱𝗶𝗿𝗲𝗰𝘁 𝗶𝗻𝘀𝘁𝗮𝗻𝘁𝗶𝗮𝘁𝗶𝗼𝗻 𝗼𝗳 𝗰𝗹𝗮𝘀𝘀𝗲𝘀 𝗱𝗲𝗰𝗹𝗮𝗿𝗲𝗱 𝗮𝘀 𝗮𝗯𝘀𝘁𝗿𝗮𝗰𝘁 and enforces implementation of abstract methods in concrete subclasses. 𝗣𝘆𝘁𝗵𝗼𝗻 supports 𝘈𝘣𝘴𝘵𝘳𝘢𝘤𝘵 𝘉𝘢𝘴𝘦 𝘊𝘭𝘢𝘴𝘴𝘦𝘴 (𝘈𝘉𝘊𝘴) via the 𝗮𝗯𝗰 𝗺𝗼𝗱𝘂𝗹𝗲, but their use is optional. ABCs are enforced at runtime only when explicitly defined and used. 𝗝𝗮𝘃𝗮𝗦𝗰𝗿𝗶𝗽𝘁 has no native abstract class concept at all. In both Python and JavaScript, abstraction is primarily a design convention, not a structural requirement imposed by the language runtime.

In the earlier days, when Pega was less of a low-code platform, being a Java-built technology, it was naturally influenced by the Java-centric patterns. However, there is an important semantic difference here - In Java, instantiation means creating an 𝗼𝗯𝗷𝗲𝗰𝘁 𝗶𝗻 𝗺𝗲𝗺𝗼𝗿𝘆. In Pega terms, that is closest to creating a 𝗖𝗹𝗶𝗽𝗯𝗼𝗮𝗿𝗱 𝗽𝗮𝗴𝗲. In Pega, calling a class 𝗰𝗼𝗻𝗰𝗿𝗲𝘁𝗲 means something else: that the class is mapped to a physical database table. An abstract class can still have Clipboard pages and participate fully in runtime behavior, but it does not own its own 𝗽𝗲𝗿𝘀𝗶𝘀𝘁𝗲𝗻𝗰𝗲 𝗹𝗮𝘆𝗲𝗿.

If we look at other low-code platforms: 𝗠𝗲𝗻𝗱𝗶𝘅 supports abstract 𝗲𝗻𝘁𝗶𝘁𝗶𝗲𝘀 that cannot be instantiated directly but can define attributes. 𝗔𝗽𝗽𝗶𝗮𝗻 has no concept of abstract 𝗥𝗲𝗰𝗼𝗿𝗱 𝗧𝘆𝗽𝗲𝘀; all Record Types are concrete. 𝗢𝘂𝘁𝗦𝘆𝘀𝘁𝗲𝗺𝘀 also has no abstract 𝗲𝗻𝘁𝗶𝘁𝘆 concept, but differentiates between 𝗗𝗮𝘁𝗮𝗯𝗮𝘀𝗲 𝗘𝗻𝘁𝗶𝘁𝗶𝗲𝘀 and 𝗦𝘁𝗮𝘁𝗶𝗰 𝗘𝗻𝘁𝗶𝘁𝗶𝗲𝘀 to control mutability rather than existence.

Given that Pega is increasingly maturing as a 𝗹𝗼𝘄-𝗰𝗼𝗱𝗲/𝗻𝗼-𝗰𝗼𝗱𝗲 platform and focusing on a more 𝗺𝗼𝗱𝗲𝗹-𝗱𝗿𝗶𝘃𝗲𝗻 development approach, moving away from the abstract/concrete distinction makes sense, in my opinion. That said, I would prefer this configuration to disappear entirely from the rule form - so that there is no lingering ambiguity or confusion for developers.

@SamyaGanguly thanks for sharing your thoughts with the community.

@Premkumar

> So for constellation applications, we no more talk about Abstract / Concrete data types instead we just see the SOR pattern. Data objects that need to be persisted (define local or external SOR) Vs Data objects that need to be embedded (not persisted, so we mark just define data source later, so technically it uses pr_other table).

I think it is even simpler than that. Think of it as “Is my case data composed of any other types of data?”. My Account Onboarding case needs a Customer, an Address, and a Credit Assessment (among others). Each of these is a data object that needs to be in your application’s layer cake.

  • Where distinct records of the data object exist, the case types that use them add a Data Reference field of that data object.
  • Where the case holds its own instance of the data object, the case types that need them add an Embedded Data field of that data object.

Both approaches can happily use a data object whose underlying class is Concrete. And, yes, the philosophy fits for Traditional UI applications too.

> For time being we can safely say this is applicable only for Constellation applications but still lot of projects do traditional UI design using app studio. Do we need to change the class to abstract in this situation?

  • If you have an existing application using a Concrete class for Embedded Data. Leave it. Changing it to Abstract does not unlock any special powers, and in its current form it will play nicer with modern app configuration in App Studio.

@EricSchranz90 The choice of Concrete vs. Abstract is a persistence decision.

The inheritance design of the classes - and resulting architectural benefits that you and @MarcCheong allude to - is independent of the persistence decisions.

  • A Car can always inherit from a Vehicle.
  • Instances of a Car can be persisted (Concrete), even if instances of a Vehicle are never to be persisted (Abstract or Concrete).

If you were to build that data model in Infinity today, creating Vehicle as a Concrete class:

  • If no use case in your application needs to persist an instance of Vehicle, then Vehicle still behaves as Abstract.
  • With Vehicle defined as Concrete, you can Build for Change more easily when a future need emerges to record instances of Vehicle.

It can be harder to pin down whether certain business objects in enterprise data models will never require distinct records to be saved. Let Infinity’s studios create them as Concrete. If you don’t currently need to save them as distinct records, then that’s fine.

@SamyaGanguly yes I think that if we had our time again, we at Pega might have chosen different words to differentiate between Abstract and Concrete.

For the purposes of this conversation, the key distinction for our Pega ecosystem on these two terms is:

  • Abstract: instances in memory cannot be saved to the Infinity database
  • Concrete: instances in memory may optionally be saved to the Infinity database

As Infinity creates all new data objects as Concrete, every data object in modern Infinity applications has the option to save its instances, without any obligation to.

As we move into delivering applications using Blueprint, this is incredibly powerful. Blueprint will import (contextually correct) sample data for the case types and data objects that you choose build from the Blueprint. The sample data is stored as records in the Infinity database of your application. This helps your stakeholders get immediate visibility of how case types built from the Blueprint use Data References to those data objects, even when the data object eventually gets this data from another system-of-record.

So, I hope that you can see that the choice of Concrete for all data objects is a powerful tool that assists with rapid completion, playback, and business acceptance of user stories.

@EricSchranz90not a simple question, nor a simple answer. In my opinion, the Constellation architecture provides better reusability and implementation across the enterprise, especially approaching it with a modular architecture. Instead of just inheriting a collection of rules, you are now inheriting from and reusing a well-defined business object.

  • The customer data object, for example, is defined once with all its properties, views, logic, relevant records, and sourcing.

No logic hidden in the UI, to launch clipboard pages or transform data in the UI itself - no broken UI because someone has modified it without realising the true impact of their changes amongst the “spaghetti” of action sets and sections stacked in the UI. The primary unit of reuse becomes the data object itself, which is easily accessible in Constellation View authoring.​​​​​

This architecture is the technical embodiment of Pega’s Center-out business architecture. You define your core business logic and data entities in the “center,” independent of any specific channel (like web, mobile, or back office). This creates a stable, enterprise-wide foundation.

I’ve personally found, this also helps data redundancies by elevating the data object with that single source of truth, mitigating those “more common than comfortable” scenarios where we have multiple different definitions for the same data object in the same application.

Is that explicitly all down Abstract vs Concrete? No. However, this answer should be taken in the context of the architecture evolution, simplifying application design and build, all to provide working software quicker.

I would love your opinion. Does the adoption of Concrete data objects as standard impact your implementations?

@BraamSmithCLSA Thank you for the clarity! And yes, I agree.