dimanche 26 mars 2017

Refactoring legacy mixin-based class hierarchies

I'm currently working on a huge javascript project which has a huge class hierarchy and heavily uses mixins to extend functionality of base classes. Here is an example of how mixin looks like, we're using compose library to create class-like objects:

// Base.js
var Base = compose({
  setX: function (x) {
    this.x = x;
  },

  setY: function (y) {
    this.y = y;
  },

  setPosition: function (x, y) {
    this.setX(x);
    this.setY(y);
  }
})

// SameXAndY.js - mixin
var SameXAndY = compose({
  // Executes after setX in Base.js
  setX: compose.after(function (x) {
    this.y = x;
  }),

  // Executes after setY in Base.js
  setY: compose.after(function (y) {
    this.x = y;
  }),

  // Overrides setPosition in Base.js
  setPosition: compose.around(function (base) {
    return function (x, y) {
      if (x !== y) {
        throw 'x !== y';
      }
      return base.call(this, x, y);
    }
  })
})

We have the following problems with this solution:

  • Mixins heavily depend on each other - you can break something by changing mixins' order in base classes.
  • There is no easy way to ensure that you can safely include some mixin in your class, you may need to implement additional methods / include additional mixins into it.
  • Child classes have hundreds of methods because of the various mixins.
  • It's almost impossible to rewrite mixin in Flow or Typescript.

I'm looking for better plugin-like alternatives which allow to gradually refactor all existing mixins. I understand that there is no "easy" answer to my question, but I would really love to hear your thought on this topic. Design pattern names, relevant blog posts, or even links to the source code will be greatly appreciated.

Cheers, Vladimir.

Aucun commentaire:

Enregistrer un commentaire