Why bother using Polymorphism?
Tags: oop
Published: 2020-09-07 10:37:28

There are a lot of articles out there that try to explain what is polymorphism. Basically, it is one of OOP pillar that every programmer should know and respect.

This article is an attempt to explain why.

--------------------------------

Let say you have a system with a user registration feature. The stakeholder said that the system must

1. Validate the user information. Show the error page if the user inputs any invalid data.
2. Save the user avatar
3. Save the user information
4. Response to the user

The most straightforward code that reflects the requirement will look like this

```csharp
class User {
  public User Register(string name, string password, stream avatar) {
    // Validate
    var user = new User(name, password);
    if (!user.valid()) throw new InvalidUserException();

    // Uploading
    var avatarPath = Uploader.upload(avatar);
    user.avatarPath = avatarPath;

    // Save
    user.save();

    // Return response
    return user;
  }
}
```

As you can see, the flow of this code reflect the requirement from business stakeholder.

-------------------------------------

Ok. So what happened if there is an infrastructure requirement. We hate vendor lock-in. We want to be able to switch between two image storage types, Google Storage and Amazon S3? 

Let me take another naive approach. We create an uploader class that can upload to each type of storage.

```csharp
class User {
  public User Register(string name, string password, stream avatar) {
    // Validate
    var user = new User(name, password);
    if (!user.valid()) throw new InvalidUserException();

    // Upload
    String avatarPath = "";
    if (Environment.get("STORAGE") == "S3") {
      // Setup S3 Uploader
      // Setup credentials
      // Setup some more
      avatarPath = Uploader.uploadS3(avatar);
    } else {
      // Setup Google Uploader
      // Setup credentials
      // Setup some more
      avatarPath = Uploader.uploadGoogleCloud(avatar);
    }

    user.avatarPath = avatarPath;

    // Save
    user.save();
    return user;
  }
}
```

But then, this code does not fully reflect the business requirement anymore. The infrastructure related concern is embedded in this chunk of code. There is a credential setup that different for each storage provider. There is a connectivity setup different for each storage provider. And so-on.

Now, any developer who wants to work with this method must understand the system's infrastructure to some degree.

That seems complicated and time-consuming. What if we want to allow developers to work with this chunk of code without understanding those infrastructure details?

We can do this.

```csharp
// Different uploader
interface IUploader {
   public string Upload(Stream fileContent);
}
class S3Uploader: IUploader {
  public string Upload(Stream fileContent) { // Something }
}
class GoogleCloudUploader: IUploader {
  public string Upload(Stream fileContent) { // Something }
}

// Factory. Create uploader according to environment
class Uploader {
  public static IUploader CreateUploaderByEnvironment() {
    if (Environment.get("STORAGE") == "S3") {
      var result = new S3Uploader();
      // Setup S3 Uploader
      // Setup credentials
      // Setup some more
      return result;
    } else {
      var result = new GoogleCloudUploader();
      // Setup Google Uploader
      // Setup credentials
      // Setup some more
      return result;
    }

  }
}
```

And by having these Uploader classes with the same interface, we can change a code in the User class to be

```csharp
class User {
  public User Register(string name, string password, stream avatar) {
    // Validate
    var user = new User(name, password);
    if (!user.valid()) throw new InvalidUserException();

    // Uploading
    var avatarPath = Uploader.CreateByEnvironment().upload(avatar);
    user.avatarPath = avatarPath;

    // Save
    user.save();
    return user;
  }
}
```
And now, this code reflects business requirements again. 

Developers who don't understand the infrastructure detail can work and modify the code without breaking the infrastructure requirement, as long as they still use `Uploader.CreateByEnvironment()`.

Let take a look at what we did.

1. We made interchangeable uploader classes, S3Uploader and GoogleCloudUploader. Both adhere to the same interface. This practice is called Polymorphism.
2. We created a method that will choose a class implementation according to the environment. We called this a factory pattern.

Using these practices, we create a code that swiftly reflects the business requirement inside the User class while hiding an infrastructure requirement in another class.

------------------

Polymorphism allow use to hide some detail and highlight some detail.

For example, in this scenario, in a procedural programming paradigm without Polymorphism, we cannot make a code that swiftly reflects the business requirement.

This technique ultimately allows you to organize your codebase in different ways.

If we look at programming industry history, Polymorphism was promoted in the day where we still design a bunch of classes from the requirement and hand each class with specs over to a big group of programmers to work on, without knowing what how the overall system going is.

And as you can see, how can we make a developer working on the user registration feature without knowing the infrastructure detail in the example above. You can see that this is a perfect tool for this job.

---------------------------

I don't do Polymorphism just for the sake of becoming "a professional developer who deeply understands and respects Object-oriented design". 

That has no meaning or value in itself. 

And so should you. You should not do Polymorphism just because everyone said so or padding in the resume.

Why do I care about OOP, especially Polymorphism? 

Because I know that when I do it right, these things will happen:

From business perspective, I can hide infrastructure detail.

From infrastructure perspective, I can hide business detail.

I can take a notebook to the meeting room with the business stakeholders and listen to what they are talking about. My code and the diagram they display on the Powerpoint presentation will look exactly the same.

I can take a notebook to the meeting room with the infrastructure team. Open another file. And the diagram on the wall will match my code perfectly.

It will be just a different file and a different class.

I can use my code as a source of truth to discuss everything with every related party and department. I don't need any extra documentation to discuss with different teams.

Many programmers hate having a conversation with the user because it feels like they do not understand the system. They talk in different languages, use other terms, and have different wavelengths to programmers who actually work on the codebase.

But what if I say that you can make codebase reflect user thought

With a clean codebase that reflects how user think system work (with some detail hiding in the lower level), you allow programmers and users to speak in the same wavelength with the same understanding. 

Programmers will enjoy conversation with the user more and more. 

Believe me. I did.

And this is the end game of Polymorphism done right.