At what point is having a static class with utility methods better than having an injectable service?

by Joshua Schroijen   Last Updated May 15, 2019 15:05 PM - source

I have a pretty general question about the design of Angular web applications. I'm a big fan of writing services. Sometimes I write services that have only utility methods that don't require state at all (think mathematical functions and the like). I feel that even in that case writing injectable services for the utility functions makes sense, since in that case you could swap different varieties of the service easily if you want to change the behavior of your application without having to delete old code inside of your static class.

To give an example: let's say we have a service that computes distances between points. You could just create that service as a plain old class with static methods to do it. But there are numerous ways to compute the distances between points. One might use the simple Euclidean formula, the somewhat more complex Haversine formula etc.

Suppose you'd want to pick the way to do it dynamically so users can choose the desired accuracy/complexity tradeoff. That's going to be a lot of spaghetti if you use a simple static class. On the other hand, it becomes rather simple if you have injectable distance services with a common base class/interface. This is a huge advantage and having state or not is irrelevant.

But still, in the context of web development with Angular this advantage might be tiny for some scenarios, even though it is good design. I was wondering if there is a certain point at which stateless services become so simple that the increase in bundle size or the decrease in (client-side) performance really begins to warrant just turning the service into a simple static class.

Answers 1

Performance is not the issue here. The real issue comes in when resolving the dependencies for the code using the "static" class (btw, a class is a Function object in JavaScript or just an object literal that can still be passed around like any other value).

If the "static" class is being pulled in to the page asynchronously using something like require.js then you have a race condition between the browser downloading the source code for the static class, and the code using the static class. Depending on who wins, you might get a JavaScript error.

For instance if you attempt to call a method on the static class while that JavaScript file is still being downloaded then you will get an error, because that object/class has not been defined yet in the lifecycle of the web page and web application.

Sticking with services in Angular allows the framework to load dependencies however it sees fit to ensure your code executes only when all of its dependencies have been downloaded, initialized and resolved.

I'm sure you don't need to do this. You can simply import the static class as a JavaScript file as a regular <script> tag, so that symbol is defined before Angular even comes into the picture, but that will increase the initial payload the browser must download before the page becomes something a user can interact with — and with enough of these kinds of files performance could start becoming an issue.

Greg Burghardt
Greg Burghardt
May 15, 2019 14:51 PM

Related Questions

Angular Injecting a State/Context Snapshot

Updated November 21, 2018 00:05 AM

How to implement a dependency mocking library for JS

Updated October 25, 2017 21:05 PM

open webapplication from desktop application

Updated August 09, 2017 11:05 AM

MEAN stack for Dashboard project

Updated February 02, 2019 14:05 PM