Separating Class Responsibilities with Clprolf

Published: (December 4, 2025 at 01:06 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Overview

Designing clean, well‑structured classes is a central challenge in object‑oriented programming.
Clprolf introduces declensions – a simple way to express the nature of a class and the domain it belongs to – without replacing your existing architecture. Repositories, services, controllers, entities, and abstractions stay where they are; the declension is added on top to ensure consistency.

Declensions

A declension tells whether a class belongs to the business/domain layer (agent) or the technical layer (worker_agent). The term is borrowed from natural languages, where a word changes form depending on its use while keeping the same core identity.

Main declensions

DeclensionTypical responsibilities
agentBusiness logic, domain concepts, abstractions, simulation entities
worker_agentTechnical components: repositories, display logic, file operations, system interactions, launchers

Synonyms

Within a declension, synonyms refine the intention without changing the domain.

  • agent synonyms: abstraction (conceptual or structural elements, e.g., List, Button, Color), simu_real_obj (objects inside a simulation)
  • worker_agent synonyms: comp_as_worker (same meaning with a simulation nuance)

These synonyms do not alter the actual domain; they simply provide clearer terminology for developers.

Integration with Existing Components

Clprolf does not replace Service, Repository, or Controller roles. It adds a declension annotation on top of them to enforce consistent boundaries.

Typical mapping

Component typeDeclension
Repository / DAOworker_agent
Serviceagent
Controlleragent (or worker_agent if the architecture treats controllers as purely technical endpoints)

Inheritance Rules

Clprolf supervises inheritance between components indirectly:

  • A worker_agent cannot inherit from an agent (e.g., a Repository cannot inherit from a Service).
  • An agent cannot inherit from a technical class.
  • Two classes with the same declension may inherit, but a warning is issued if they use different synonyms, indicating differing perspectives.

These rules prevent accidental cross‑domain inheritance and keep responsibilities clear over time.

Comparison with DDD and Clean Architecture

  • DDD relies on conventions and team discipline to model the domain and maintain a ubiquitous language.
  • Clean Architecture separates domain and technical layers by guidelines, patterns, and project structure.
  • Clprolf enforces domain vs. technical roles at the language level, turning architectural boundaries into compiler‑checked guarantees.

Thus, Clprolf works alongside DDD and Clean Architecture, providing additional safety without replacing them.

Approach Comparison

ApproachFocusEnforcement
DDDDomain modelling, ubiquitous languageConventions & team discipline
Clean ArchitectureSeparation of domain vs. technical layersGuidelines, patterns, project structure
ClprolfDeclensions: domain vs. technical rolesCompiler‑checked, enforced by the language

Example Usage (Java)

// Business logic (agent)
@Agent
public class OrderService {

    private final OrderRepository repository = new OrderRepository();

    public void validateAndStore(String orderId) {
        // Business logic
        System.out.println("Validating order " + orderId);

        // Technical operation delegated to a worker_agent
        repository.save(orderId);
    }
}
// Technical work (worker_agent)
@Worker_agent
public class OrderRepository {

    public void save(String orderId) {
        System.out.println("Saving order " + orderId);
    }
}
// Illegal inheritance – compilation error
@Worker_agent
public class WrongRepo extends OrderService {
    // ❌ A worker_agent cannot inherit from an agent.
}
// Domain object (agent)
@Agent
public class Animal {

    public void eat(String food) {
        System.out.println("The animal eats " + food);
    }
}
// Service using technical workers
@Agent
public class CheckoutService {

    private final OrderRepository orders = new OrderRepository();
    private final PaymentRepository payments = new PaymentRepository();

    public void checkout(String orderId) {
        orders.save(orderId);
        payments.process(orderId); // Technical operation
    }
}

These examples demonstrate that:

  • Existing components (Service, Repository, Controller) remain unchanged.
  • Adding @Agent or @Worker_agent clarifies the domain of each class.
  • Inheritance respects the business ↔ technical separation, preventing accidental mixing.

Benefits

  • Clear separation of business and technical logic.
  • Compiler‑checked boundaries reduce accidental cross‑domain inheritance.
  • Consistent terminology via declension synonyms.
  • Compatibility with SOLID principles, DDD, and Clean Architecture.
  • Predictable, readable, and maintainable codebase for new developers.

Further Reading

Full Clprolf manual, specifications, and framework source code are available at:

https://github.com/charleskoffler/clprolf

Back to Blog

Related posts

Read more »