Immutability is not enough (2016)
This is a common misconception, functional code is order independent in its evaluation model, but if you are modeling order dependent operations, it still lets you specify order for them, and if you specify the wrong order for what you&#x27;re doing it&#x27;ll do the wrong thing.<p>So you can think of it as it solves accidental complexity, but leaves essential complexity still for you to solve.<p>A very simple example is:<p><pre><code>    30 - 2 * 10
</code></pre>
This is order dependent, but it&#x27;s part of the essential complexity of the problem at hand.<p>Now where accidental complexity would creep in is with something like:<p><pre><code>    position - 2 * position + 10
</code></pre>
Now first we have the essential complexity, what order is the behavior we want? Let&#x27;s say here we want:<p><pre><code>    (position - 2) * (position + 10)
</code></pre>
In imperative we might do:<p><pre><code>    position = 10
    position.minus(2)
    position.plus(10)
    position.times(position.value)
</code></pre>
And hopefully you&#x27;re already seeing the accidental complexity created by the imperative approach. This doesn&#x27;t work, and makes no sense. It isn&#x27;t just that the order of the operations we&#x27;re modeling is defined wrongly, in fact you could say it&#x27;s defined correctly, we want to substract, add and then multiply. But in this case it&#x27;s the mutable state itself which makes things more complex then they need to be.<p>So in imperative you&#x27;d have to do:<p><pre><code>    position = 10
    firstPosition = position.value
    secondPosition = position.value
    firstPosition.minus(2)
    secondPosition.plus(10)
    position = firstPosition.times(secondPosition)
    position.value
</code></pre>
That&#x27;s a lot of added complexity due to us having to manage the fact that the state is mutable. We need three memory locations, we need to make sure that we copy the state values at the right times and we need to make sure we are mutating the right memory locations and than adding them back and all that ourselves.<p>In functional you&#x27;d just do:<p><pre><code>    position = 10
    times(minus(position, 2)
          plus(position, 10))
</code></pre>
All you need to model is just the essential ordering inherent to the behavior you want.<p>Not surprisingly, most modern programming language actually use pure functions for their math operations. That&#x27;s why in Java:<p><pre><code>    int position = 10;
    (position - 2) * (position + 10)
</code></pre>
will work, because minus, plus and multiply are implemented as pure functions, even in Java. That said, if you use the imperative ones instead it won&#x27;t work:<p><pre><code>    int position = 10;
    (position -= 2) * (position += 10)
</code></pre>
or if you went all imperative you&#x27;d have what I showed before:<p><pre><code>    int position = 10;
    position -= 2;
    position += 10;
    position *= position;
</code></pre>
Now using math operations I think shows very clearly the accidental complexity that imperative has over functional in this case. What happens is all your other operations that are not math, but related to your business logic or program logic that you also model using the imperative style suffers from this added complexity which is removed if you move to the functional style.<p>Now back to the article, they&#x27;re expecting functional programming to somehow know the behavior they want, and magically figure out the essential complexity of it. It won&#x27;t give you that, but it will get rid of a large amount of accidental complexity, and that was the point of the &quot;No Silver Bullet&quot; paper, that since the amount of essential complexity is fixed and inherent to your problem, only accidental complexity can be simplified when implementing said problem. Functional programming argues to dramatically simplify your accidental complexity, letting you focus all your attention on the essential parts.<p>Having said that, there are things that tries to tame essential complexity as well and functional programming tends to mix with them very simply and easily. For example, the ideas around declarative programming, metaprogramming, interactive programming, static code analysis, and testable code all touch on the essential complexity parts of a problem.<p>If you have more independently reusable pieces, that you can simply declare compositions of, or rules around them, it allows you to tackle some aspects of essential complexity. Metaprogramming lets you abstract things behind code-gen so you can more quickly reuse parts of each essential features that is the same. Interactive programming (like a REPL in Lisps or smalltalk systems) will let you have a quicker feedback loop to evaluate the effect of your essential problem and validate if it&#x27;s correct letting you more quickly implement the essential complexity. Static code analysis can validate assertions of your essential complexity and quickly tell you if you might have made a mistake in it, it can also help you see a clearer mental map of how the essential complexity is modeled which can help you understand it better. Finally testable code, which functional code often is by virtue of its style, similarly lets you assess the validity of your essential behavior, and thus you can more quickly iterate over your essential complexity.