Abstraction_in_Software_Engineering

Abstraction Abstracted
Russ Abbott
Department of Computer Science
California State University
Los Angeles, Ca
01-310-202-8035
[email protected]
ABSTRACT
Abstraction generally takes the form of the extraction and
reification of a parameterized common core from some area of
interest. In software, abstraction often goes under the name of
refactoring. Refactoring gives software the elegance prized by
software developers. Refactoring requires constructs (such as
procedures, classes, etc.) that can be used to build abstractions.
Often these are provided by a programming language. Sometimes
they are provided by design patterns. We can teach students how
to understand and use these abstraction-building constructs, and
we can teach students how to recognize some of the situations in
which these constructs are applicable. But refactoring is a skill
that we have not (yet) learned how to automate. Like any other
skill, some people will be better at it than others.
When abstraction—i.e., the thought process often referred to as
analysis—is applied to domains outside software the result is
typically an intellectual or conceptual model. When we as
software developers implement such a conceptual model in
software we are externalizing our thoughts as software.
Confusingly, the conceptual model that some software implements
is often referred to as an abstraction of the software. (It’s also
referred to as a specification.) The sense of this usage is that the
conceptual model captures the essence of the software without
describing the implementation details. This is a somewhat
misleading use of the term abstraction. A conceptual model
abstracts and parameterizes its subject domain. That abstraction
may then be externalized and implemented in software.
When abstraction (as domain analysis) is applied to the domain of
software itself, it results in conceptual models, which when
externalized and implemented (in software) result in constructs,
tools, and frameworks that provide most of the abstractionbuilding constructs used in refactoring.
Confident and definitive as the preceding sounds, we are just
beginning to understand abstraction. This essay is intended to be
exploratory, tentative, and speculative. It raises as many questions
as it answers.
Keywords
Abstraction, refactoring.
1. INTRODUCTION
Liskov and Guttag [Liskov] describe what they claim are two
kinds of abstraction: abstraction by parameterization and
abstraction by specification. Abstraction by parameterization
covers the traditional forms of software abstraction such as
procedural abstraction (procedures, functions, methods, etc.), data
abstraction (data types, classes, etc.), iteration abstraction, and
polymorphic abstraction. Abstraction by parameterization extracts
an essential core of some computational element, usually a
process or structure, and reifies that core as a computational
element of its own. A while-loop construct, for example, extracts
iteration as a computational element and by providing slots into
which a boolean expression and a procedural code segment may
be inserted makes iteration available in a generic form.
I will argue that abstraction by parameterization is the essence of
abstraction in general and that refactoring is how we do
abstraction as parameterization in software. In order to do
abstraction as parameterization constructs must be available for
expressing extracted essences. Programming languages provide
many of those constructs. Software frameworks and libraries
provide others. Programming languages, frameworks, and
libraries are considered useful to the extent that they provide
mechanisms that software developers can use to build
abstractions. These notions are explored further in sections xxx.
According to Liskov and Guttag, “Abstraction by specification
abstracts from the implementation details (how the module is
implemented) to the behavior users can depend on (what the
module does).” The implication of this definition is that one finds
a piece of code, figures out what it does, and then expresses that
understanding as an abstraction. For some code this may actually
happen, but in most cases, the abstraction process goes in the
opposite direction. One knows the behavior one wants before the
code is written; one then writes code that implements that
behavior.1 How does one know what one wants? There is no
single answer to that. But however one develops the idea about
what one wants—e.g., by systems analysis, by fantasizing about a
software system, etc.—what one wants exists as an idea in one’s
mind before it is externalized as software.2 Section yyy discusses
the process whereby one develops an idea about what one wants
and then implements it in software.
An idea certainly is an abstraction. The process of creating in
one’s mind the idea that one wants to have implemented and then
implementing it is an important aspect of software development.
So abstraction has two important and distinct roles to play in
software engineering. Abstraction allows software developers to
write better, i.e., more concise and more elegant software.
1
Of course that description is grossly simplified. Most of the
time, one starts with an idea, codes a version of it, works with
the written code, discovers that it’s not exactly what one wants,
changes one’s idea about what one wants, etc.
2
For a discussion of software as externalized thought, see
[Abbott08].
Abstraction also connects ideas in one’s mind with software that
embodies them.
2. SOFTWARE ELEGANCE
I would guess that most of the participants in this workshop think
of themselves—undoubtedly with justification—as top-notch
abstraction practitioners.3 We are among those whom Kramer [x]
singled out as being
able to produce clear, elegant designs and programs, while
others cannot. Abstraction is suggested as the source for this
phenomenon.
Some software is simply far more elegant and conceptually
inviting than other software; software development is an art. At
least many of the most accomplished practitioners of software
development think so. This sentiment is not new. Knuth’s 1974
Turing Award lecture [Knuth] was entitled “Computer
Programming as an Art” and his still incomplete 7 volume work
on software is called The Art of Computer Programming. In his
Turing Award lecture Knuth described his feelings about
software.
[W]hen we prepare a program, it can be like composing
poetry or music …
The possibility of writing beautiful programs, even in assembly
language, is what got me hooked on programming in the first
place. …
Some programs are elegant, some are exquisite, some are
sparkling. My claim is that it is possible to write grand
programs, noble programs, truly magnificent ones!
As a programmer4 I have my own sense of what I mean by
abstraction and elegance in software. I often use the analogy of
climbing a mountain. To realize that there is an abstraction that
incorporates a number of previously disparate elements as special
cases is like reaching a spot from which one can look out over the
valley below. One now has a better perspective of how things that
were once familiar in detail are related to each other more
abstractly. One also sees that one is not at the top, that there is
another lookout area above. After climbing to that next overview
one has an even clearer perspective. But once one has understood
3
Other than to think itself, I have been unable to find an English
word that refers to the act of creating and manipulating
abstractions—she abstracts very well—or to someone who
abstracts expertly—he’s a superior abstractor.
4
My Ph.D. is in Computer Science, and I am a professor of
Computer Science. But at heart I’m really a programmer. I
fantasize that if I ever retire, I’d adopt an open source system
and spend my time coding—and writing papers about software
and computational thinking.
The position of programmer as a job title is commonly
denigrated as referring to a low level task. I think that’s a
mistake. One of the most important attributes of software is that
it is executable. That’s what keeps software developers at all
levels honest. But creating executable software is at its heart
programming a computer. Consequently, in the remainder of
this paper, I use the word programmer in the broadest sense as
encompassing software engineer, software developer, software
designer, software architect, etc.
the view from that perspective one sees that with a bit more
reorganization, one can reach a higher level view yet. It seems
never to end. At each level one catches glimpses of yet higher
peaks with better views. No matter how God-like one’s view of
the code, there seems to be an even more elegant and more
abstract way of understanding it.
On the other hand, I also find myself getting closer and closer to
the code I write. The analogy I use in describing that experience is
to someone who loves woodworking. After building an initial
serviceable version of an artifact her next step is to make it more
finished by going over it with fine sandpaper. She lovingly takes
time with it until the wood is soft and smooth. As she works the
material, smoothing it, polishing it, and shining it, it begins to
glow with an inner light. One cannot resist running one’s hands
over its subtle surfaces.
With software one takes both journeys simultaneously. As the
code becomes more abstract it also becomes more clarified and its
surface more limpid and elegant. The farther the software allows
you to see as a vehicle for generality and abstraction, the more
one appreciates its detailed beauty, the ingenious simplicity of
each element, the mind-satisfying shape of each line of code, the
clarity of thought revealed by each construct.
One of the earliest proposed “methodologies” for software
development was called “stepwise refinement.” [Wirth x]
Refinement in Wirth’s sense meant decomposition from higher
level constructs into lower level details. That sort of refinement is
not what I find myself doing when I develop software. But if one
understands refinement in its other sense—to polish, to improve,
and to perfect—then for those who appreciate it, software
development is indeed successive (if not necessarily “stepwise”)
refinement.
3. REFACTORING: THE ROYAL ROAD
TO ABSTRACTION
Refactoring is commonly understood as “the process of changing
a software system in such a way that it does not alter the external
behaviour of the code, yet improves its internal structure.”
[Fowler]
Why would anyone ever want to do that? If refactored software
behaves no differently from unfactored software, why bother? The
standard answer appeals to pragmatic benefits: when one later
wants to modify the software the refactored code with its
“improved internal structure” will be easier to understand and less
expensive to fix or extend. I doubt, however, that most expert
programmers would agree that the ultimate measure of software
quality is how easy it is to maintain. Software quality is more than
just ease of maintenance.
Most expert programmers are fanatical about refactoring. Why? In
my view, expert programmers refactor to reveal and express
abstractions—in particular the abstractions that identify and
reflect the essential structure of the software.
Plato spoke of “carving Nature at its joints” (Phaedrus 265d266a). When we refactor software, we don’t so much as carve the
software at its joints as sharpen our understanding of it. What had
seemed somewhat amorphous comes to have bones and other
essential skeletal structures. In other words, abstraction is the
identification or creation of underlying structure. Here’s an
example.
In writing an expression evaluator in Prolog one could write the
following.5
eval(A + B, C) :eval(A, AVal),
eval(B, BVal),
C is AVal + BVal.
eval(A - B, C) :eval(A, AVal),
eval(B, BVal),
C is AVal - BVal.
eval(A * B, C) :eval(A, AVal),
eval(B, BVal),
C is AVal * BVal.
…
But one could also write the following.6
eval(Expr, Result) :Expr =.. [Op | Args],
isArithmeticOp(Op),
map(eval, Args, ArgsVals),
Expr1 =.. [Op | ArgsVals],
Result is Expr1.
Why is this better? It’s certainly simpler; there is far less code.
More importantly, it is more powerful—because it is explicit
about what one does to evaluate an arithmetic expression. One
extracts the arguments, evaluates them, reconstitutes the
expression using the argument values in place of the arguments,
and then performs the expression’s operator on the result.
In being explicit about how to evaluate an arithmetic expression
this refactored version of the code is more powerful. Once one has
an explicit representation of the process required to evaluate an
arithmetic expression, one can apply that process to any arithmetic
expression.
Of course this is not new; it is procedural abstraction, the sort of
abstraction represented by any software subprogram. This
example may seem more elegant because it manipulates symbolic
expressions rather than numbers. But it’s really no different.
The conversion of the first version of the program to the second is
a prototypical example of refactoring. The general process of
evaluating arithmetic expressions has been made explicit and
reified by factoring it out of the original code and expressing it
separately.7
By extracting and reifying the essence of the expression
evaluation process one has gained leverage: a unit of knowledge
has been created and made available for further use. This is not a
minor issue. As discussed below, virtually every word is an
abstraction. When we as human beings create a word for a
concept we have captured and tamed that concept (tamed in the
sense of breaking a horse) at least to the extent that we can refer to
it whenever we choose. So when one factors out and thereby
reifies an aspect of a computation, one not only creates a concept
but also “breaks it to the saddle” so that one can put it to work
elsewhere.
4. CLIMBING THE ABSTRACTION
MOUNTAIN
The example in this section offers a simple illustration of how one
abstraction leads to another. Figures 1 and 2 show standard
versions of depth-first and bread-first search. The idea is that
these searches are methods in a Goal class. A goal (instance of
Goal) is passed the root Node of a tree, which is searched for a
node that satisfies it. The test that determines whether a particular
node satisfies this goal is the following.
this.isSatisfiedBy(node).
The method dfSearch uses recursion to perform a depth-first
search. The method bfSearch uses a frontier list (of Nodes) to
keep track of the nodes at the current and next level to be
examined.
Although it may appear that dfSearch does not keep a list of
nodes to be searched, in fact it does. Its call stack is essentially
such a list. The primary difference between the lists kept by
bfSearch and dfSearch is that the list implicitly embodied in the
call stack is (naturally) treated as a stack whereas the frontier list
maintained explicitly by bfSearch is treated as a queue.
If the implicit list embodied by the depth-first search call stack is
made explicit, the two search approaches can be combined. The
reasoning is as follows. Both searches keep a list of nodes to be
examined. Breadth-first search calls that list a frontier. In depthfirst search the list is implicit. But let’s call it a frontier in any
case. In both searches, nodes are removed from the front of the
frontier. The difference is that in breadth-first search the frontier
is treated as a queue (the list of children is appended to the
frontier) whereas in depth-first search the frontier is treated as a
7
5
6
Prolog programs manipulate tree structures. Thus A + B is the
tree structure with root + and children A and B. The Prolog is
operator evaluates its right hand argument (as long as it is an
arithmetic expression) and unifies the result with its left hand
argument. Thus the first clause (the first four lines) says that to
evaluate the expression A + B one should evaluate the
arguments and then apply the + operator to the results.
The Prolog operator =.. converts between its left hand
argument, which is a tree, and its right hand argument, which is
a list whose first element is the root of the tree, and whose
remainder is the list of children of the root. The Prolog notation
for a list is [Head | Tail].
It is appropriate that the term abstraction should be used for a
process that extracts the essence from something. The Online
Etymological Dictionary [Etymological] offers this entry for
abstract.
1387, from the Latin abstractus “drawn away,” past
participle of abstrahere, from ab(s)- “away” + trahere
“draw.” Meaning “withdrawn or separated from material
objects or practical matters” is from 1557.
The original late fourteenth century sense of abstract was to
draw away from. One still finds that sense in current
dictionaries: to abstract is to extract. By the mid sixteenth
century, a sense evolved that the act of drawing away separated
the essence of something from its material realization.
stack (the list of children is prepended to the frontier). This
realization can be expressed as the code in Figure 3.
various ways. Naturally also the product of abstracting is an
abstraction.
One may justifiable argue that combing breadth-first and depthfirst search in this way does no honor to abstraction. After all,
these two searches have very different qualities. Most notably
depth-first is not complete where as breadth-first is. But Figure 3
makes the two seem like twins, which they aren’t. Nonetheless,
Figure 3 does illustrate two features of refactoring. (a) An implicit
element (the depth-first search list of yet-to-be-examined nodes) is
made explicit. (b) An underlying essential procedural similarity is
highlighted and parameterized.
The conceptualization of abstracting as refactoring into a
framework plus parameters is somewhat different from the
standard understanding—as expressed, for example, in [Kramer].
In that article (and others) abstraction is said to be concerned
“removing detail and [identifying] generalisations or common
features.”
More interesting is the next step. Figure 3 suggests that the key to
search types is how the children of a node are added to the
frontier. Best-first search is different from both breadth-first and
depth-first children in that it maintains the frontier sorted by a
measure of goodness. So to add best-first search to Figure 3 one
would merge (in sort order) the children into the frontier.
But why not abstract out the entire question of how to combine
the children and the frontier? Figure 4 illustrates how that can be
done: pass as a parameter to the search method an object that
represents the search type and let that object decide how to
combine the children and the frontier. This refactoring reifies the
search type itself.
Both steps in this sequence of refactorings show how reifying as a
first class computational element a previously implicit element of
a computation (first a list and then a code segment) often yields a
useful abstraction. This sequence also illustrates how taking an
initial abstraction step sets the stage for more steps as one climbs
the mountain of abstraction.
5. DEFINING ABSTRACTION
The standard understanding of a (formal) parameter in
mathematics and computer science is “a variable that can be
varied or changed.”8 In the following I will extend that notion and
use the term parameter to refer to any “slot” within any structure
that may be filled in multiple ways. I’ll refer to structures that
have such slots as parameterized structures.
It’s striking that there seems to be no standard English word that
refers to the slots in parameterized structures—other than “slot”
itself. Nor does there appear to be a standard English word that
refers to the process of building such structures. Words that come
to mind include structure, pattern and framework. But I know of
no standard English verb that means to create such a thing.
Recently Jeanette Wing [Wing] wrote about what she called
“computational thinking” and argued that computer science has
developed ways of thinking that are valuable beyond their direct
application to computing. This seems to be a good example. We
can and should export the notion of building parameterized
structures.
Before exporting the notion we should name the process first.
Naturally I propose “to abstract:” to identify and characterize
(a) the fundamental organization or structure of an area of interest
along with (b) the slots within that structure that may be filled in
8
This definition is from Eric Weisstein's World of Mathematics
(http://mathworld.wolfram.com/Parameter.html),
accessed
January 13, 2008.
I’d like to explain why I don’t think that adequately conveys the
notion of abstraction as we do it in software development. In
doing so, I hope to elaborate my sense of what it means to
abstract.
 Abstraction is not the removal of detail. I would argue that
abstraction is not the removal of detail but its parameterization.
This becomes clearer when one thinks about abstraction from
the perspective of refactoring. A refactored program is not the
same program with detail removed. It is a reorganization of the
program so that essential structures are made visible—as in an
X-ray in which one sees inside an object and understands its
internal structure, perhaps for the first time.
To make essential structures visible, one highlights them and
brings them to the foreground while putting the non-essential
elements in the background. But the non-essential elements are
not discarded. When one refactors, the connections between the
essential structures and non-essential elements are retained.
Typically those relationships are reflected as a parameterization
of the non-essential elements within the essential structures.
Consider, as a non-software example, the category of human
beings. There are many details—height, blood type, eye color, a
genetic code, etc.—about any particular person whose specific
values are not essential to characterizing her as a human being.
But it makes no sense to talk of human beings who don’t have a
height or a blood type or a genetic code. Those non-essential
values may differ from one human being to another, but they
exist in all human beings. They are parameters in the “human
being” abstraction and not discarded elements. This becomes
clear when we conceptualize abstraction as refactoring.
 Abstraction is not generalization. A standard example of
generalization in software engineering is the relationship
between a class and its super-class: a super-class is a
generalization of its sub-classes. I would argue that it’s not
reasonable to say that a super-class is an abstraction of its subclasses. Abstraction and generalization are two different
concepts.
It’s often the case that a generalization has the same essential
structures is its more specific cases. And generalization may be
a good way to see those essential structures more clearly. But
generalization and abstraction seem (at least to me) to be two
different concepts.
Again, refactoring makes this clear. Refactoring is often used to
create super-classes. When one performs such a refactoring the
step from one or more individual classes to a super-class—
along with the newly declared subclass or subclasses—qualifies
as abstraction because the refactoring has identified an essential
structure that is separated out from the subclass or subclasses.
But again, the subclasses are not discarded. They are
(implicitly) parameterized when the super-class is defined.
In virtually every object-oriented language, every class is
capable of having subclasses created from it. Thus every class,
simply by virtue of its being a class, has (perhaps virtual)
“slots” predefined as available for subclasses. When a superclass is created from an existing class or classes, one is
demonstrating one or more ways in which the new super-class’s
subclass slot(s) may be instantiated.
To say that every class has “slots” for subclasses is not very
different from saying that every class has “slots” for instance
variables or that every subprogram has a “slot” for procedural
code. The class structure by definition has defined within it the
possibility of having subclasses defined. Thus the refactoring
step of creating a super-class from one or more existing classes
is equivalent to the refactoring step of creating a procedure
from one or more code segments. In both cases one is factoring
out an essential structure and identifying how the defined slots
may be filled in a particular case.
New constructs such as a new class or a new procedure are
powerful because they explicitly identify and reify a
(presumably) important structure—along with that structure’s
parameters.
 Abstraction is not the identification of common features. The
fact that the sky and the ink in my pen in my pocket are both
blue doesn’t make the category of blue things an abstraction. It
is sometimes useful to focus on particular attributes. But I
would argue that it’s not reasonable to say that “blue thing” is
an abstraction of either the sky or the ink in my pen. Grouping
elements together just because they have features in common
does not produce abstractions.
 Abstraction is not formal methods. Compare and contrast
with
http://www.stsc.hill.af.mil/crosstalk/2008/01/0801DewarSchon
berg.html. According to Liskov and Guttag, abstraction by
specification “abstracts from the implementation details to the
behavior users can depend on. It isolates modules from one
another’s implementations; we require only that a module’s
implementation supports the behavior being relied on.”
A “worrysome trend” [Dewar],
1. Mathematics requirements in CS programs are shrinking.
2. The development of programming skills in several languages
is giving way to cookbook approaches using large libraries
and special-purpose packages.
“The irresistible beauty of programming consists in the
reduction of complex formal processes to a very small set of
primitive operations. Java, instead of exposing this beauty,
encourages the programmer to approach problem-solving like a
plumber in a hardware store: by rummaging through a
multitude of drawers (i.e. packages) we will end up finding
some gadget (i.e. class) that does roughly what we want. How it
does it is not interesting!”
The opposite of creative abstraction. This is an attempt to
reduce everything to fundamental physics. See [Abbott]
Emergence.
6. IS EVERY CONCEPT AN
ABSTRACTION?
Or does it? When we group elements together because they have
some feature in common why isn’t that an abstraction? Thought is
all about abstractions. Is there a concept that is not an abstraction?
In [Abbott if a tree] I claim that computation is exactly the
externalization of thought—but I don’t attempt to define what I
mean by thought, leaving that as a primitive. I don’t claim to have
a philosophy of thought that I could explain were there more
room in this article. I don’t. (For a review and discussion of
concept see [Margolis].) I would like to assume that we are
similar enough in our subjective experience of thinking that we
have (or can agree to) a mutually consistent sense of what we
mean by a concept. Given that assumption, we can take the notion
of a concept as a starting point.
Is every concept an abstraction? Certainly every concept is a
intentional, i.e., it is about something—real or not real. It’s not
clear to me whether it’s possible to have a thought that is about
itself. (Perhaps that can be a Zen koan: can one think a selfreferential thought? What about the simple case of thought or
concept itself? These seem to be self-referential, but not in a
paradoxical way. What would seem more difficult would be a
thought that referred to nothing other than itself. Concept and
thought refer to the entire class of concepts and thoughts and not
to the thing itself.) But other than that possibility, concepts are
about something other than the concept itself. Does that make
them abstractions? It may make them abstractions in the sense that
a concept typically includes essential (to the thinker) elements of
the concept’s referent—and leaves other aspects open for later
binding. This is true when the concept is both a category (house)
and an individual (my house). This is consistent with the notion of
abstraction discussed above.
Human beings have done quite well as a result of our ability to
conceptualize.
Are we talking about abstraction in thinking or in computing? Are
they different? Fables are abstraction in thinking, but not
computing.
To what extent is the ability to do abstraction comparable to the
general “g” measure of intelligence? That is, we can measure
individual intelligences, and we can find a correlation, which we
refer to as “g.” We can probably measure programming ability in
multiple languages and frameworks. There is also probably a
correlation. It’s unlikely that we can teach that.
7. BUILDING ABSTRACTIONS
REQUIRES STRUCTURING
MECHANISMS
It’s also harder (in some sense) for CS in that if one doesn’t
remember the notation, it starts to look foreign after a while. For
example, here’s a lazy evaluation approach to computing the
primes.
primes = (sieve [2 .. ])
where
sieve (p:xs) = p : sieve [x | x <- xs, (x `mod` p) /= 0]
Uses list comprehension, list construction (:) and lazy evaluation
besides the built-in functions take, mod (used as an operator), and
/=. It also makes use of the ability to define a function on the fly
using where.
fib = 1 : 2 : zipWith (+) fib (tail fib)
Uses zipWith, lazy evaluation, functions a first-class objects (+),
tail, list notation (where : associates to the right), and infinite lists.
8. WE CAN TEACH STRUCTING
MECHANISMS BUT WE CAN’T TEACH
THEIR CREATIVE USE
Can we build development environments that are able to suggest
refactorings? If so, then we can certainly teach abstraction—at
least at that level since we can teach it to computers. But if we
can’t, then why should be assume that we can teach abstraction to
people?
Can that be taught any more than painting or piano playing?
Probably one can teach about abstractions: does it offer
conceptual convenience. It might be useful to attempt to develop
a theory of abstraction qualities similar to a theory of aesthetic
qualities in music, painting, writing.
Those can certainly be taught.
Can’t teach musical genius. Can one even teach a good pianist to
be a good violinist? Or a good jazz pianist to be a good classical
pianist? Or a poet to be an essayist? Is that different from being
good with the abstractions in different languages or frameworks?
To what extent is there are general abstraction skill? And can it be
taught?
9. DESIGN PATTERNS ARE
ABSTRACTIONS
We certainly can “teach” computers to “do” the abstractions that
are built into frameworks, languages, tools, etc. But that doesn’t
mean we can “teach” computers to use them to develop programs.
So even if we can teach people to understand those abstractions,
that doesn’t mean we can teach people how to write elegant code
using them.
What about history? Does that teach modeling?
10. ALL SOFTWARE DEVELOPMENT IS
ABSTRACTION: EVERY CONCEPTUAL
MODEL IS AN ABSTRACTION
Model building is both. Especially when the model is built
explicitly. That's the abstraction. But isn't that just thinking? Isn't
that what most academic disciplines teach in one way or another?
Not the art disciplines. Some of them refine the senses. As a
computer scientist it's hard for me to think of teaching anything
else.
11. PROGRESS IN SOFTWARE (ALONG
ONE AXIS) IS THE IDENTIFICATION AND
IMPLEMENTATION OF INCREASINGLY
POWERFUL ABSTRACTINOS
Do search examples.
How are elegance and abstraction related?
From the website: Teaching Aesthetics to Artists.
Most contemporary art forms already have a body of theory
which for most artists constitutes the intellectual dimension of
their field. This theory is often created by artists themselves, or
by critics working closely with them, and it is ultimately
visionary rather than analytical in nature. It is to be found in the
manifestos, the avant-garde magazines, the interviews with
artists, the reverential accounts by their disciples, that define
the many artistic movements that have dominated our century.
For the most part, this theory is prescriptive; it is concerned
with defining art only in order to advocate a particular kind of
art, and its discussions of aesthetic value, of the social effects of
art, and of such classic issues in aesthetics as the nature of
artistic meaning or the purpose of art, are all loaded to show
that the work of a particular school or artist embodies the
highest or latest development in the art form in question. Of
course this kind of writing can be wonderfully creative and
inspiring, and it naturally excites many artists. But the fact that
“theory” for most student artists means this kind of artistic
advocacy makes it harder to convince them of the value of
aesthetics as most of us understand it—an attempt to analyze
what is actually happening in the creation and appreciation of
art, not to provide a rationalization for the work of a particular
group of artists. The plodding work of analysis cannot compete
with the glamour of “theory” as the term is used in most
contemporary art forms.
Sounds a lot like programming framework and language
manifestos, which also are abstractions. Also like the proponents
of patterns, object-oriented programming, etc.—also abstractions.
All of software development is abstraction.
What is abstraction? Is it a dimension of intelligence?
Gardner’s dimensions of intelligence. Doesn’t mention, for
example, olfactory intelligence or sensory intelligence. How are
skills distinguished from intelligences?
What sort of brain components do we have. (I don’t think we
know.) Even if we did know, there are other integrating functions
that also matter, which we also don’t know about.
Is every word an abstraction? If every word is (approximately) an
abstraction, that’s not what we’re looking for. Even proper nouns
(and definite descriptions) are abstractions since they refer to
individuals/entities who are different (literally and figuratively)
from time to time. So a proper noun is an abstraction for an
individual.
But what we want in software is the ability to create new
abstractions that reflect not coding efficiency but conceptual
economy and efficiency: refactoring and reuse. As computers
become able to deal with more and more domains, more
abstractions will become important in SW-Engr. For example,
what about image abstractions, which I don’t understand. For
example, what about the image transformations that image
manipulation programs perform, such as add what Picasa calls fill
light or increase shadows and highlights in Picasa and layers in
Photoshop. What about removing red-eye or “intelligent
scissors?” Not a deep abstraction but certainly useful. These are
probably not abstractions done elegantly at the software level but
very useful at the user level. And transparency, which wasn’t
available as an abstraction until someone figured out how to
implement it by averaging pixel values. These abstractions are
important because they do a good job of matching our intuitions
and provide good ways of dealing with things in the world. But
are they abstractions in the sense intended by this workshop? Is
any library of concepts abstractions in that sense?
Java generics are an abstraction of specifically typed data
structures. But that’s an example of refactoring. They also don’t
always reduce algorithmic complexity in the sense of making
programs smaller.
In fact, one doesn’t have to use them. Their use—like the use of
types in general—tend to make programs better. But programming
with bits (i.e., in assembly language) and without types will work.
But it puts the burden of understanding the program on the
programmer. It doesn’t externalize all the information in the mind
of the programmer.
We in computer science are always looking for abstractions—and
we have done a very good job of finding lots of powerful ones.
Sometimes abstraction is taken to mean the distinction between a
specification and implementation. The specification is the
abstraction. (Don’t agree.)
Every time a biological organism (or some other device) is
capable of making a distinction it has created an abstraction.
Actually, I don’t think so. Making a distinction—say that changes
behavior—is not the same as an abstraction in that an abstraction
(a concept) implies an idea in the head. So if the thing that makes
the distinction doesn’t have a conscious idea that goes along with
the distinction it isn’t creating an abstraction—or at least not an
explicit abstraction.
But that sort of abstraction is a matter of category rather than a
matter of combining things and categories, which is what the
workshop sense of abstraction is about. What’s the real difference
other than how you got there? Is abstraction more conceptual?
Does it necessarily imply a category that can’t be reached directly
but must be reached by abstracting away from some existing
categories or things?
So teaching frameworks, tools, languages does help in teaching
abstraction since students will use the tools and are forced to think
in terms of the abstractions they embody.
This doesn’t teach people how to be creative in generating
abstractions any more than learning aesthetics or a new style
teaches artists how to be creative in terms of the aesthetic
concepts or style they learn.
Is abstraction for software like beauty in art? Not quite since it is
more functional.
Still, recursion is a powerful programming technique. But the
recursive aspects of it can be factored out into what is known as a
visitor pattern. A visitor pattern is a software structure that
accepts as one of its two inputs a tree and as the other a chunk of
software. The visitor pattern traverses the tree and applies the
processing software to each node. In this way the recursiveness
has been factored out of the processing software — which now
need not worry about anything but the processing steps — and
encoded separately in the visitor pattern. Even more generally a
visitor pattern can be applied to any data structure. It need not be
a tree.
Tree search. (See appendix.)
Is this a good abstraction? I don’t know.
Depth-first and breadth-first have very different properties. Spaceintensive vs. not. Complete vs. not. So is it a good idea to
combine them in a single elegant piece of code. The code
illustrates what’s common about them. It doesn’t illustrate the
significant ways they differ.
12. SOFTWARE IS EXTERNALIZED
THOUGHT, I.E., EXTERNALIZED
MODELS. SO WE SHOULD TEACH
STUDENTS HOW TO CREATE
CONCEPTUAL MODELS AND HOW TO
EXTERNALIZE THEM
This position also argues for teaching computer science students
as many (mental) modeling techniques as we know — including
mathematical techniques. As noted earlier, the point is not to
teach mathematics as mathematics but to teach mathematics as a
language for expressing models. It would be useful to computer
science students to teach them mathematics in this way, i.e., as a
way to model problem domains. In most mathematics courses, the
use of the mathematical tools for modeling purposes tends to be
taught as an afterthought or as an exercise. It would be much more
useful (at least to computer science students and to most nonmathematics students) to teach the subject as modeling tools
rather than as formal mathematics.
It would be even better if the modeling aspect were taught
separately from the solving of the equations. There are many
systems available that can solve equations once they are
generated. It would be useful to teach mathematics to nonmathematicians by using those systems. The goal of the course
would be to teach students how to use a mathematical modeling
language as a way to characterize a problem. Once a problem
were characterized, the tool would use the equations to help one
understand
the
problem
from
various
perspectives.
This would mean, for example, teaching a course in system
dynamics to computer science students rather than teaching a
course in partial differential equations. System dynamics could be
taught much earlier and with far fewer mathematical prerequisites
than today's courses in partial differential equations.
Of course, those students who wanted to know how the system
solved the equations or how to build a system dynamics modeling
system would have to learn the necessary mathematics. But for
most computer science students, it would be quite valuable to
learn how to express relationships in terms of partial differential
equations even if they relied on software to solve or simulate the
effects of those equations. This is analogous to the way we teach
programming languages. We teach all students how to write in a
programming language. Only some students learn how to write
compilers.
I think that if mathematics were taught that way it would in fact
help computer science students learn how to think more
abstractly. Each such mathematical modeling framework would be
another tool they could use to understand a situation from one or
another abstract perspective.
The same argument could be made about many other disciplines.
Most disciplines develop models of their domains. It would be
useful for computer science students to learn as many ways as
possible to conceptualize the world. The challenge then would be
to find ways to make models developed in other disciplines
expressible in an executable form, i.e., as software.
Of course most software does not attempt to model something that
exists in the world prior to the software. Most software is the
development of something new. But consider how our intellectual
abilities work. We evolved the ability to conceptualize the world
presumably because it was a useful survival capability. But once
we developed that ability, we used it to invent new worlds — to
write fiction — as well as to conceptualize the world as it is. The
same is true for software. Most of the software we write involves
developing models of things that don't exist elsewhere. But the
ability to build software that models anything is grounded on the
ability to write software that implements models in general — of
both existing and imaginary elements. So it makes sense to argue
that computer science is the study of building models and that
anything that helps develop that ability will contribute to one's
ability to write better software. Abstraction, then is the factoring
out common elements in model building and understanding those
common elements as conceptualizations on their own.
My department is in the School of Engineering, Computer
Science, and Technology. We recently had a school-wide open
house in which we wore T-shirts that said "Turning dreams into
reality." Although I don't for the most part think of Computer
Science as an engineering discipline, I agree that we have that in
common. We are both creative disciplines in which we create
visions, which we then transform into something that exists in the
material world. (Even software and the cyberspaces that it creates
exist in the material world.)
Engineering is said to be the application of science to practical
ends. If one thinks of engineering as transforming dreams to
reality, it is far more than that. But science is what underlies
engineering. It provides the understanding that allows the
engineer to transform a dream into reality.
Perhaps in the same way, modeling serves as the "science" of
computer science. It's the understanding of models and how
models work that allows software developers to transform their
dreams into software reality.
But is the step of going from the intuitive notion of the size of a
collection to the mathematical notion of number mathematics, or
is mathematics the step of formalizing this new notion of number
and proving theorems about it? In my experience, mathematics
has always been about the latter, i.e., proving theorems about
existing abstractions. The actual process of coming up with the
abstraction about which theorems should be proved is considered
somehow pre-mathematics.
Computer science has been called applied philosophy. It's the only
discipline that has created languages that can both (a) represent
ideas in one's head and (b) produce results in the physical world.
Software is the externalization of thought in a symbolic and
executable form. No other discipline can claim anything like that.
Definition of analysis and model and abstraction.
Interestingly enough, Dictionary.com again comes up with a
relevant definition of analysis.
Analysis: a method of studying the nature of something or of
determining its essential features and their relations: the
grammatical analysis of a sentence.
Model: a simplified representation of a system or phenomenon, as
in the sciences or economics, with any hypotheses required to
describe the system or explain the phenomenon, often
mathematically. (Dictionary.com)
Absraction: philosophy conceptualization: the philosophical
process by which people develop concepts either from experience
or from other concepts. (Encarta.com)
Abstraction: the process of formulating general concepts by
abstracting common properties of instances (Wordnet.edu)
13. REFERENCES
All Internet accesses are as of January 24, 2007.
[2] Abbott, Russ, “If a tree casts a shadow is it telling the time?”
Journal of Unconventional Computation, to appear.
[1] Robert B.K. Dewar and Edmond Schonberg, “Computer
Science Education: Where Are the Software Engineers of
Tomorrow?” Crosstalk: the Journal of Defense Software
Engineering,
January
2008.
http://www.stsc.hill.af.mil/crosstalk/2008/01/0801DewarSch
onberg.html.
[2] Fowler, M., Refactoring: Improving the Design of Existing
Programs, Addison-Wesley, 1999.
Harper, Douglas (ed), Online Etymological Dictionary,
http://www.etymonline.com/index.php
[1] Knuth, Donald E. “Computer programming as an art,.”
Commun. ACM 17:667-73, 1974.
http://fresh.homeunix.net/~luke/misc/knuth-turingaward.pdf.
[2] Kramer, Jeff and Orit Hazzan, “The Role of Abstraction in
Software Engineering,” in Proceeding of the 28th
international conference on software engineering, ACM,
2006, pp 1017 – 1018.
[5] Liskov, Barbara and Guttag, John. Program development in
Java. Addison-Wesley, 2000.
[2] Margolis, Eric and Stephen Laurence, "Concepts", The
Stanford Encyclopedia of Philosophy (Winter 2007 Edition),
Edward
N.
Zalta (ed.),
URL
=
http://plato.stanford.edu/archives/win2007/entries/concepts/.
[2] Wing, Jeanette, “Computational Thinking,” Communications
of the ACM, March 2006, (49, 3) 33-35.
http://www.cs.cmu.edu/afs/cs/usr/wing/www/publications/Wi
ng06.pdf.
[6] Wirth, Niklaus, “Program Development by Stepwise
Refinement,” Communications of the ACM, Vol. 14, No. 4,
April 1971, pp. 221-227.
http://www.cs.unca.edu/~brownsmi/0408_Fall/csci431/resou
rces/generalReference/PgmDvmtByIterative.htm.
Figures
public Node dfSearch(Node node) {
if (this.isSatisfiedBy(node)) return node;
for (Node child : node.children) {
Node solution = this.dfSearch(child);
if (solution != null) return solution;
}
return null;
}
Figure 1. Depth-first search.
public Node bfSearch(List< Node > frontier) {
while (!frontier.isEmpty()) {
Node node = frontier.remove(0);
if (this.isSatisfiedBy(node)) return node;
frontier = append(frontier, node.children);
}
return null;
}
Figure 2. Breadth-first search.
public Node parameterizedSearch(List< Node > frontier, boolean breadthFirst) {
while (!frontier.isEmpty()) {
Node node = frontier.remove(0);
if (this.isSatisfiedBy(node)) return node;
// For breadth-first search put the children at the end of the frontier as usual.
// For depth-first search put the children at the front of the frontier, simulating a stack.
frontier = breadthFirst ? append(frontier, node.children)
: prepend((node.children, frontier);
}
return null;
}
Figure 3. The search type has been parameterized: breadth-first or depth-first.
public Node abstractedSearch(List< Node > frontier, SearchType searchType) {
while (!frontier.isEmpty()) {
Node node = frontier.remove(0);
if (this.isSatisfiedBy(node)) return node;
// searchType.merge(node.children, frontier) merges node.children
// into frontier. Depending on the SearchType, the merge may produce
// a breadth-first, depth-first, best-first, A* or some other search strategy.
frontier = searchType.merge(frontier, node.children);
}
return null;
}
Figure 4. The search type has been abstracted.