Search code examples
phparchitecturesolid-principlessingle-responsibility-principle

single responsibility principle and code readability


While trying to stick with single responsibility rule, my classes have started to look like this

$productImage = new ProductImage(// holds all rules for product image only
                    new ImageFile( // makes sure given file is an image file
                        new ReadableFile( // checks given item is a readable file / permissions check
                            new UploadedFile( // validates given file is uploaded file
                                new FilePath( // validates given string is a valid file path
                                    new Path( // validates for string to be a path
                                        new NonEmptyString( // given string is not empty
                                            '/tmp/xyzk7kjnbrukhg'
                                        )
                                    )
                                )
                            )
                        )
                    )
                );

This is just one sample. On the surface it all looks cool as it provides very simple and testable classes. but as you can notice the readability or usability of code sucks. I need to write countless lines of code even to handle a simple initialization of an uploaded file (as shown in the above code).

I have started to feel something is wrong and I have misunderstood the concept of single responsibility principle.

Is it how pure OOP with single responsibility for each class is handled or am I way off the mark?


Solution

  • You're totally way off from the SRP (Single Responsibility Principle). How SRP work is totally not seen in your code. It's ok that you've classes they are responsible for different jobs. May be or I guess, they are implemented by respecting SRP. The visibility of SRP is much less in your code except assumption.

    In OOP, classes depend on other classes. It's totally normal. Dependency Injection is completely seen in your code. But you can't maintain Dependency Injection via constructor method the way you did when you're building complex structure. That should be some what in the following way:

    <?php
    
    // given string is not empty
    $nonEmptyString = new NonEmptyString('/tmp/xyzk7kjnbrukhg');
    
    // validates for string to be a path
    $path = new Path($nonEmptyString);
    
    // validates given string is a valid file path
    $filePath = new FilePath($path);
    
    // validates given file is uploaded file
    $uploadedFile = new UploadedFile($filePath);
    
    // checks given item is a readable file / permissions check
    $readableFile = new ReadableFile($uploadedFile);
    
    // makes sure given file is an image file
    $imageFile = new ImageFile($readableFile);
    
    // holds all rules for product image only
    $productImage = new ProductImage($imageFile);
    

    But this is also not correct way do to do this. To do this proper way you need to use Factory Method Design Pattern. Factory Method Design Pattern actually creates other objects. Assuming you've a factory method pattern implementation and that will be responsible for creating ImageFile object as ProductImage has a dependency of ImageFile. Assuming you imported all the classes you need in the following code snippet:

    <?php
    
    class ImageFileFactory implements FactoryInterface
    {
        public static function make($string)
        {
            // given string is not empty
            $nonEmptyString = new NonEmptyString($string);
    
            // validates for string to be a path
            $path = new Path($nonEmptyString);
    
            // validates given string is a valid file path
            $filePath = new FilePath($path);
    
            // validates given file is uploaded file
            $uploadedFile = new UploadedFile($filePath);
    
            // checks given item is a readable file / permissions check
            $readableFile = new ReadableFile($uploadedFile);
    
            // makes sure given file is an image file
            return new ImageFile($readableFile);
        }
    }
    
    
    // Creates ImageFile instance
    $imageFile = ImageFileFactory::make('/tmp/xyzk7kjnbrukhg');
    
    // holds all rules for product image only
    $productImage = new ProductImage($imageFile); 
    

    Oh! I have a write on medium on SRP. If you may read it. Here is the link of SRP

    Hope this would help you! Happy Coding!