While there's abundant information about the Repository pattern on the internet with various implementation examples, applying these implementations to Apex presents several unique challenges.

Here, I'll introduce the Repository class configuration patterns I've actually tried in Apex, along with their respective advantages and disadvantages.


## Pattern 1: Use Case-Based Repository

This style defines individual Repository classes for each use case, where processing classes exist per use case. While this approach appears flexible in design, it creates the challenge of **mass generation of interfaces and concrete classes**.

Since Apex does not support namespaces, **creating a large number of classes can easily lead to name collisions and naming exhaustion**, which is a design constraint.


## Pattern 2: Object-Based Repository (Selector Pattern)

To reduce class count, there's also the approach of defining Repository (Selector) per SObject unit. Salesforce's official "Selector Pattern" introduces this style.

📚 [Official Selector Pattern Guide (Trailhead)](https://trailhead.salesforce.com/content/learn/modules/apex_patterns_dsl/apex_patterns_dsl_learn_selector_l_principles)

However, for frequently used objects like `Opportunity` with multiple purposes, the following problems arise:

- **Proliferation of detailed retrieval methods** to handle conditional branching
- Increased **query control through flag arguments**, making caller intentions unclear
- Method context becomes ambiguous, making **safe modifications impossible**

I consider this situation a classic example of **"the road to debt paved with good intentions"**.


## Solution: Built-in Repository and Query Delegation Pattern

Based on these challenges, I propose the **Query Delegation Pattern**.

This pattern adopts a design where **query construction is performed in the domain layer, delegating only pure I/O processing to the Repository**. This allows having just one common "Built-in Repository" class.

### Advantages of This Pattern

- ✅ Prevents excessive proliferation of Repository classes
- ✅ Keeps the intention "I want to retrieve this kind of data" and query construction in the same place
- ✅ Can absorb detailed query differences in the domain layer, avoiding Repository bloat
- ✅ No need to define Interface, making tests dramatically easier to write

In fact, this pattern in my projects has significantly lowered the psychological barrier to writing test code, improving productivity.

### A Key Principle: Immutability

A core architectural principle of the query builder (`Scribe`) is its immutability.
Every time you add a condition or a field (e.g., using `.whereEqual()` or `.field()`), it doesn't modify the original query object. Instead, it returns a new, modified instance. This design offers two powerful advantages:
- **Safety**: It completely prevents side effects. A base query can be passed around your application without any risk of it being accidentally modified.
- **Reusability**: It allows you to create a base query and then safely "branch" it into multiple, more specific queries

**Example:**
```apex
// Create a base query for all open opportunities
Scribe baseQuery = Scribe.source(Opportunity.getSObjectType())
    .whereEqual('IsClosed', false);

// Safely create variations without modifying the baseQuery
Scribe highValueQuery = baseQuery.whereGreaterThan('Amount', 100000);
Scribe urgentQuery = baseQuery.whereDate('CloseDate', 'THIS_MONTH');
```

## Key Features of Eloquent and MockEloquent

`Eloquent` and its test-double counterpart, `MockEloquent`, are core components of ApexEloquent. They provide the following features:

### Data Retrieval
- **`get()` and `first()`**: Retrieve query results as `IEntry` objects, which act as wrappers for the underlying `SObject` records.

### DML Operations
- **`doInsert()`, `doUpdate()`, `doDelete()`**: Perform standard DML operations for single `SObjects` or `List`.

### Complete Mocking Support
- **MockEloquent**: Provides a complete, in-memory mock of all `Eloquent` methods, enabling true, database-free unit testing.
- **Automatic Fake ID Assignment**: The mocked `doInsert()` method automatically assigns a realistic, fake record ID, simulating real database behavior.

### Advanced Testing Features
- **Mocking Non-writable Fields**: Override values for any field in your tests—even formula fields and other read-only system fields—using the powerful `MockEntry`.
- **"Select-Forgotten" Detection**: Get immediate feedback in your unit tests. The mock framework throws an error if you try to access a field that wasn't part of your `Scribe` query, ensuring your tests and production code behave identically.

These features significantly reduce data dependency issues and enhance safety in unit testing.


## Comparison with Traditional Patterns

| Aspect | Traditional Repository | Built-in Repository |
|--------|----------------------|-------------------|
| **Class Count** | High (multiple per use case) | Low (single shared class) |
| **Test Complexity** | Complex mocking setup | Simple mock configuration |
| **Query Location** | Scattered across repositories | Centralized in domain layer |
| **Maintenance** | Difficult with many interfaces | Easy with single interface |
| **Apex Compatibility** | Poor (namespace issues) | Excellent (Apex-optimized) |



## Conclusion

The "Query Delegation Pattern" combined with a "Built-in Repository" is more than just a practical choice—it's a **paradigm shift for Apex development**.

This approach liberates developers from the pitfalls of manual SOQL and database-dependent tests. It empowers teams to adopt a modern, test-driven workflow that was previously difficult to achieve on the Salesforce platform. By embracing this model, your team can not only reduce technical debt and accelerate development but also foster a culture of writing cleaner, more reliable, and fundamentally more maintainable code.
