Skip to content

Instantly share code, notes, and snippets.

@kevroletin
Last active April 16, 2018 04:14
Show Gist options
  • Save kevroletin/49699eca01e5719da79ba038a1489066 to your computer and use it in GitHub Desktop.
Save kevroletin/49699eca01e5719da79ba038a1489066 to your computer and use it in GitHub Desktop.
My current thought about extensible abstractions

Problems

  1. Runtime configuration

    Example: web services which read database configuration from config.yaml.

    An application reads configurations and chooses between different subsystem implementations.

  2. Write your own implementation of a concept from 3rd party library

    Example: graphical toolkits.

    We want our users to be able to extend framework/library functionality without modifying framework/library code. For example, in graphical toolkits, it is possible (and even desirable) to implement your own widgets.

  3. Extend existing implementation

    Example: graphical toolkits.

    Extend existing implementation by configuring/overriding some aspects of its behavior.

  4. Dependency injection.

    Example: mocking for testing.

  5. Separation of concerns

OOP

  1. Runtime configuration

    Here we just declare an interface and take advantage of dynamic methods dispatch:

      interface Database {
          public <User> fetchAllUsers();
          public void   deleteUser(User);
      }
      
       class PostgresDatabase implements Database { ...
       
       class MysqlDatabase implements Database { ...
       
       ...
       
       if (config.database.url.contains("postgres")) {
           return new PostgresDatabase(config.database);
       }
       else if (config.database.url.contains("mysql")) {
           return new MysqlDatabase(config.database);
       } else {
           ...
    
  2. Write your own implementation of a concept from 3rd party library

    Aka "Implement this interface" frameworks.

    Basically the same idea as in the previous point. Framework declared common interface and users are able to extend this interface.

  3. Extend existing implementation

    Aka "Fill the gap by overriding this virtual method" approach.

    The cool thing here is that extension happens at compile time.

  4. Dependency injection

    The object receives all its dependencies in the constructor and works with them via interfaces. That way it is easy to mock dependencies for testing.

  5. Separation of concerns

    We usually implement different subsystems or different scenarios as objects. The rule of thumb is "the object should do a single thing and do it well". There are OOP patterns which help to organize interaction between an object in such a way that the rule of thumb works. Then we combine solution by calling object methods.

FP

First of all, OOP can be implemented in Haskell and there are several approaches which implement the different amount of concepts from OOP. I didn't read all of them because I want to concentrate on alternatives to OOP.

  1. Runtime configuration
  2. Write your own implementation of a concept from 3rd party library
  3. Extend existing implementation
  4. Dependency injection.
  5. Separation of concerns
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment