《Out of Tar Pit》总结
Complexity,Conformity, Changeability Invisibility
¡°I conclude that there are two ways of constructing a softwaredesign: One way is to make it so simple that there are obviouslyno deficiencies and the other way is to make it so complicatedthat there are no obvious deficiencies. The first method is farmore difficult.
Simplicity is Hard
Approaches to Understanding
There are two widely-used approaches to understandingsystems (or components of systems):
This is attempting to understand a system from the outside ¡ª asa ¡°black box¡±.
This is attempting to understand the system by examiningit from the inside
The hope is that by using the extra informationavailable, a more accurate understanding can be gained
problem of test
The other justification is that improvements in informal reasoning will lead to less errors being created whilst all that improvements in testing can do is to lead to more errors being detected
This is not to say that testing has no use. The bottom line is that allways of attempting to understand a system have their limitations
It is precisely because of the limitations of all these approaches thatsimplicity is vital
Causes of Complexity
Complexity caused by State
reboot your computer!
The reason that they are often successful in resolving the problem isthat many systems have errors in their handling of state
Impact of State on Testing
Impact of State on Informal Reasoning
As a result of all the above reasons it is our belief that the single biggestremaining cause of complexity in most contemporary large systems is state,and the more we can do to limit and manage state, the better
Complexity caused by Control
Control is basically about the order in which things happen
Complexity caused by Code Volume
Other causes of complexity
Finally there are other causes, for example:
code which is never actually used (¡°dead code¡±)
All of these other causes come down to the following three (inter-related)principles:
Complexity breeds complexity
Simplicity is Hard
Classical approaches to managing complexity
object is seen asconsisting of some state together with a set of procedures for accessing andmanipulating that state
This is essentially similar to the (earlier) idea of an abstract data type(ADT) and is one of the primary strengths of the OOP approach whencompared with less structured imperative styles
One problem with this is that, if several of the access procedures accessor manipulate the same bit of state, then there may be several placeswhere a given constraint must be enforced (these different access proceduresmay or may not be within the same file depending on the specific languageand whether features, such as inheritance, are in use).
Another major problemis that encapsulation-based integrity constraint enforcement is stronglybiased toward single-object constraints and it is awkward to enforce morecomplicated constraints involving multiple objects with this approach (forone thing it becomes unclear where such multiple-object constraints shouldreside).
Identity and State
Most OOP languages offer standard sequential control flow, and many offerexplicit classical ¡°shared-state concurrency¡± mechanisms together with allthe standard complexity problems that these can cause.
One slight variationis that actor-style languages use the ¡°message-passing¡± model of concurrency
Conventional imperative and object-oriented programs suffer greatly fromboth state-derived and control-derived complexity
Whilst OOP developed out of a desire to offer improved ways of managingand dealing with the classic stateful von-Neumann architecture, functionalprogramming has its roots in the completely stateless lambda calculus ofChurch (we are ignoring the even simpler functional systems based on combinatorylogic).
The untyped lambda calculus is known to be equivalent in power to the standard stateful abstraction of computation — the Turing machine
Modern functional programming languages are often classified as ‘pure’
which implies that when supplied with a given set of arguments a function will always return exactly the same result
It is this cast iron guarantee of referential transparency that obliterates one of the two crucial weaknesses of testing as discussed above. As a result, even though the other weakness of testing remains (testing for one set of inputs says nothing at all about behaviour with another set of inputs),
By avoiding state functional programming also avoids all of the other state-related weaknesses discussed above, so — for example — informal reasoning also becomes much more effective.
Most functional languages specify implicit (left-to-right) sequencing (of calculation of function arguments) and hence they face many of the same issues mentioned above.
they encourage a more abstract use of control using functionals (such as fold / map) rather than explicit looping.
Kinds of State
In most of this paper when we refer to “state” what we really mean is mutable state
Despite this, the fact is that we are using functional values to simulate state.