After a while, by chance, you happen to join an existing edge to a node. That component now has three vertices, and is 50% more likely to be chosen at random than the isolated edges.
There comes a point where you join two non-trivial components, and before long you reach a tipping point. Suddenly nearly every node you choose already belongs to a component, and that component starts vacuuming up everything.
Thus we have the emergence of "The Giant Component". This transition is sharp and well-studied. Whether you think of it as "obvious" depends on how much you study these things. I seem to recall that there is a major result that says that all first-order predicates have these threshold emergence properties, but it's been too long (30 years) since I studied this, and I could be wrong. I may be able to find some references if people really want me to.
According to Robert Sedgewick, this particular problem has no known mathematical solution, and the threshold (for a given N) is only obtained through, e.g. a Monte Carlo simulations where you randomly open sites until the grid percolates (akin to the adding of threads). The whole thing is a good application of the union find algorithm.
The threshhold for N > 2 is about 60%. Not sure how that applies to software complexity, but it's interesting to think about.
Thanks, Coursera!
Just to clarify because one might interpret your statement to mean that percolation problems in general don't have exact formulas for their solution but the "exact formula" section in your link would say otherwise.
For a given first-order sentence s, as n -> infinity, the fraction of models of cardinality n that satisfy s approaches either 0 or 1.
[1] http://researcher.watson.ibm.com/researcher/files/us-fagin/t...
Software complexity strikes me as a graph-coverage problem: given a graph of N vertices and M paths (i.e. software components and dependencies), how many vertices and paths do we need to traverse (i.e. understand) in order to make a change to component X? How does that parameter scale with different forms of graph -- linear, n-ary tree, DAG, cyclic (yikes!)?
Or is there a homomorphism between the two problems?
The problem then is when business logic is encapsulated in the mud.
https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93R%C3%A9nyi_...
When designing something, there are often many choices. If they interact, it quickly becomes intractable. It's tempting to try to keep them in mind, and work out the answer, but with exponentially increasing complexity, your limits are quickly reached (no matter how smart you are). Enhancing your intelligence, e.g. by offloading information onto paper, also has limits.
One solution is the scientific experiment: hold all variables constant, and see the effect of changing just one design choice. Holding them constant means you have made a design choice for that aspect that is almost certainly not optimal.
Ideally, you can do what is suggested in the article - create modules that are largely independent, and experiment within one module in isolation. Because there are fewer variables per module, they are less complex, and it takes fewer experiments to understand how each works.
The deep problem with this is if you don't know what those modules would be - i.e. you don't know which aspects are independent because that's the very thing you're trying to find out! Of course, you can probably have a guess, and certainly use your initial experiments to check those guesses, and maybe with the information gained, improve your guesses.
EDIT a specification is a module, in that it separates out some design choices.
This bit bothered me: "Wikipedia does a great job of explaining it:" then has a quote from an actual source, that happens to be block-quoted on the Wikipedia page. If the part you quote was directly said by Brian Foote and Joseph Yoder, attribute it to them.
It's about the full lifecycle of a typical software product. Particularly "Section 2.3.1: Loss of Architectural Integrity"
> code decay can be thought of as any implementation of functionality that makes the overall comprehension of the system more difficult to attain and increases the efforts required to implement future changes.
.. and makes further decay more likely
Once a system gets to the point where more than (somewhere between 30-50%) is connected together, developers stop caring about keeping it modular, because it's clear to them that their efforts are a waste of energy.
From that point onwards, the project becomes a cesspool of hackery.
Everything else is trying to shoehorn something new into an existing framework, and you don't have enough time to get it 'done properly' because your product manager has a heart attack when you tell them how long it'll take to do a proper refactoring job. This is where you will quite happily cut corners, and the chance that you'll inadvertently break existing functionality in the process increases exponentially. This is the mechanism that, in my experience, causes balls-of-mud.
And of course, no matter how good you are at planning every required use-case of your code over its lifetime at the 'done properly' stage, you can never think of it all, so at some point or another you are forced to shoehorn stuff in everywhere anyway.
I think I have knack for seeing and caring about that. I see complexity arising (even if I can't always prevent it, I mean we have to ship too).
It's also interesting to note that Foote and Yoder's "Big Ball of Mud" paper[1] portrayed the mechanisms for mud-ball formation as a set of anti-patterns. It's an interesting read. Their give some pretty thoughtful explanations for how software transmogrifies into a mud-ball, none of which include random processes.
[1] http://laputan.org/mud (1999)
https://en.wikipedia.org/wiki/Big_ball_of_mud#In_programming...
In any software, everything is going to be connected, otherwise there's unreachable code. So the largest cluster is always 100%, so I don't get why his argument about the sudden phase transition is relevant to software?
Uncle Bob was talking about this in his keynote about how Rails is not your application.
http://confreaks.com/videos/759-rubymidwest2011-keynote-arch...
http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-arch...
For instance, SOA has had a new lease on life lately, for good reasons. I picked up a system that had four layers involved with doing a request; each of these layers had different serialization/deserialization logic (two submodules) and at least one submodule that would actually do the work.
Debugging a problem in the system often involved a wild goose chase across 12 submodules and often changing something simple (like adding a new data field) would require all 12 modules to be changed.
Even if you have a good batting average and you manage to make these changes right 90% of the time it's close to certain that making a change to that system would create a new bug.
The underlying social problem isn't that "people want to do things quickly", it's that people don't see simplicity as a virtue and don't see complexity as a problem. If they valued speed, they'd pursue simplicity because you can make changes much more quickly in a simple system.
IME: Doing N features hackishly takes O(n^2) time; Doing them properly takes O(2n). The problem is when management sees a project as a series of several n=1 tasks, instead of one n=n project.
So I see your point. Thanks for elucidating.
> somth
What?