---
title: Separate Processing And Data Access
impact: HIGH
impactDescription: enables testable business logic and cleaner architecture
tags: separation, repository, service, architecture, quality, php
---

## Separate Processing And Data Access

Mixing business logic with database queries (SQL or ORM calls) creates tight coupling. This makes unit testing difficult because it forces a dependency on a real database and violates the Single Responsibility Principle.

**Incorrect (mixed concerns in Service):**

```php
class OrderService {
    public function calculateDiscount($userId) {
        // Business logic mixed with database queries
        $user = DB::table('users')->where('id', $userId)->first();
        $orderCount = DB::table('orders')->where('user_id', $userId)->count();
        
        $discount = 0;
        if ($orderCount > 10) $discount += 5;
        if ($user->is_premium) $discount += 10;
        
        return $discount;
    }
}
```

**Correct (separated Service and Repository layers):**

```php
/**
 * Repository - Handles Data Access only
 */
class UserRepository {
    public function findById($id): ?User {
        return User::find($id);
    }
}

class OrderRepository {
    public function getCountByUserId($userId): int {
        return Order::where('user_id', $userId)->count();
    }
}

/**
 * Service - Handles Business Logic only
 */
class DiscountService {
    public function __construct(
        private UserRepository $userRepo,
        private OrderRepository $orderRepo
    ) {}

    public function calculateDiscount(int $userId): int {
        $user = $this->userRepo->findById($userId);
        $orderCount = $this->orderRepo->getCountByUserId($userId);
        
        return $this->compute(user, $orderCount);
    }

    private function compute(?User $user, int $count): int {
        $discount = 0;
        if ($count > 10) $discount += 5;
        if ($user?->is_premium) $discount += 10;
        return $discount;
    }
}
```

**Why separate them?**
- **Mockability**: You can test the `DiscountService` by mocking the repositories without touching a real database.
- **Maintainability**: If the database schema changes, you only update the Repository, not the business logic.
- **Reusability**: Different services can use the same repository methods.
- **Clarity**: High-level business rules are not obscured by low-level data access details.

**Tools:** Architectural review, PHPUnit (Mocking), Laravel Repository Pattern
