SCOUG-Programming Mailing List Archives
Return to [ 22 |
May |
2006 ]
<< Previous Message <<
Content Type: text/plain
Imperative languages require the writer to define the logical
organization of the entire input source. Any changes which
occur after that point which impact the logical organization
similarly requires the writer to "rewrite" the logical
organization.
Declarative languages require the writer to define the logical
organization of code segments and name them for later
invocation from other code segments. This creates a name
hierarchy of the code segments which in turn defines the
logical organization of the source code segments, thus the
entire source. Any change in the invoking logic of a code
segment affecting the previously determined logical
organization now initiates a "regeneration" by the software to
"rewrite" a new one.
The writer writes in the "small". The software writes in the
"large". The writer rewrites in the "small". The software
rewrites in the "large". Human writers write more error free
in the small, while software writes unerringly error free in the
large...no matter how large. Have some respect for the
advantages of this division of labor.:-)
This comes about through use of the first stage of the
two-stage proof engine of declarative languages: the
completeness proof. It has another advantage. It is
absolutely tolerant of incompleteness: it never gives you a
"severe" error. Instead it gives you a current state of
incompleteness and what it needs from you to continue on the
process toward completeness. In a sense it "recognizes" the
"natural" state of software development: starting from zero
code, incomplete with incremental additions until complete.
It raises the question of why we use tools like compilers for
whom we have to "fake" completeness in order to use them.
It also raises the question of we would implement an
interpreter which would not incorporate the completeness
proof, and thus support for incompleteness, of declarative
languages.
So what do we write logically organized in the small? Control
structures: sequence, decision (if...then...else... and case
(select...when...(multiple)otherwise...), and iteration (do I =....,
do while..., do until...). They have in common a single entry,
single exit structure. That essentially makes them "plugable"
or "replaceable" entities.
More importantly from the perspective of what occurs after
code generation it makes them "testable" entities. If you can
guarantee their internal logic in isolation, all possibilities, you
can guarantee their behavior in "connection".
That takes us to the second stage of the two-stage proof
engine: the exhaustive true/false proof.
Here we have to have a clear understanding of use of the
term "exhaustive". SQL satisfies a query by after assuring its
completeness, generating the necessary code, and processing
it against the "FROM" tables named in the query. Here
exhaustive simply means "from the data in the rows from the
tables supplied".
You prepare the "test data" in the tables somehow. The
query will return zero, one, or more true instances satisfying
the "WHERE" clause. You change the tables, you change the
data, you may get different results. It does an exhaustive
test of the data you somehow provide.
Now declarative languages support two forms of logical
testing, clausal, where you provide the data, and predicate,
where the software generates it. SQL obviously uses the
"clausal" form. You still get an exhaustive true/false proof
but only against a particular set of data instances you
provide. That means you have to do, develop, and maintain
the test data. That resulting work, the effort required, has
lead to the "rule of thumb" to allocate twice the amount of
time for testing (generating test data, test scripts, their
preparation and execution) as you have for writing the code.
Obviously if you don't have to do that, if you can
automatically generate the necessary test data by the
software, it can save you one heck of a lot of time, money,
and effort.
Thus why use clausal logic when predicate is available?
Predicate logic derives from the form for each variable
defined as "for all x where x equals" a range or set of ranges.
You specify a set of values either continuous or discontinuous
that you want to apply to the variable. The software will
then consider the set of all variables under consideration, e.g.
those contained within a control structure, and enumerate all
possible value sets for use in the true/false proof.
This simplifies your contribution to the generation of test data.
While the software could do it for an entire program, it would
overwhelm you with the volume of results. You could do the
most exhaustive of tests, but you couldn't live long enough to
review all the results. Thus the testing period would exceed
that of code development by a factor of several magnitudes.
It makes the rule of thumb, 2, of the ration of test time to
programming time look absolutely angelic in comparison.
So on the one hand those engaged in testing programs written
in imperative languages and those using clausal logic with
declarative languages face the impossibility of complete
testing. In fact they have commonly made the same error in
saying that such exhaustive testing is impossible.
As it inserts a delay between the production of the source
and its entry as a version of a production system, it is
accepted that most errors will occur, i.e. be discovered, by its
users. Thus we introduce an alpha test period, a beta test
period, and then more general user test period. In beta
testing we seek a broad audience of users to execute, i.e.
test, a program in their environment in parallel or
concurrently with all other selected users. This goal of
parallel testing we hope will discover the most bugs in the
least amount of time. Nevertheless we never expect that it
will catch all bugs, which we explicitly claim with respect to
testing as impossible on its face.
On the other hand predicate logic allows an easy means, in
terms of what we manually have to specify, to perform as
exhaustive test as we exercise its ability to do so. We can in
fact achieve a broader range of tests and thus test results
without ever calling on a human population greater than zero.
We can discover all errors, i.e. bugs, fix them, and provide
users with a production version completely free of logical
errors. The decision then becomes more political related to
meeting deadlines and such, to the time to fix detected bugs,
than to whether we can issue bug-free code.
Thus if you take into account the writing of code segments
along with the higher probability of writing them error free,
combine that with the ability of the reduced scope, i.e. volume
of results, resulting from its "complete" exhaustive test to
guarantee its error-free condition, you now have a means of
incrementally climbing the "invoking name" hierarchy defining
the logical organization of the program to effectively achieve
the same exhaustive testing of the program as a whole.
You start at the lowest level of any path in the hierarchy and
perform a complete exhaustive true/false proof on each one.
Once they are error-free, once you determine the false false
and the true true, you need only the set of true results to
incorporate this test within that of every invoking segment. In
that manner you climb each path in turn until you have
completed the process on the highest segment, i.e. the "goal",
in the hierarchy.
You will have done in less time complete exhaustive testing,
producing an error-free result, than possible using other
testing methods. Even though changes may occur which alter
the flow in one or more paths, at one or more levels, the
completeness proof will hasten the rewrite of the logical
organization. The previous exhaustive testing of unchanged
segments will contain results usable in regressive testing. The
new changes will receive an exhaustive test in now an
established process. This will result in a version-to-version
flow of error-free production code at minimal cost in people
time and effort.
Just remember that the code segments at minimum represent
"true" control structures following the one entry, one exit
rule, i.e. plugable units. Contrary to the popular belief that
you cannot test every logical path in a program, you certainly
can. The secret lies in using an interpreter which "tolerates"
code segments as complete program units, using the
two-stage proof engine of declarative languages, and using
predicate instead of clausal logic in testing.
Now none of this occurs by magic. Someone has to write the
software that does this. As we progress from PM interface,
i.e. programming, to writing an editor, incorporating syntax
and semantic checking, and code generation within the
context of the completeness proof we will have to
incorporate the use of predicate logic as part of our second
stage of exhaustive true/false proof.
As we will have either interpretive or compiled code as an
option within a single tool along with the other features
related to the abilities of the completness and exhaustive
true/false proofs no other IDE in use or underway choosing
different means will even come close. It's not a "silver
bullet", but an intelligent assessment of available technology
organized with priority on the productivity of the user and not
on the preservation of any vendor of software tools.
This is about as far from the intent of ECLIPSE as you can get.
Tough luck, IBM.
=====================================================
To unsubscribe from this list, send an email message
to "steward@scoug.com". In the body of the message,
put the command "unsubscribe scoug-programming".
For problems, contact the list owner at
"postmaster@scoug.com".
=====================================================
<< Previous Message <<
Return to [ 22 |
May |
2006 ]
The Southern California OS/2 User Group
P.O. Box 26904
Santa Ana, CA 92799-6904, USA
Copyright 2001 the Southern California OS/2 User Group. ALL RIGHTS
RESERVED.
SCOUG, Warp Expo West, and Warpfest are trademarks of the Southern California OS/2 User Group.
OS/2, Workplace Shell, and IBM are registered trademarks of International
Business Machines Corporation.
All other trademarks remain the property of their respective owners.
|