DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Classes, Enums, and Records Look Like Simple Language Features — Until You Realize They Define Your Entire Domain Model

Classes, Enums, and Records Look Like Simple Language Features — Until You Realize They Define Your Entire Domain Model

Classes, Enums, and Records Look Like Simple Language Features — Until You Realize They Define Your Entire Domain Model

Why Senior .NET Engineers Spend More Time Designing Data Than Writing Business Logic

Most developers begin learning C## by creating variables.

string name = "Laptop";
decimal price = 999.99M;
int quantity = 5;
Enter fullscreen mode Exit fullscreen mode

At first, this feels perfectly reasonable.

The application works.

The compiler is happy.

Nothing appears wrong.

Then the system grows.

Suddenly you have:

  • Product names
  • Product descriptions
  • Categories
  • Inventory quantities
  • Suppliers
  • Status values
  • Registration dates

And now dozens of variables are floating around your application.

At that moment, a critical realization emerges:

The problem is no longer writing code.

The problem is modeling reality.

This is where Classes, Enums, and Records enter the picture.

And while they may appear to be simple language features, they are actually among the most important architectural tools available in modern C#.

Because software is ultimately a representation of real-world concepts.

The quality of that representation often determines the quality of the system itself.


TL;DR

Classes, Enums, and Records are not just syntax.

They introduce:

  • Domain Modeling
  • Type Safety
  • Encapsulation
  • Immutability
  • Compile-Time Validation
  • Business Rule Enforcement
  • Architectural Thinking

Senior .NET developers spend far more time designing data structures than writing algorithms.

Because a well-designed model eliminates entire categories of bugs before they can exist.


The Hidden Problem With Variables

Imagine an inventory application.

A beginner might write:

string productName = "Laptop";
string description = "Gaming Laptop";
decimal price = 1200M;
int quantity = 10;
Enter fullscreen mode Exit fullscreen mode

Nothing technically wrong.

But there is a deeper issue.

These values are related.

They represent a single concept:

Product
Enter fullscreen mode Exit fullscreen mode

The code knows it.

The business knows it.

The developer knows it.

But the program does not.

This mismatch creates complexity.


Classes Are Models of Reality

A class allows us to group related information together.

public class Product
{
    public int Id { get; set; }

    public string Name { get; set; } = string.Empty;

    public string Description { get; set; } = string.Empty;

    public decimal Price { get; set; }

    public int Quantity { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Now the software understands:

These values belong together.

This is far more important than it appears.

Because software engineering is largely the process of creating useful abstractions.


A Class Is More Than a Container

Many beginners think:

A class stores data.

Not exactly.

A class models behavior and state.

Consider:

public class Product
{
    public decimal Price { get; set; }

    public int Quantity { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

The class isn't merely storing values.

It is defining a business concept.

The difference matters.

Because business concepts evolve.

Variables do not.

Models do.


Why Properties Exist

This lesson introduces:

public string Name { get; set; }
Enter fullscreen mode Exit fullscreen mode

Instead of:

public string Name;
Enter fullscreen mode Exit fullscreen mode

Properties provide control.

They allow:

  • Validation
  • Encapsulation
  • Computed values
  • Future extensibility

Without changing the public contract.

This becomes incredibly important in large systems.


Computed Properties Eliminate Duplication

One of the most elegant concepts introduced in this lesson is:

public decimal TotalValue =>
    Price * Quantity;
Enter fullscreen mode Exit fullscreen mode

This is called a computed property.

Notice what it eliminates:

public decimal TotalValue;
Enter fullscreen mode Exit fullscreen mode

Storing calculated values creates risk.

What happens if:

Price changes
Enter fullscreen mode Exit fullscreen mode

but:

TotalValue does not
Enter fullscreen mode Exit fullscreen mode

Now the system contains inconsistent data.

Computed properties solve this problem.

The value is always derived from the source of truth.

This is a powerful design principle:

Store facts.

Calculate everything else.


ToString() Is About Communication

Every object eventually needs to communicate.

That is why:

public override string ToString()
{
    ...
}
Enter fullscreen mode Exit fullscreen mode

exists.

A custom ToString() allows a domain object to describe itself meaningfully.

Instead of:

Inventory.Models.Product
Enter fullscreen mode Exit fullscreen mode

you might display:

Laptop - $1200 - Qty: 10
Enter fullscreen mode Exit fullscreen mode

Small improvement.

Massive usability gain.


DateTime Represents More Than a Date

The lesson introduces:

DateTime CreatedAt
Enter fullscreen mode Exit fullscreen mode

Many developers underestimate timestamps.

Yet timestamps are among the most important pieces of data in software.

They answer questions like:

  • When was this created?
  • When was it modified?
  • When does it expire?
  • When was it purchased?

Most enterprise systems are built around events.

Events require time.

And time requires proper modeling.


Strings Are Dangerous for Business Rules

Imagine this property:

public string Category { get; set; }
Enter fullscreen mode Exit fullscreen mode

Seems harmless.

Until somebody writes:

Electronics
electronics
Electronic
Electronica
Electrnics
Enter fullscreen mode Exit fullscreen mode

All technically valid strings.

All representing the same concept.

The compiler cannot help you.

This is where Enums become transformational.


Enums Turn Runtime Problems Into Compile-Time Problems

Consider:

public enum ProductCategory
{
    Electronics,
    Home,
    Office,
    Other
}
Enter fullscreen mode Exit fullscreen mode

Now:

ProductCategory.Electronics
Enter fullscreen mode Exit fullscreen mode

is guaranteed to be valid.

The compiler becomes your ally.

If a developer writes:

ProductCategory.Electrnics
Enter fullscreen mode Exit fullscreen mode

the application fails during compilation.

Not production.

That distinction is priceless.


Type Safety Is a Competitive Advantage

One of the hidden superpowers of C## is type safety.

Enums strengthen that safety dramatically.

Instead of:

string status = "Active";
Enter fullscreen mode Exit fullscreen mode

you get:

ProductStatus.Active
Enter fullscreen mode Exit fullscreen mode

The compiler now understands the business domain.

And software becomes safer.


Why Enums Matter in Enterprise Systems

Enums appear everywhere:

OrderStatus
PaymentStatus
UserRole
SubscriptionType
NotificationType
Enter fullscreen mode Exit fullscreen mode

They create explicit business vocabulary.

And explicit vocabulary reduces ambiguity.

Reducing ambiguity reduces bugs.


Records Introduce a Different Philosophy

Classes assume change.

Records assume stability.

This distinction is subtle.

And extremely important.

Consider a supplier:

public record Supplier(
    int Id,
    string Name,
    string Email,
    string Phone);
Enter fullscreen mode Exit fullscreen mode

A supplier record represents information that rarely changes.

The design communicates intent.


Classes Are Mutable

Mutable means:

product.Price = 2000M;
Enter fullscreen mode Exit fullscreen mode

is allowed.

This is useful when state changes naturally.

Inventory changes.

Prices change.

Quantities change.

Products evolve.

A class fits this scenario perfectly.


Records Are Immutable

Records encourage:

var supplier =
    new Supplier(
        1,
        "Contoso",
        "info@contoso.com",
        "555-1234");
Enter fullscreen mode Exit fullscreen mode

Once created:

The data remains stable.

This dramatically reduces bugs caused by unintended state changes.


Reference Equality vs Value Equality

This is where records become fascinating.

Classes compare references:

productA == productB
Enter fullscreen mode Exit fullscreen mode

asks:

Are these the same object?

Records compare values:

supplierA == supplierB
Enter fullscreen mode Exit fullscreen mode

asks:

Do these objects contain the same data?

That difference changes how systems behave.

Especially in distributed architectures.


Immutability Is One of the Most Powerful Engineering Concepts

Modern software increasingly favors immutable data.

Why?

Because immutable objects:

  • Are easier to reason about
  • Reduce side effects
  • Improve thread safety
  • Simplify debugging
  • Reduce accidental mutations

Records make immutability approachable.


The Hidden Lesson Behind This Module

At first glance this lesson teaches:

  • Classes
  • Properties
  • Enums
  • Records

But beneath the surface it introduces:

  • Domain Modeling
  • Business Language
  • Data Integrity
  • Immutability
  • Type Safety
  • Software Design

The real lesson is not syntax.

The real lesson is representation.


The Senior Perspective

Beginners ask:

How do I create a class?

Experienced engineers ask:

What business concept am I modeling?

That question changes everything.

Because most software failures do not originate from algorithms.

They originate from poorly designed models.

Bad models create confusion.

Good models create clarity.

And clarity scales.


Final Thought

Classes, Enums, and Records may appear to be simple language constructs.

They are not.

They are tools for translating reality into software.

Classes model things that change.

Enums model constrained business rules.

Records model stable facts.

Together, they create a language that allows software to describe the world accurately.

And that is ultimately what engineering is:

Building reliable representations of reality.

The developers who master .NET eventually realize something surprising.

The hardest part is rarely writing code.

The hardest part is deciding what the code should represent.

And that journey begins with your models.


Written by Cristian Sifuentes

.NET Engineer · Domain Modeling Enthusiast · Software Architect · AI-Assisted Developer

Top comments (0)