1. 5

  2. 6

    Try to reduce intermodule dependencies

    Very common advice…. very rare to find practical suggestions on how to do that.

    Recently it occurred to me that a very simple refactoring achieves this.

    Where possible and where appropriate, favour passing in parameters or returning values over invoking functions.

    ie. Rather than invoke a function in a different module to get a value, design your API so the client passes in that value as a parameter.

    ie. Rather than invoke a function in a different module to handle the result (eg. output, store, persist…), design your API to either return the result or return it as an out parameter.

    The effect of this….

    • Decreases coupling between modules.
    • Makes your functions easier to test and reuse.
    • Makes your designs less stiff and fragile to change (less brittle).

    The side effect of this is…

    • it pushes your coupling higher up the call graph,
    • you may end up with, hopefully tiny modules, that are “all coupling and no content”.
    • you will end up with longer parameter lists.
    • you may end up with duplicated snippets of code where clients invoke the same sequence of functions and pass them as parameters to your functions.

    This is not in fact a problem.

    For soon you will observe that the preconditions on some of your parameters share common subexpressions between functions.

    This is a classic signal that a group of parameters are not Plain Old Data, but an object.

    So refactor to clump that group of parameters into an object.

    Another way of expressing this is “Favour Parameter Binding over Assignment”.

    1. 2

      Feels quite a lot like purity. When people start complaining about having to pass so many arguments… Then you can look into the reader monad.