Functions that ask for more than they need trick the developer into writing unnecessary code. At best, this slows down future development; at worst, it harms runtime qualities: of the present system.
Imagine that you inherited this code:
const post = await api.fetchPostById('abc123')
// => {
// id: 'abc123',
// title: 'The dangers of greedy functions',
// authorName: 'Max'
// }
const postUrl = getPublishedUrl(post)
One day, the back-end team changes the API so that author data is exposed through a separate endpoint. Your IDE tells you that getPublishedUrl
needs an argument of type { id: string, title: string, authorName: string }
, so you make the necessary changes:
const post = await api.fetchPostById('abc123')
const author = await api.fetchAuthorByPostId(post.id)
const postUrl = getPublishedUrl({
...post,
authorName: author.name,
})
Tests succeed, production works, all is good.
Some time later, you look into a file called post‑utils.ts
:
type Post = {
id: string
title: string
authorName: string
}
function getPublishedUrl(post: Post): string {
return '/posts/' + post.id
}
It turns out that getPublishedUrl
didn’t need author data at all.
And yet, it led you into adding complexity, and even causing some performance degradation (an extra network request).
Surely you could have peeked at getPublishedUrl
implementation sooner?
For every getPublishedUrl
in a contrived example, dozens exist in a real code base. But impracticality aside: why establish contracts, if you’re required to look at implementations? Function signatures and object interfaces are there to save you that work. If you still have to do it, they’re not doing their job right.
In fact, the real problem (at least at the program level) is that getPublishedUrl
is lying. This:
function getPublishedUrl(post: Post): string
Says: My name is getPublishedUrl
and, to do my job, I need a post (i.e. a map of id, title, and authorName)." A greedy lie.
The solution (again, at least at the program level) is for functions to only ask for what they really need:
function getPublishedUrl(postId: string): string
(Unless they really need 90% or so of a large, complex type, in which case there’s little point in leaving out the 10%.)
It’s harder to pinpoint the problem at the programmer level, i.e. what led someone to choose to write that code. Most likely it was a well-intentioned quest for simplicity and readability. Unfortunately, simplicity that isn’t backed by truth looks the part, and quietly invites its opposite.