Skip to content

Enumerations

Info

At ConnectSoft, Enumerations are not simple technical enums —
they are rich domain concepts that evolve, carry behaviors, and express business meaning cleanly.


Introduction

In Domain-Driven Design (DDD), Enumerations are used to model domain-specific choices and states
that must be explicit, meaningful, and sometimes behavior-rich — going beyond simple technical enums.

Simple Enums (like integers) are often insufficient because:

  • They are not extensible without modifying source code.
  • They cannot carry domain behaviors.
  • They are tightly coupled to static primitives.

At ConnectSoft, we use Enumeration Classes (sometimes called Smart Enums) to:

  • Model complex business concepts (e.g., OrderStatus, PaymentMethod, SubscriptionPlan).
  • Add behaviors and business rules directly into the Enumeration.
  • Support future extensibility without major rewrites.

Concept Definition

An Enumeration in the DDD sense:

Aspect Description
Purpose Represents a fixed set of meaningful domain choices.
Type Modeled as a full class, not just primitive enums.
Behavior Can carry domain behaviors and validations.
Extensibility New values can be added without breaking old code.
Identity Identified by stable IDs or Codes, not implicit ordering.
Examples OrderStatus, PaymentMethod, AppointmentType.

📚 Why Rich Enumerations Matter at ConnectSoft

Model Business Language Precisely

  • Enumerations express domain concepts clearly (e.g., "Paid", "Pending", "Cancelled").

Extend Behavior Safely

  • New options can add new behaviors (e.g., different pricing logic for a new SubscriptionPlan).

Preserve Backward Compatibility

  • Systems consuming Enumerations via APIs or Events remain stable as new options are introduced.

Encourage Open/Closed Principle

  • Behavior can change based on the Enumeration without changing consumers.

Improve Domain Expressiveness

  • Code reads naturally for developers and business stakeholders alike.

Simple Enum vs Rich Enumeration Class

Aspect Simple Enum Rich Enumeration
Type Language primitive (enum) Class-based model
Behavior Cannot hold methods or logic Can contain domain behaviors
Extensibility Requires recompilation Extendable without touching existing code
Serialization Control Limited (names/ints) Full control (Id, Name, extra metadata)
Example enum OrderStatus { Pending, Paid, Cancelled } OrderStatus.Pending, OrderStatus.Paid instances with behavior

🧩 Visual: Enumeration and Domain Entity Relationship

flowchart TD
    OrderEntity["Order Entity"]
    OrderStatusEnum["OrderStatus Enumeration"]
    PaymentEntity["Payment Entity"]
    PaymentMethodEnum["PaymentMethod Enumeration"]

    OrderEntity -->|Has Status| OrderStatusEnum
    PaymentEntity -->|Has Method| PaymentMethodEnum
Hold "Alt" / "Option" to enable pan & zoom

✅ Entities reference Enumerations to model their domain states clearly.
✅ Enumerations may evolve independently from core Entity structure.


Strategic Design Principles for Enumerations

At ConnectSoft, Enumerations are modeled intentionally
only when a domain concept needs clear expression, stable identity, possible behavior, and safe evolution.


📚 Core Principles for Good Enumeration Design

Model Real Domain Concepts

  • Only introduce Enumerations for business-relevant states, types, or modes — not for technical flags.

Prefer Class-Based Enumerations Over Language Primitives

  • Primitive enums are not flexible enough to evolve with complex business needs.

Expose Stable Identifiers

  • Each Enumeration instance must expose a stable Id (integer or string) and a business-meaningful Name.

Allow Behavior When Needed

  • If needed, Enumeration classes can include methods or strategies related to the specific type.

Respect Open/Closed Principle

  • Adding a new Enumeration value should not require changing existing consumers.

Support Serialization Explicitly

  • Enumerations must serialize to known IDs or names — never rely on implicit enum integer values.

Avoid Mixing Enumeration and Infrastructure Concerns

  • Enumerations belong in the Domain Layer, not infrastructure or DTOs.

🎯 Clear Criteria: When to Use Rich Enumerations

✅ Use Rich Enumeration 🚫 Don't Use Rich Enumeration
Fixed set of domain states/types needed Ad-hoc, volatile flags
Possibility of behaviors per option No behavior variation
Business needs clear naming, IDs, metadata Internal-only technical flags
States evolve but require backward compatibility Constantly changing tech toggles
Need for future extension without breaking changes Static, unchanging two-state flags

🛑 Common Anti-Patterns to Avoid

Anti-Pattern Symptom Why It's Dangerous
Primitive Enums Everywhere Use enums for all states, no extensibility. Breaks flexibility, requires redeployment on changes.
Leaking Persistence Concerns Enumeration depends on database structure (e.g., foreign key to enum table). Tight coupling, breaks evolution safety.
Mixed Domain and Infrastructure Concepts Enumeration carries persistence IDs, DTO properties. Violates clean architecture separation.
Unstable Identifiers Enumeration values change ID or Name after creation. Breaks historical data, event consumers, APIs.
Overloading Enums Put unrelated concepts into a single Enumeration. Poor domain clarity, violates SRP (Single Responsibility Principle).

📚 Good vs Bad Enumeration Examples

✅ Good Enumeration Example 🚫 Bad Enumeration Example
OrderStatus: Pending, Paid, Cancelled Flags: A, B, C, D (no meaning)
PaymentMethod: CreditCard, PayPal, WireTransfer ProcessFlags: 0, 1, 2, 3
SubscriptionPlan: Free, Premium, Enterprise DbEnum: 1, 2, 3 with no meaning outside DB
Values stable across system lifetime Values tied to database row IDs

🧩 Visual: Enumeration Open/Closed Evolution

flowchart LR
    v1["Initial Enumeration"]
    v2["Enumeration + New Option Added (Backward Compatible)"]
    Consumer1["Old Consumer"]
    Consumer2["New Consumer"]

    v1 --> Consumer1
    v2 --> Consumer1
    v2 --> Consumer2
Hold "Alt" / "Option" to enable pan & zoom

✅ Existing consumers remain stable even when new Enumeration options are added.


ConnectSoft.Extensions.EntityModel.Enumeration Base Class

At ConnectSoft, we use the ConnectSoft.Extensions.EntityModel.Enumeration base class
to provide a consistent, powerful foundation for all enumeration implementations.

The base class provides:

  • Value (int) — Stable numeric identifier for persistence and serialization
  • ShortName (string) — Concise identifier for APIs and code references
  • LongName (string) — Human-readable description for UI and documentation
  • GetAll<T>() — Static method to retrieve all enumeration values via reflection
  • FromValue<T>(int value) — Factory method to create enumeration from numeric value
  • FromShortName<T>(string shortName) — Factory method to create enumeration from short name
  • Equals(), GetHashCode(), ToString() — Proper value semantics
  • IComparable — Support for sorting and comparison operations

C# Examples: Domain-Driven Enumerations at ConnectSoft

At ConnectSoft, Enumerations are full domain models
not just primitive flags — and often carry business rules, validations, and metadata.

All examples below are based on real implementations from the ConnectSoft.Saas.ProductsCatalog microservice.


🛠️ Example 1: SaaS Product Catalog — ProductStatusEnumeration

Real Implementation from ConnectSoft.Saas.ProductsCatalog.EntityModel:

// Ignore Spelling: Saas

namespace ConnectSoft.Saas.ProductsCatalog.EntityModel
{
    using System;
    using ConnectSoft.Extensions.EntityModel;

    /// <summary>
    /// Product status enumeration.
    /// </summary>
    public class ProductStatusEnumeration : Enumeration
    {
        /// <summary>
        /// Active - product status.
        /// </summary>
        public static readonly ProductStatusEnumeration Active = new ActiveProductStatusEnumeration();

        /// <summary>
        /// Inactive - product status.
        /// </summary>
        public static readonly ProductStatusEnumeration Inactive = new InactiveProductStatusEnumeration();

        /// <summary>
        /// Deprecated - product status.
        /// </summary>
        public static readonly ProductStatusEnumeration Deprecated = new DeprecatedProductStatusEnumeration();

        /// <summary>
        /// Initializes a new instance of the <see cref="ProductStatusEnumeration"/> class.
        /// </summary>
        protected ProductStatusEnumeration()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ProductStatusEnumeration"/> class.
        /// </summary>
        /// <param name="value">the value.</param>
        /// <param name="shortName">the sort name.</param>
        /// <param name="longName">the long name.</param>
        protected ProductStatusEnumeration(int value, string shortName, string longName)
            : base(value, shortName, longName)
        {
        }

        /// <summary>
        /// Active - product status enumeration class.
        /// </summary>
        [Serializable]
        private sealed class ActiveProductStatusEnumeration : ProductStatusEnumeration
        {
            public ActiveProductStatusEnumeration()
                : base(1, "Active", "Active")
            {
            }
        }

        /// <summary>
        /// Inactive - product status enumeration class.
        /// </summary>
        [Serializable]
        private sealed class InactiveProductStatusEnumeration : ProductStatusEnumeration
        {
            public InactiveProductStatusEnumeration()
                : base(2, "Inactive", "Inactive")
            {
            }
        }

        /// <summary>
        /// Deprecated - product status enumeration class.
        /// </summary>
        [Serializable]
        private sealed class DeprecatedProductStatusEnumeration : ProductStatusEnumeration
        {
            public DeprecatedProductStatusEnumeration()
                : base(3, "Deprecated", "Deprecated")
            {
            }
        }
    }
}

Key Pattern Elements:

Inherits from ConnectSoft.Extensions.EntityModel.Enumeration
Protected constructors prevent external instantiation
Private sealed nested classes for each enumeration value
[Serializable] attribute for persistence and serialization support
Three-part identity: Value (int), ShortName (string), LongName (string)

Usage in Entity:

public partial class ProductEntity : EntityWithTypedId<Guid>, IProduct
{
    // ... other properties ...

    /// <inheritdoc/>
    required public virtual ProductStatusEnumeration Status { get; set; }

    // ... other properties ...
}

Usage in Domain Logic:

var newProduct = new ProductEntity
{
    ProductId = productId,
    Name = "Salesforce CRM Cloud",
    DisplayName = "Salesforce CRM Cloud",
    Key = "Salesforce-CRM-Cloud",
    Description = "Unified CRM platform for sales, marketing, and customer support.",
    ProductCategory = "CRM",
    Status = ProductStatusEnumeration.Active,  // ✅ Using static readonly field
    LatestVersion = "v1.0.0",
    ReleaseNotes = "Initial release.",
};

🛠️ Example 2: SaaS Product Catalog — PricingTypeEnumeration with Rich Metadata

Real Implementation showing enumerations with descriptive metadata:

// Ignore Spelling: Saas Freemium

namespace ConnectSoft.Saas.ProductsCatalog.EntityModel
{
    using System;
    using ConnectSoft.Extensions.EntityModel;

    /// <summary>
    /// Pricing type enumeration.
    /// </summary>
    public class PricingTypeEnumeration : Enumeration
    {
        /// <summary>
        /// Fixed price - pricing type.
        /// </summary>
        public static readonly PricingTypeEnumeration FixedPrice = new FixedPricePricingTypeEnumeration();

        /// <summary>
        /// Tiered pricing - pricing type.
        /// </summary>
        public static readonly PricingTypeEnumeration TieredPricing = new TieredPricingPricingTypeEnumeration();

        /// <summary>
        /// Usage-based pricing - pricing type.
        /// </summary>
        public static readonly PricingTypeEnumeration UsageBasedPricing = new UsageBasedPricingPricingTypeEnumeration();

        /// <summary>
        /// Freemium - pricing type.
        /// </summary>
        public static readonly PricingTypeEnumeration Freemium = new FreemiumPricingTypeEnumeration();

        /// <summary>
        /// Subscription-based pricing - pricing type.
        /// </summary>
        public static readonly PricingTypeEnumeration SubscriptionBased = new SubscriptionBasedPricingTypeEnumeration();

        // ... more pricing types ...

        /// <summary>
        /// Initializes a new instance of the <see cref="PricingTypeEnumeration"/> class.
        /// </summary>
        protected PricingTypeEnumeration()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="PricingTypeEnumeration"/> class.
        /// </summary>
        /// <param name="value">the value.</param>
        /// <param name="shortName">the sort name.</param>
        /// <param name="longName">the long name.</param>
        protected PricingTypeEnumeration(int value, string shortName, string longName)
            : base(value, shortName, longName)
        {
        }

        /// <summary>
        /// Fixed Price - pricing type enumeration class.
        /// </summary>
        [Serializable]
        private sealed class FixedPricePricingTypeEnumeration : PricingTypeEnumeration
        {
            public FixedPricePricingTypeEnumeration()
                : base(1, "Fixed Price", "Fixed Price - A set price for the product or service regardless of usage or other factors.")
            {
            }
        }

        /// <summary>
        /// Tiered Pricing - pricing type enumeration class.
        /// </summary>
        [Serializable]
        private sealed class TieredPricingPricingTypeEnumeration : PricingTypeEnumeration
        {
            public TieredPricingPricingTypeEnumeration()
                : base(2, "Tiered Pricing", "Pricing that changes based on usage or quantities. Different tiers offer different pricing levels.")
            {
            }
        }

        /// <summary>
        /// Usage-Based Pricing - pricing type enumeration class.
        /// </summary>
        [Serializable]
        private sealed class UsageBasedPricingPricingTypeEnumeration : PricingTypeEnumeration
        {
            public UsageBasedPricingPricingTypeEnumeration()
                : base(4, "Usage-Based Pricing", "Pricing based on the amount of resources consumed or features used.")
            {
            }
        }

        /// <summary>
        /// Freemium - pricing type enumeration class.
        /// </summary>
        [Serializable]
        private sealed class FreemiumPricingTypeEnumeration : PricingTypeEnumeration
        {
            public FreemiumPricingTypeEnumeration()
                : base(7, "Freemium", "Offering basic features for free, with additional charges for premium features or higher usage.")
            {
            }
        }

        /// <summary>
        /// Subscription-Based - pricing type enumeration class.
        /// </summary>
        [Serializable]
        private sealed class SubscriptionBasedPricingTypeEnumeration : PricingTypeEnumeration
        {
            public SubscriptionBasedPricingTypeEnumeration()
                : base(8, "Subscription-Based", "Recurring charges on a periodic basis (e.g., monthly, annually).")
            {
            }
        }
    }
}

Rich LongName descriptions provide business context in the enumeration itself.
Extensible pattern — new pricing types can be added without modifying existing code.


🛠️ Example 3: SaaS Product Catalog — BillingCycleEnumeration with Business Context

Real Implementation showing enumerations with domain-specific descriptions:

// Ignore Spelling: Saas

namespace ConnectSoft.Saas.ProductsCatalog.EntityModel
{
    using System;
    using ConnectSoft.Extensions.EntityModel;

    /// <summary>
    /// The BillingCycle enumeration represents different billing frequencies or cycles at which charges are applied.
    /// Depending on your SaaS product's pricing structure, you might need to support various billing cycles.
    /// </summary>
    public class BillingCycleEnumeration : Enumeration
    {
        /// <summary>
        /// Monthly billing cycle.
        /// </summary>
        public static readonly BillingCycleEnumeration Monthly = new MonthlyBillingCycleEnumeration();

        /// <summary>
        /// Quarterly billing cycle.
        /// </summary>
        public static readonly BillingCycleEnumeration Quarterly = new QuarterlyBillingCycleEnumeration();

        /// <summary>
        /// Annually billing cycle.
        /// </summary>
        public static readonly BillingCycleEnumeration Annually = new AnnuallyBillingCycleEnumeration();

        /// <summary>
        /// One-Time billing cycle.
        /// </summary>
        public static readonly BillingCycleEnumeration OneTime = new OneTimeBillingCycleEnumeration();

        // ... more billing cycles ...

        /// <summary>
        /// Initializes a new instance of the <see cref="BillingCycleEnumeration"/> class.
        /// </summary>
        protected BillingCycleEnumeration()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BillingCycleEnumeration"/> class.
        /// </summary>
        /// <param name="value">the value.</param>
        /// <param name="shortName">the sort name.</param>
        /// <param name="longName">the long name.</param>
        protected BillingCycleEnumeration(int value, string shortName, string longName)
            : base(value, shortName, longName)
        {
        }

        /// <summary>
        /// Monthly - billing cycle enumeration class.
        /// </summary>
        [Serializable]
        private sealed class MonthlyBillingCycleEnumeration : BillingCycleEnumeration
        {
            public MonthlyBillingCycleEnumeration()
                : base(1, "Monthly", "Billing occurs on a monthly basis. Charges are applied every 30 days.")
            {
            }
        }

        /// <summary>
        /// Quarterly - billing cycle enumeration class.
        /// </summary>
        [Serializable]
        private sealed class QuarterlyBillingCycleEnumeration : BillingCycleEnumeration
        {
            public QuarterlyBillingCycleEnumeration()
                : base(2, "Quarterly", "Billing occurs every three months. Charges are applied every 90 days.")
            {
            }
        }

        /// <summary>
        /// Annually - billing cycle enumeration class.
        /// </summary>
        [Serializable]
        private sealed class AnnuallyBillingCycleEnumeration : BillingCycleEnumeration
        {
            public AnnuallyBillingCycleEnumeration()
                : base(4, "Annually", "Billing occurs once a year. Charges are applied every 365 days.")
            {
            }
        }

        /// <summary>
        /// One-Time - billing cycle enumeration class.
        /// </summary>
        [Serializable]
        private sealed class OneTimeBillingCycleEnumeration : BillingCycleEnumeration
        {
            public OneTimeBillingCycleEnumeration()
                : base(5, "One-Time", "A single charge is applied once, with no recurring billing. A one-time purchase or setup fee.")
            {
            }
        }
    }
}

Usage in Entity with Multiple Enumerations:

public class PricingModelEntity : EntityWithTypedId<Guid>, IPricingModel
{
    // ... other properties ...

    /// <inheritdoc/>
    required public virtual PricingTypeEnumeration PricingType { get; set; }

    /// <inheritdoc/>
    required public virtual BillingCycleEnumeration BillingCycle { get; set; }

    // ... other properties ...
}

Usage Example:

var pricingModel = new PricingModelEntity
{
    PricingModelId = Guid.NewGuid(),
    Name = "Premium Subscription",
    Key = "premium-subscription",
    DisplayName = "Premium Subscription Plan",
    Description = "Full feature access with monthly billing",
    CreationDate = DateTime.UtcNow,
    PricingType = PricingTypeEnumeration.SubscriptionBased,  // ✅ Using enumeration
    Currency = "USD",
    BasePrice = 99.99m,
    BillingCycle = BillingCycleEnumeration.Monthly,          // ✅ Using enumeration
    MinimumPrice = 99.99m,
    MaximumPrice = 99.99m,
    EditionPricingModels = new List<IEditionPricingModel>(),
};

🛠️ Working with Enumerations: Common Operations

The ConnectSoft.Extensions.EntityModel.Enumeration base class provides powerful static methods:

Getting All Enumeration Values

// Get all ProductStatusEnumeration values
IEnumerable<ProductStatusEnumeration> allStatuses = 
    Enumeration.GetAll<ProductStatusEnumeration>();

// Use in LINQ queries, validation, UI dropdowns, etc.
foreach (var status in allStatuses)
{
    Console.WriteLine($"{status.Value}: {status.ShortName} - {status.LongName}");
}

Creating Enumerations from Values

// Parse from numeric value (e.g., from database)
ProductStatusEnumeration status = 
    Enumeration.FromValue<ProductStatusEnumeration>(1);  // Returns Active

// Parse from short name (e.g., from API request)
ProductStatusEnumeration statusFromName = 
    Enumeration.FromShortName<ProductStatusEnumeration>("Active");

// Throws InvalidEnumerationException if value/name not found

Comparing Enumerations

// Value equality
if (product.Status == ProductStatusEnumeration.Active)
{
    // Product is active
}

// Comparison for sorting
var sortedStatuses = Enumeration.GetAll<ProductStatusEnumeration>()
    .OrderBy(s => s);  // Uses IComparable implementation

// Absolute difference calculation
int difference = Enumeration.AbsoluteDifference(
    ProductStatusEnumeration.Active,
    ProductStatusEnumeration.Deprecated
);

Using in Entity Queries

// Find all active products
var activeProducts = repository.Query<ProductEntity>()
    .Where(p => p.Status == ProductStatusEnumeration.Active)
    .ToList();

// Find products by pricing type
var freemiumProducts = repository.Query<ProductEntity>()
    .Where(p => p.PricingModel.PricingType == PricingTypeEnumeration.Freemium)
    .ToList();

📋 Complete Implementation Template

Here's a complete template you can use to create new enumerations following ConnectSoft patterns:

// Ignore Spelling: [Add any domain-specific terms here]

namespace YourNamespace.EntityModel
{
    using System;
    using ConnectSoft.Extensions.EntityModel;

    /// <summary>
    /// [Your enumeration] enumeration.
    /// </summary>
    public class YourEnumeration : Enumeration
    {
        /// <summary>
        /// [First value] - [description].
        /// </summary>
        public static readonly YourEnumeration FirstValue = new FirstValueEnumeration();

        /// <summary>
        /// [Second value] - [description].
        /// </summary>
        public static readonly YourEnumeration SecondValue = new SecondValueEnumeration();

        /// <summary>
        /// Initializes a new instance of the <see cref="YourEnumeration"/> class.
        /// </summary>
        protected YourEnumeration()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="YourEnumeration"/> class.
        /// </summary>
        /// <param name="value">the value.</param>
        /// <param name="shortName">the sort name.</param>
        /// <param name="longName">the long name.</param>
        protected YourEnumeration(int value, string shortName, string longName)
            : base(value, shortName, longName)
        {
        }

        /// <summary>
        /// [First value] - [description] enumeration class.
        /// </summary>
        [Serializable]
        private sealed class FirstValueEnumeration : YourEnumeration
        {
            public FirstValueEnumeration()
                : base(1, "FirstValue", "Descriptive long name for FirstValue")
            {
            }
        }

        /// <summary>
        /// [Second value] - [description] enumeration class.
        /// </summary>
        [Serializable]
        private sealed class SecondValueEnumeration : YourEnumeration
        {
            public SecondValueEnumeration()
                : base(2, "SecondValue", "Descriptive long name for SecondValue")
            {
            }
        }
    }
}

Follow this pattern for all new enumerations to ensure consistency across ConnectSoft projects.


📚 Key Lessons from ConnectSoft Enumeration Modeling

Good Practice Why It Matters ConnectSoft Implementation
Inherit from ConnectSoft.Extensions.EntityModel.Enumeration Provides consistent base functionality across all enumerations All enumeration classes inherit from the base Enumeration class
Use Value, ShortName, and LongName Three-part identity enables clear APIs, persistence, and UI display Value (int) for persistence, ShortName (string) for code/APIs, LongName (string) for UI
Private sealed nested classes for values Encapsulation and type safety — prevents external instantiation Each enumeration value is a private sealed nested class (e.g., ActiveProductStatusEnumeration)
Protected constructors Prevents external instantiation while allowing inheritance Base class and derived enumerations use protected constructors
[Serializable] attribute Enables proper serialization for persistence and messaging All nested enumeration value classes are marked [Serializable]
Use Enumeration.GetAll<T>() Reflection-based discovery of all enumeration values Base class provides GetAll<T>() method for retrieving all values
Use Enumeration.FromValue<T>() and FromShortName<T>() Safe parsing from persisted values or API inputs Factory methods handle parsing with proper exception handling
Rich LongName descriptions Business context embedded in enumeration itself LongName provides detailed descriptions for UI and documentation
Stable Value identifiers Never change numeric IDs after creation — ensures backward compatibility Value IDs are assigned once and never modified

🧩 Visual: Enumeration Usage Inside Application Service Workflow

sequenceDiagram
    participant API
    participant ApplicationService
    participant OrderAggregate
    participant Enumeration as OrderStatus Enumeration

    API->>ApplicationService: Place Order Request
    ApplicationService->>OrderAggregate: Create Order
    OrderAggregate->>Enumeration: Set Initial Status (Pending)
    OrderAggregate-->>ApplicationService: Order Created
    ApplicationService-->>API: Success Response
Hold "Alt" / "Option" to enable pan & zoom

✅ Enumerations participate naturally in orchestrated domain workflows.


Best Practices for Enumerations

At ConnectSoft, Enumerations are modeled as living domain concepts,
empowering the system to evolve naturally, scale behaviors, and communicate business meaning clearly.


📚 Best Practices Checklist

Use Enumeration Classes, Not Primitive Enums

  • Prefer class-based smart enums that can evolve and carry behavior.

Expose Stable Identifiers and Names

  • Provide explicit Id and Name fields for safe persistence, messaging, and APIs.

Model Business Behavior and Metadata

  • Add domain-relevant behaviors (e.g., validation rules, strategy differences).

Apply Open/Closed Principle

  • Add new Enumeration options without modifying consumer code.

Avoid Leaking Infrastructure Concerns

  • Keep Enumerations pure — no database IDs, no DTO dependencies.

Support Validation and Lookups

  • Provide explicit methods for listing, looking up, and validating Enumeration instances.

Version Carefully if Necessary

  • If Enumerations are exposed in public APIs or events, design versioning strategies safely.

Use Enumerations Only for Meaningful Domain Concepts

  • Avoid overloading Enumerations for technical flags or volatile toggles.

Conclusion

At ConnectSoft, Enumerations are not afterthoughts
they are strategic tools to:

  • Express real-world business states, types, and choices.
  • Safely extend system capabilities without risking fragile code rewrites.
  • Capture behaviors and metadata inside clear, maintainable models.
  • Enable APIs, Events, and UI layers to speak the true language of the domain.

Without rich Enumerations:

  • Systems drift into fragile procedural checks (if-else, switch-case chaos).
  • Adding a new type or status requires breaking core logic everywhere.
  • Business meaning is hidden behind technical plumbing.

With strong Enumeration modeling:

  • Evolution becomes safe.
  • Communication becomes clear.
  • Architecture remains aligned to business agility.

At ConnectSoft, Enumerations safeguard the flexibility, expressiveness, and integrity of our domain-driven software systems —
from E-Commerce to Finance to Healthcare to SaaS and AI ecosystems.

"Enumerations capture choices;
Smart Enumerations empower evolutions.
Build for change, model with meaning.
"


References

  • Books and Literature

    • Eric Evans — Domain-Driven Design: Tackling Complexity in the Heart of Software
    • Vaughn Vernon — Implementing Domain-Driven Design
    • Jimmy Nilsson — Applying Domain-Driven Design and Patterns
  • Online Resources

  • ConnectSoft Packages and Code

    • ConnectSoft.Extensions.EntityModel.Enumeration — Base enumeration class providing:
      • Value, ShortName, and LongName properties
      • GetAll<T>() method for reflection-based discovery
      • FromValue<T>() and FromShortName<T>() factory methods
      • Proper equality, hashing, and comparison semantics
      • Serialization support
    • Real-World Examples — See ConnectSoft.Saas.ProductsCatalog.EntityModel for production implementations:
      • ProductStatusEnumeration
      • PricingTypeEnumeration
      • BillingCycleEnumeration
      • AccessTypeEnumeration
      • And more...
  • ConnectSoft Internal Standards

    • ConnectSoft Smart Enumeration Patterns Playbook
    • ConnectSoft API and Event Modeling Guidelines
    • ConnectSoft Domain Layer Evolution Strategies