Take the following JavaScript module as an example of a utility class helper file that exposes many related utility functions.

This module initializes the state of module and the exported functions reference that state via closures.

const state = getState()

export function methodOne() {
  // do stuff with state
}

// more functions that rely on state

We can test these functions by mocking what getState(), etc.

In this case, from a testability perspective, it seems like it might be worth creating a stateful class that takes a state. In this way, it becomes easier to test, less reliant on how getState() works, more portable, etc.

class A {
  constructor(state) {
    this.state = state
  }

  methodOne() {
    // do stuff with this.state
  }

  // more methods that rely on this.state
}

export default A

In moving the methods to a class it becomes much more testable, explicit, declarative, etc.

However, now we have the performance overhead of exporting the full class and not being able to reference a single instance of state as well as needing to new up the class in each importing file unless we opted for static methods, but it definitely will result in more code required to use the utility functions. Also, at least in the JavaScript ecosphere, we can take advantage of bundle performance optimizations such as tree shaking, etc.

Is it worth going for the class option just for testability, portability, etc. purposes? Or is it just wasteful as it is less performant.

I'm worried that I'm trying to make something into a class just for testability purposes, but possibly causing excess code, performance degradation, etc. On the other hand the class approach is more testable, declarative, and portable.

How should I handle these trade-offs? What is the better approach? What is the lesson here?

  • 3
    Are any of your worries backed up by hard performance requirements and measurements that say you won't meet them? – Blrfl Nov 19 at 18:15
  • @Blrfl good question, no performance requirements specifically laid out but we strive to optimize our performance where we can. I suppose a large problem is that I don't have any quantification between the performance differential between the two approaches. – Adam Thompson Nov 19 at 18:31
  • 3
    "optimize our performance where we can" without measurements is pretty much the definition of premature optimization. I'd also have a look at JavaScript: The Good Parts for some tips about classes in modern JS. – l0b0 Nov 19 at 20:54
  • 1
    Yes. As an aside, I don't think I've ever been in a situation where TDD led to bad performance. Properly test driven code ends up being easy to understand, and is therefore easy to modify to fit any performance requirements. – l0b0 Nov 19 at 21:49
  • 2
    If speed is so important that a single object instantiation is a problem you might need to rethink the approach. Maybe rewriting in a lower level language like Rust, Go, C or even assembly. Also, I'd reiterate that I've found that TDD leads to good performance, because the resulting design ends up being the simplest I could have come up with. – l0b0 Nov 19 at 22:11

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.