Monday, September 15, 2014

Why Must I Be A Programmer in Love (with Inheritance)?


Why do I hate code inheritance so much? Possibly because no matter how much I pretend to hate it, it still seems to be my first instinct for extending class behavior. Which only makes me hate it more. Or at least pretend to.

Tonight's case in point comes from an unlikely source: the Karma configuration for one of the chapter projects in Patterns in Polymer. I am (slowly) working through each chapter standardizing on the dependencies and generated structure provided by eee-polmer-tests. One of the peer dependencies of eee-polymer-tests is Karma and eee-polymer-tests is kind enough to include a file with common configuration options.

I use those common configuration options in each Polymer project with a karma.conf.js that looks like:
module.exports = function(config) {
  var common = require('./node_modules/eee-polymer-tests/karma-common.conf.js');

  config.set(common.mixin_common_opts(config, {
    // Override common settings here...
  }));
};
OK, this is not classical class inheritance. This is typical JavaScript prototypical inheritance. My problem remains the same. I see a problem and I want to solve it by putting junk in the object doing the extending. Worse, once I start down that road, I begin inventing ways to make the inheritance smart.

While converting some old tests over to this new approach, I realized that I was missing two things: the html2js Karma preprocessor and the inclusion of HTML fixtures in the configuration. The fix is simple enough:
module.exports = function(config) {
  var common = require('./node_modules/eee-polymer-tests/karma-common.conf.js');

  config.set(common.mixin_common_opts(config, {
    // Override common settings here...
    preprocessors: {
      'test/*.html': 'html2js'
    },

    files: [
      'test/PolymerSetup.js',
      {pattern: 'elements/**', included: false, served: true},
      {pattern: 'bower_components/**', included: false, served: true},
      'test/**/*Spec.js',
      'test/*.html'
    ]

  }));
};
I have added the html2js preprocessor (I am also required to npm install karma-html2js-preprocessor --save-dev). I have copied the list of files from eee-polymer-test's common Karma configuration and added the test/*.html fixtures to the list.

And this is enough to trigger my Pavlovian inheritance response: “I should add preprocessors by default, I should change the mixin_common_opts() so that I can add the one entry to the list rather than copying and pasting, I should support special attribute that are added to existing values instead of overwriting them.”

Maybe this is why inheritance is so insidious. Because each of those things is small enough that they make sense. I would not be violating YAGNI—I would use them immediately. Each would legitimately solve a problem for me. So why not just give in? Why not just implement the configuration like this and be done with it?

There are at least two reasons. The first is a nagging sense that I would be in violation of POLS—that I (or someone else using this code) would find the inheritance confusing or non-obvious. The second reason is that I am jumping to implementation without really considering the problem.

And here's the problem. Here's my dirty little secret. I don't use fixtures in my Polymer testing. In my very first Polymer tests, I used them mostly as I was trying to understand how best to approach testing. The Polymer fixtures worked, but since then I have mostly dynamically created the elements right in my tests. So maybe this is a case of YAGNI after all. But it's not that I don't need the code—this is a situation where I don't need the solution.

As a nod to my struggles, I will likely add the list of files from the common configuration into the generated karma.conf.js as a comment. That way, if I do run into this again, I will have all of the information that I need right in the configuration file.

In the end, I nearly gave into my seemingly natural reflex to add some form of inheritance to everything. Thankfully, I was able to listen to my better nature. Maybe someday that will be my first instinct.


Day #184

No comments:

Post a Comment