DEV Community

Cover image for DRY (Don't Repeat Yourself)
Parzival
Parzival

Posted on

1

DRY (Don't Repeat Yourself)

Core Concept

DRY emphasizes that every piece of knowledge in a system should have a single, unambiguous representation.

Examples of Code Violating DRY

Example 1: Validation Logic

// WET (Write Everything Twice) Code
class User {
    public function validateUsername($username) {
        if (strlen($username) < 3 || strlen($username) > 20) {
            throw new Exception("Username must be between 3 and 20 characters");
        }
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
            throw new Exception("Username can only contain letters, numbers and underscore");
        }
    }

    public function updateUsername($username) {
        // Same validation repeated
        if (strlen($username) < 3 || strlen($username) > 20) {
            throw new Exception("Username must be between 3 and 20 characters");
        }
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
            throw new Exception("Username can only contain letters, numbers and underscore");
        }
        // Update logic
    }
}
Enter fullscreen mode Exit fullscreen mode

DRY Solution

class User {
    private function validateUsername($username) {
        if (strlen($username) < 3 || strlen($username) > 20) {
            throw new Exception("Username must be between 3 and 20 characters");
        }
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
            throw new Exception("Username can only contain letters, numbers and underscore");
        }
    }

    public function createUser($username) {
        $this->validateUsername($username);
        // Creation logic
    }

    public function updateUsername($username) {
        $this->validateUsername($username);
        // Update logic
    }
}
Enter fullscreen mode Exit fullscreen mode

Implementing DRY with Inheritance

abstract class BaseController {
    protected function jsonResponse($data, $status = 200) {
        header('Content-Type: application/json');
        http_response_code($status);
        echo json_encode($data);
    }
}

class UserController extends BaseController {
    public function show($id) {
        $user = User::find($id);
        return $this->jsonResponse($user);
    }
}

class ProductController extends BaseController {
    public function show($id) {
        $product = Product::find($id);
        return $this->jsonResponse($product);
    }
}
Enter fullscreen mode Exit fullscreen mode

Using Traits for DRY

trait Loggable {
    private function log($message) {
        $timestamp = date('Y-m-d H:i:s');
        file_put_contents('log.txt', "[$timestamp] $message\n", FILE_APPEND);
    }
}

class UserService {
    use Loggable;

    public function createUser($data) {
        $this->log("Creating new user");
        // User creation logic
    }
}

class PaymentService {
    use Loggable;

    public function processPayment($amount) {
        $this->log("Processing payment: $amount");
        // Payment processing logic
    }
}
Enter fullscreen mode Exit fullscreen mode

Using Constants

class Config {
    const DEFAULT_ITEMS_PER_PAGE = 10;
    const MAX_UPLOAD_SIZE = 5242880; // 5MB
    const ALLOWED_FILE_TYPES = ['jpg', 'png', 'pdf'];
}

class FileUploadService {
    public function validateFile($file) {
        if ($file['size'] > Config::MAX_UPLOAD_SIZE) {
            throw new Exception("File too large");
        }

        $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
        if (!in_array($extension, Config::ALLOWED_FILE_TYPES)) {
            throw new Exception("Invalid file type");
        }
    }
}

class MediaController {
    public function index() {
        return $this->paginate(Config::DEFAULT_ITEMS_PER_PAGE);
    }
}
Enter fullscreen mode Exit fullscreen mode

These examples demonstrate how to apply DRY through various PHP features like inheritance, traits, constants, and proper method extraction. The goal is to maintain a single source of truth for any given functionality in your codebase.

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay