One place for hosting & domains

      Object

      S.O.L.I.D: The First 5 Principles of Object Oriented Design


      S.O.L.I.D is an acronym for the first five object-oriented design(OOD)** principles** by Robert C. Martin, popularly known as Uncle Bob.

      These principles, when combined together, make it easy for a programmer to develop software that are easy to maintain and extend. They also make it easy for developers to avoid code smells, easily refactor code, and are also a part of the agile or adaptive software development.

      S.O.L.I.D stands for:

      Let’s look at each principle individually to understand why S.O.L.I.D can help make us better developers.

      Single-responsibility Principle

      S.R.P for short – this principle states that:

      A class should have one and only one reason to change, meaning that a class should have only one job.

      For example, say we have some shapes and we wanted to sum all the areas of the shapes. Well this is pretty simple right?

      class Circle {
          public $radius;
      
          public function construct($radius) {
              $this->radius = $radius;
          }
      }
      
      class Square {
          public $length;
      
          public function construct($length) {
              $this->length = $length;
          }
      }
      

      First, we create our shapes classes and have the constructors setup the required parameters. Next, we move on by creating the AreaCalculator class and then write up our logic to sum up the areas of all provided shapes.

      class AreaCalculator {
      
          protected $shapes;
      
          public function __construct($shapes = array()) {
              $this->shapes = $shapes;
          }
      
          public function sum() {
              // logic to sum the areas
          }
      
          public function output() {
              return implode('', array(
                  "",
                      "Sum of the areas of provided shapes: ",
                      $this->sum(),
                  ""
              ));
          }
      }
      

      To use the AreaCalculator class, we simply instantiate the class and pass in an array of shapes, and display the output at the bottom of the page.

      $shapes = array(
          new Circle(2),
          new Square(5),
          new Square(6)
      );
      
      $areas = new AreaCalculator($shapes);
      
      echo $areas->output();
      

      The problem with the output method is that the AreaCalculator handles the logic to output the data. Therefore, what if the user wanted to output the data as json or something else?

      All of that logic would be handled by the AreaCalculator class, this is what SRP frowns against; the AreaCalculator class should only sum the areas of provided shapes, it should not care whether the user wants json or HTML.

      So, to fix this you can create an SumCalculatorOutputter class and use this to handle whatever logic you need to handle how the sum areas of all provided shapes are displayed.

      The SumCalculatorOutputter class would work like this:

      $shapes = array(
          new Circle(2),
          new Square(5),
          new Square(6)
      );
      
      $areas = new AreaCalculator($shapes);
      $output = new SumCalculatorOutputter($areas);
      
      echo $output->JSON();
      echo $output->HAML();
      echo $output->HTML();
      echo $output->JADE();
      

      Now, whatever logic you need to output the data to the user is now handled by the SumCalculatorOutputter class.

      Open-closed Principle

      Objects or entities should be open for extension, but closed for modification.

      This simply means that a class should be easily extendable without modifying the class itself. Let’s take a look at the AreaCalculator class, especially it’s sum method.

      public function sum() {
          foreach($this->shapes as $shape) {
              if(is_a($shape, 'Square')) {
                  $area[] = pow($shape->length, 2);
              } else if(is_a($shape, 'Circle')) {
                  $area[] = pi() * pow($shape->radius, 2);
              }
          }
      
          return array_sum($area);
      }
      

      If we wanted the sum method to be able to sum the areas of more shapes, we would have to add more if/else blocks and that goes against the Open-closed principle.

      A way we can make this sum method better is to remove the logic to calculate the area of each shape out of the sum method and attach it to the shape’s class.

      class Square {
          public $length;
      
          public function __construct($length) {
              $this->length = $length;
          }
      
          public function area() {
              return pow($this->length, 2);
          }
      }
      

      The same thing should be done for the Circle class, an area method should be added. Now, to calculate the sum of any shape provided should be as simple as:

      public function sum() {
          foreach($this->shapes as $shape) {
              $area[] = $shape->area();
          }
      
          return array_sum($area);
      }
      

      Now we can create another shape class and pass it in when calculating the sum without breaking our code. However, now another problem arises, how do we know that the object passed into the AreaCalculator is actually a shape or if the shape has a method named area?

      Coding to an interface is an integral part of S.O.L.I.D, a quick example is we create an interface, that every shape implements:

      interface ShapeInterface {
          public function area();
      }
      
      class Circle implements ShapeInterface {
          public $radius;
      
          public function __construct($radius) {
              $this->radius = $radius;
          }
      
          public function area() {
              return pi() * pow($this->radius, 2);
          }
      }
      

      In our AreaCalculator sum method we can check if the shapes provided are actually instances of the ShapeInterface, otherwise we throw an exception:

      public function sum() {
          foreach($this->shapes as $shape) {
              if(is_a($shape, 'ShapeInterface')) {
                  $area[] = $shape->area();
                  continue;
              }
      
              throw new AreaCalculatorInvalidShapeException;
          }
      
          return array_sum($area);
      }
      

      Liskov substitution principle

      Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.

      All this is stating is that every subclass/derived class should be substitutable for their base/parent class.

      Still making use of out AreaCalculator class, say we have a VolumeCalculator class that extends the AreaCalculator class:

      class VolumeCalculator extends AreaCalulator {
          public function construct($shapes = array()) {
              parent::construct($shapes);
          }
      
          public function sum() {
              // logic to calculate the volumes and then return and array of output
              return array($summedData);
          }
      }
      

      In the SumCalculatorOutputter class:

      class SumCalculatorOutputter {
          protected $calculator;
      
          public function __constructor(AreaCalculator $calculator) {
              $this->calculator = $calculator;
          }
      
          public function JSON() {
              $data = array(
                  'sum' => $this->calculator->sum();
              );
      
              return json_encode($data);
          }
      
          public function HTML() {
              return implode('', array(
                  '',
                      'Sum of the areas of provided shapes: ',
                      $this->calculator->sum(),
                  ''
              ));
          }
      }
      

      If we tried to run an example like this:

      $areas = new AreaCalculator($shapes);
      $volumes = new AreaCalculator($solidShapes);
      
      $output = new SumCalculatorOutputter($areas);
      $output2 = new SumCalculatorOutputter($volumes);
      

      The program does not squawk, but when we call the HTML method on the $output2 object we get an E_NOTICE error informing us of an array to string conversion.

      To fix this, instead of returning an array from the VolumeCalculator class sum method, you should simply:

      public function sum() {
          // logic to calculate the volumes and then return and array of output
          return $summedData;
      }
      

      The summed data as a float, double or integer.

      Interface segregation principle

      A client should never be forced to implement an interface that it doesn’t use or clients shouldn’t be forced to depend on methods they do not use.

      Still using our shapes example, we know that we also have solid shapes, so since we would also want to calculate the volume of the shape, we can add another contract to the ShapeInterface:

      interface ShapeInterface {
          public function area();
          public function volume();
      }
      

      Any shape we create must implement the volume method, but we know that squares are flat shapes and that they do not have volumes, so this interface would force the Square class to implement a method that it has no use of.

      ISP says no to this, instead you could create another interface called SolidShapeInterface that has the volume contract and solid shapes like cubes e.t.c can implement this interface:

      interface ShapeInterface {
          public function area();
      }
      
      interface SolidShapeInterface {
          public function volume();
      }
      
      class Cuboid implements ShapeInterface, SolidShapeInterface {
          public function area() {
              // calculate the surface area of the cuboid
          }
      
          public function volume() {
              // calculate the volume of the cuboid
          }
      }
      

      This is a much better approach, but a pitfall to watch out for is when type-hinting these interfaces, instead of using a ShapeInterface or a SolidShapeInterface.

      You can create another interface, maybe ManageShapeInterface, and implement it on both the flat and solid shapes, this way you can easily see that it has a single API for managing the shapes. For example:

      interface ManageShapeInterface {
          public function calculate();
      }
      
      class Square implements ShapeInterface, ManageShapeInterface {
          public function area() { /Do stuff here/ }
      
          public function calculate() {
              return $this->area();
          }
      }
      
      class Cuboid implements ShapeInterface, SolidShapeInterface, ManageShapeInterface {
          public function area() { /Do stuff here/ }
          public function volume() { /Do stuff here/ }
      
          public function calculate() {
              return $this->area() + $this->volume();
          }
      }
      

      Now in AreaCalculator class, we can easily replace the call to the area method with calculate and also check if the object is an instance of the ManageShapeInterface and not the ShapeInterface.

      Dependency Inversion principle

      The last, but definitely not the least states that:

      Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.

      This might sound bloated, but it is really easy to understand. This principle allows for decoupling, an example that seems like the best way to explain this principle:

      class PasswordReminder {
          private $dbConnection;
      
          public function __construct(MySQLConnection $dbConnection) {
              $this->dbConnection = $dbConnection;
          }
      }
      

      First the MySQLConnection is the low level module while the PasswordReminder is high level, but according to the definition of D in S.O.L.I.D. which states that Depend on Abstraction not on concretions, this snippet above violates this principle as the PasswordReminder class is being forced to depend on the MySQLConnection class.

      Later if you were to change the database engine, you would also have to edit the PasswordReminder class and thus violates Open-close principle.

      The PasswordReminder class should not care what database your application uses, to fix this again we “code to an interface”, since high level and low level modules should depend on abstraction, we can create an interface:

      interface DBConnectionInterface {
          public function connect();
      }
      

      The interface has a connect method and the MySQLConnection class implements this interface, also instead of directly type-hinting MySQLConnection class in the constructor of the PasswordReminder, we instead type-hint the interface and no matter the type of database your application uses, the PasswordReminder class can easily connect to the database without any problems and OCP is not violated.

      class MySQLConnection implements DBConnectionInterface {
          public function connect() {
              return "Database connection";
          }
      }
      
      class PasswordReminder {
          private $dbConnection;
      
          public function __construct(DBConnectionInterface $dbConnection) {
              $this->dbConnection = $dbConnection;
          }
      }
      

      According to the little snippet above, you can now see that both the high level and low level modules depend on abstraction.

      Conclusion

      S.O.L.I.D might seem to be a bit too abstract at first, but with each real-world application of S.O.L.I.D. principles, the benefits of adherence to its guidelines will become more apparent. Code that follows S.O.L.I.D. principles can more easily be shared with collaborators, extended, modified, tested, and refactored without any problems.



      Source link

      How to Move Objects Between Buckets in Linode's Object Storage


      Updated by Linode

      Contributed by
      Linode

      Marquee image for How to Move Objects Between Buckets in Linode's Object Storage

      Note

      Linode’s Object Storage is a globally-available, S3-compatible method for storing and accessing data. With Object Storage more widely available, you may have buckets in multiple locations, this guide shows you how to move objects between buckets quickly and easily.

      In this guide you learn how to move objects between buckets using:

      Before You Begin

      To learn how to enable Object Storage, see the How to Use Object Storage guide.

      Object Storage is similar to a subscription service. After it is enabled, you are billed at the flat rate regardless of whether or not there are active buckets on your account. Cancel Object Storage to stop billing for this flat rate.

      In all Object Storage URLs the cluster where your bucket is hosted is a part of the URL string.

      Note

      A cluster is defined as all buckets hosted by a unique URL; for example: us-east-1.linodeobjects.com, ap-south-1.linodeobjects.com, or eu-central-1.linodeobjects.com.

      Cyberduck Graphical Interface

      The easiest way to move objects between buckets is using a Graphical User Interface (GUI) such as Cyberduck. Using a GUI, you can simply drag and drop objects between buckets.

      Transfer Between Buckets in the Same Cluster

      To transfer objects within the same cluster on the same account, you need to open only one Cyberduck window.

      1. Open Cyberduck and make a connection to access your buckets as described in How to Use Linode Object Storage.

      2. Expand the two buckets you want to transfer objects between by clicking the down arrow to the left of the folders.

      3. Locate the object you want to transfer.

      4. Drag the item from the source location to the destination.

        Drag a File to Move

      5. Select multiple items or folders and drag the group to the destination.

        Drag Multiple Files to Move

      Transfer Between Buckets in Different Clusters

      To transfer objects between two clusters, whether they are on the same account or not, you need to open two separate Cyberduck widows so that you can make two separate connections.

      Note

      Transferring objects between two different connections creates a copy of the object(s). If you don’t want the original files in the source bucket, you need to delete them after the transfer.

      1. Open Cyberduck, click the File menu and select New Browser. A second interface window appears where you can create another connection.

      2. In the first window, connect to the source bucket and locate the object you want to copy.

      3. In the second window, connect to the destination bucket and navigate to the location you want to place a copy of the object.

      4. Drag the object from the source to the destination.

        Select Objects to Move Between Cyberduck Windows

      Note

      You can easily copy multiple items, folders, or buckets by selecting everything you want to move and dragging the group. If you move a bucket to another bucket, it creates a folder with that bucket name.

      Cyberduck CLI

      You can also use the Cyberduck CLI, duck, to move objects from one bucket to another using the command line. The file transfer tool duck, is available for Linux, macOS, and Windows. To transfer using duck, you need the access keys that you generated for the source and destination buckets.

      1. Install duck using the instructions for your platform.

      2. Use the access keys and bucket names in the following command to move objects between buckets:

        duck --copy s3://[email protected]$bucket_source/source_object_file_name s3://[email protected]$bucket_destination/destination_object_file_name
        

        After issuing this command, you may be asked for login information.

      Note

      The bucket source and destination names are the fully qualified names including the cluster name, for example: us-east-1.linodeobjects.com/example_bucket.

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      This guide is published under a CC BY-ND 4.0 license.



      Source link

      How to Configure Nextcloud to use Linode Object Storage as an External Storage Mount


      Updated by Linode

      Contributed by
      Linode

      Marquee image for How to Configure Nextcloud to use Linode Object Storage as an External Storage Mount

      Nextcloud is an open source solution for file hosting and sharing. With Nextcloud, you can synchronize files from a local computer to the Linode server and share them with collaborators. Nextcloud’s customizable security features and intuitive user interface keeps the files safe and easy to manage.

      You can configure Nextcloud to enable external storage devices and services, like Linode Object Storage, to use as a secondary place to store files. Using Linode Object Storage to store files prevents you from running out of storage space limited by the Linode’s plan size. When using Nextcloud’s graphical user interface (GUI) to manage files, the external storage device shows up just like any other folder.

      Before You Begin

      1. Deploy a Nextcloud server instance. You can use the Linode Nextcloud One-Click App for an easy and quick deployment.

      2. Enable the Object Storage service on your Linode account.

      3. Generate Object Storage access keys.

      4. If you are not familiar with Linode Object Storage, review the How to Use Linode Object Storage guide.

      In This Guide

      Nextcloud Configurations

      Enable the External Storage App

      In this section you enable the External Storage Support Nextcloud app in order to use external storage sources.

      Note

      You must belong to the admin user group in order to install the External storage support app.

      1. Log into your Nextcloud instance.

      2. Click the user icon (or cog wheel) in the top navigation menu and select Apps.

        Access Nextcloud App settings.

      3. Click Files to access all Nextcloud apps related to file management, in the left-hand navigation menu.

        Access the Files App settings.

      4. Use the search field in the top navigation to narrow down the visible apps. You can enter external as your search term.

      5. Viewing the External storage support app, click the Enable button in order to install it to the Nextcloud instance.

        Enable the external storage support app.

      Create a New Linode Object Storage External Storage Mount

      After enabling the External Storage Support app, you are now ready to add a new external storage mount. You configure the new external storage mount to use the Linode Object Storage service.

      Note

      1. Click the user icon (or cog wheel) in the top navigation menu and select Settings.

        Access Nextcloud settings.

      2. In the left-hand navigation menu, under the Administration heading, click External Storages. The External Storages administration page appears.

        Access external storage configurations.

      3. In the Folder name text entry box, provide a name for the external storage directory.

      4. From the External Storage dropdown menu, select the Amazon S3 option.

        Note

        Linode Object Storage is S3-compatible. Nextcloud connects to Amazon’s Object Storage service by default, however, in the next step you override the default behavior to use Linode Object Storage hosts instead.

      5. Select Access Key from the Authentication dropdown menu.

      6. Under the Configuration heading, provide the following configurations:

        Configuration Description
        Bucket The name to assign to the Object Storage bucket. If this bucket name already exists in the data center region you select, an error occurs.
        Hostname The hostname used for the Object Storage region where the bucket is be stored. Refer to the Linode Object Storage Region and Hostname Values note located below this table for available hostname values.
        Port The port number to use to access the Object Storage host. This value must be 443.
        Region The data center region to store your Object Storage bucket. Refer to the Linode Object Storage Region and Hostname Values note located below this table for available data center region IDs.
        Enable SSL A configuration to enable secure sockets layer (SSL). This configuration must be enabled.
        Enable Path Style This configuration changes the default path format used by Nextcloud to access the Object Storage bucket. Do not enable this configuration.
        Legacy (v2) Authentication This configuration enables version 2 authentication to the Object Storage service. By default Nextcloud uses version 4 authentication that is compatible with Linode Object Storage. Do not enable this configuration.
        Access Key The value of the Access Key you created using the Linode Cloud Manager.
        Secret Key The value of the Secret Key you created using the Linode Cloud Manager.



        Linode Object Storage Region and Hostname Values

        Region Region ID Hostname
        Newark, NJ, USA us-east-1 us-east-1.linodeobjects.com
        Frankfurt, Germany eu-central-1 eu-central-1.linodeobjects.com
        Singapore, Singapore ap-south-1 ap-south-1.linodeobjects.com
      7. In the Available for text entry box, enter the group name(s) you would like to give access to the Linode Object Storage external storage. To learn more about user and group permissions related to external storage, see Nextcloud’s documentation.

      8. Click the check icon to save the configurations. If all your configurations are valid, you should see a green check box appear next to the external storage entry.

        Save your external storage configurations.

      9. Using the top navigation menu, click the Files menu item. The external storage folder appears in the list of folders.

        Access all your Nextcloud files.

      10. Click the external storage folder to view its contents. You should not see anything stored there yet.

      11. Test out the external storage mount by adding a file to the folder. Click the + button in the top breadcrumbs area of the screen and select Upload file.

        Upload a file to your Linode Object Storage bucket.

      12. The local file browser appears. Select a test file to add to the external storage folder and click Open. The file appears in the folder.

        Your should see your uploaded file appear in the folder.

        Note

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      This guide is published under a CC BY-ND 4.0 license.



      Source link