Live data from Hacker News

Avoid Indirection in Code

matthewrocklin.com

131–140 of 220 posts

Re: Avoid Indirection in Code

#131
post #100

Ok, to take a real world example instead: if (url.startsWith('http://')) { vs. if (isAbsoluteUrl(url)) { If the next developer comes by in 2 months to fix the case for https:// urls (and protocol relative ones in 6 months), they'll immediately be able to spot the intention of the code and can easily fix it in the abstraction layer that's already in place. Moreover, the fix will be applied every other place this fault…

Your example works because it avoids duplication a magic string constant. If the string wasn't a constant, but another variable, thw whole argument changes.

My example is literally the real world version of the example in the article, only thing I did was change string values and identifier names. If you say my example works as an abstraction, it means that it successfully refutes the argument that the article tries to make.

Re: Avoid Indirection in Code

#132
This made me think: is there an IDE or plugin that makes it easy to visualize the source code of a function by inlining the sources of the undercalled functions?

For example, before the transformation:

    function isFooLike(x) {
        return x.startsWith("foo");
    }

    function isBarLike(x) {
        return x.startsWith("bar");
    }

    function bigFunction(str) {
        if(isFooLike(str)) {
            console.log("Foo!");
        }
        else if(isBarLike(str)) {
            console.log("Bar!");
        }
        else {
            console.log("Unknown!");
        }
    }
And then:

    function bigFunction(str) {
        if((function(x) {
            return x.startsWith("foo")
        })(str)) {
            console.log("Foo!");
        }
        else if((function(x) {
            return x.startsWith("bar")
        })(str)) {
            console.log("Bar!");
        }
        else {
            console.log("Unknown!");
        }
    }

Re: Avoid Indirection in Code

#133
Both are clearly wrong, should have been using proper IoC with a fooCheckerFactory creating a checking object that inherits from a generic interface that is passed in the context.

Re: Avoid Indirection in Code

#134
One very important reason to avoid this kind of unnecessary indirection is that it wrecks locality of reference for anyone reading it. They end up spending all of their mental energy on skipping around the codebase trying to follow the thread of execution, making it very hard to assemble a coherent picture of what the code's actually trying to do.

Re: Avoid Indirection in Code

#135

This made me think: is there an IDE or plugin that makes it easy to visualize the source code of a function by inlining the sources of the undercalled functions? For example, before the transformation: function isFooLike(x) { return x.startsWith("foo"); } function isBarLike(x) { return x.startsWith("bar"); } function bigFunction(str) { if(isFooLike(str)) { console.log("Foo!"); } else if(isBarLike(str)) { console.log(…

While I find your inlined example very bad to read, I think there are many attemps IDEs do for this. I remember some showing the function stub of a called function when moving the mouse on the call instruction. I also know multiple editors that allow to quickly browse the source code with CTRL+Enter (or CTRL+Mouse click) in a similar fashion as we click on links in the web. I personally never found indirection to be a problem. It's rather the solution.

Re: Avoid Indirection in Code

#136
In theory, this abstraction of small details is not a problem, but in cases like this, I would prefer to see the inlined version, simply because, in many languages, a function call raises the possibility that it has side-effects that you might want to know about. In code that is abstracted to the max, that is sometimes a difficult question to answer, even if your IDE lets you easily trace the call stack as you read.

There is a related problem that causes more trouble, but it cannot really be blamed on the initial abstraction. It goes like this: you have something, such as a foo-ness test, that is needed in several places, so you abstract it as a function for all the right reasons. Later on, one of those uses changes, and needs slightly different logic than the other cases. Instead of writing a new function (that may, as part of its implementation, call the original), the person making this change (not you, of course!) modifies the original function to handle both cases. This, by itself, makes the code more complex than necessary, and it gets worse if the criterion for which path is taken in the function is not something that has any significance for someone who arrived at this function through reading the code for one of the other cases that call it. And if the new path has a side effect, now all the other cases are also calling a function that potentially has side effects...

This is how code rots.

Re: Avoid Indirection in Code

#137
post #134

One very important reason to avoid this kind of unnecessary indirection is that it wrecks locality of reference for anyone reading it. They end up spending all of their mental energy on skipping around the codebase trying to follow the thread of execution, making it very hard to assemble a coherent picture of what the code's actually trying to do.

I like IntelliJ's "Quick Definition" shortcut for this. It allows me to see the definition of a function in a popup window so I can quickly glance at what a certain function does without the full context switch.

Re: Avoid Indirection in Code

#138
post #44

First of all, one of the biggest reasons to do this (and not mentioned) is unit testing. If there's several variations of input, it can simply testing because it's easier to write tests for smaller units of code (fewer or no mocks, and fewer parameters). This alone is probably enough to override any negative, in my opinion. Secondly, and in contrast to the point of the article, it can usually help readability. If you…

I find your example actually being a counter-example. The comment should rather be at the top of the definition/implementation of is_legacy_user, so IDEs and users can read and extract it when neccessary (thinking of Javadoc/Python's docstrings). The obvious advantage is that you want to keep comment and function in sync, and not all the calling points distributed around the code. Also, your example is a counterexample because the function name should be spelling, and a comment like

   /* Checks if Foo */
   is_foo(...)
obviously duplicates the same information.

Re: Avoid Indirection in Code

#139
post #135

This made me think: is there an IDE or plugin that makes it easy to visualize the source code of a function by inlining the sources of the undercalled functions? For example, before the transformation: function isFooLike(x) { return x.startsWith("foo"); } function isBarLike(x) { return x.startsWith("bar"); } function bigFunction(str) { if(isFooLike(str)) { console.log("Foo!"); } else if(isBarLike(str)) { console.log(…

While I find your inlined example very bad to read, I think there are many attemps IDEs do for this. I remember some showing the function stub of a called function when moving the mouse on the call instruction. I also know multiple editors that allow to quickly browse the source code with CTRL+Enter (or CTRL+Mouse click) in a similar fashion as we click on links in the web. I personally never found indirection to be…

Yes unfortunately my example is not very readable, but it was to illustrate the idea of including the sources of the called functions.

Indeed, many IDEs allow you to easily display the source code of one function at a time, by navigating to the sources of the function or by displaying it in a pop-up, but the idea I had in mind is to be able to view the source code of the function with all its dependencies at a glance.

Post reply on HN