Refactoring: Further discussions on DI

I received an interesting question about “Refactoring: TF is Dependency Inversion”, which sparked a conversation that I thought to share that as an article with some paraphrasing to focus on relevant context.

TL;DR;

The conversation was about how to tell where DI is necessary, and we touched on topics like Side Effects and Function Predictability.

So here you said their dependency on other modules should be greatly minimized, how about in situations where you need to break them down into sub modules.

Especially when they’re getting bogus and you need to break them into pieces, like let’s say 2–4, you’ll have to import the sub modules in the main one.

Is that like bad cos’ it’s dependent on them?

Me

Ooh that’s an interesting question!

One goal of dependency inversion is to reduce side effects. And side effects are caused by a Function doing something that is unpredictable, usually by referencing something external to your system.

So if a Function depends on other Function, but neither of them cause side effects, they do not need their dependency relationship, inverted. E.g.

const pi = () => Math.PI;
const areaOfCircle = (radius) => pi() * radius * radius;

We can afford to not abstract pi(), because it is a predictable function. It will always return 3.142, so it causes no side effects.

At no point, will the value of pi() change in the future.

However,

const tomorrow = () => new Date(
Date.now() + 24 * 60 * 60 * 1000
);

Here, the value of Date.now() changes every millisecond, so it definitely causes a side effect cos we cannot predict its value. This function cannot be used in a test as is, cos well, its value cannot be predicted.

So we need to make tomorrow predictable, by abstracting its dependency on the System’s DateTime.

So I would refactortomorrowas:

const tomorrow = ({ now = () => Date.now() } = {}) => new Date(
now() + 24 * 60 * 60 * 1000
);

We’ve made now() into a dependency of tomorrow()and we can pass a predictable value for now()during tests. e.g.

tomorrow({ 
now: () => new Date("2022-01-01")
})

This function is now predictable and causes no side effects.

Function Predictability means that we can accurately tell what a function will return, given a set of arguments. It is popularly known as Function Determinism.

@thatdeji

Okay, so the tomorrow function return value won’t change as long as the now() function is made predictable, because that changing part has been abstracted.

Me

Yes, that is it.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Ikechi Michael

Ikechi Michael

I’ve learned I don’t know anything. I've also learned that people will pay for what I know. Maybe that's why they never pay.