The more I see of Maxima, the more convinced I am that we would benefit
from some form of internal compartmentalization. It is currently very
difficult to assess with certainty the impact that a change in one part
of the system will have on other parts, or even which other parts are
directly impacted by a change. (In the sense of which functions, say,
rely on foo1 function or are impacted by the changing of global
variable bar1.)
So far we have done fairly well, but I can't help having the sense that
compartmentalizing and organizing Maxima internally would have a very
positive impact on development, since it would no longer be so
difficult to get definite answers to what parts of the system are
related. Ideally, one wants to ask the question "what behaviors are
impacted if globalvar1 is set to true" and be able to see a
comprehensive list, for example. These types of questions are
virtually impossible to answer in Maxima as matters currently stand.
This issue has come up before
(http://www.math.utexas.edu/pipermail/maxima/2004/007711.html) but I
would like to suggest 5.9.3 as the logical point to meet this issue
head on and hammer out what the best way to handle these issues is. My
ideas, which may or may not be worth anything:
a) Compartmentalize Maxima into lisp packages. Start with a
maxima-user package first (partial code for this exists somewhere in
the archives, IIRC) but also separate things internally into packages,
such as the plotting package, the integration package, the ode pacakge,
etc. etc. etc. Have those packages export functions often needed by
other packages, or import whole packages when this seems advisable, and
export user relevant commands to the maxima-user environment. Then, at
the same time, impliment name spaces or the equalivent in Maxima (map
the idea of lisp packages to the maxima userspace maybe?) so things
like share packages written entirely in Maxima code can also define
their own package environment. Then (the hard part) organize Maxima
into these packages, and in the process get a clear understanding of
(and detangle) the tangle of code that is currently the MAXIMA lisp
package.
b) Use Albert or some similar system to autogenerate comprehensive
documentation, including listings of what calls each function, what
functions are external vs internal, who calls a given function, which
global or package wide variables a function uses, what functions use a
given variable, etc. It will be huge, but it will enable a developer
to fire up a web browser and find all available information on any
given function (maybe this could even be a "debugging environment"
feature of describe). Initially of course most of them would have
none, but with the structure in place we could gradually fill in the
blanks.
c) Define some sort of standard checklist for new mathematical formats,
as per earlier discussions and Dr. Fateman's paper. This will need a
fair bit of thought, but I at least would like to have a checklist to
run through when adding new functionality.
d) For any new function added, and for older functions as we progress,
impliment some sort of systematic testing setup. Perhaps some sort of
unit testing :
http://www.rdrop.com/users/jimka/lisp/heute/heute.htmlhttp://www.ancar.org/CLUnit/docs/CLUnit.htmlhttp://www.cs.northwestern.edu/academics/courses/325/readings/lisp-unit.html
We could have, for each lisp file, a #filename#-test.lisp which, while
not in any sense a reliable test in all cases, might be tweakable to do
some very useful stuff (say, for example, that foofunction1 often gets
input that has been processed by foofunction2. You could add to the
test file a call to process some example input in foofunction2 and then
process that result in foofunction1 - this would be at least a minimal
check that any changes to foofunction2 didn't wipe out foofunction1.
It wouldn't replace the Maxima test suite, but it would provide a lower
level and more assuredly universal test of the Maxima code base.
Before the avalanche of comments to the effect that this is an
impossible amount of work to undertake arrive, let me say my goal is to
get the framework for these things in place, not universally impliment
all the tests. I am hoping to transition to this type of system in the
following order:
a) Impliment the maxima-user package/environment.
b) Define, but do not populate, a tentative organization for system
packages. This should remain flexible. Have maxima-user package use
exported symbols from these packages. (OK, so initially there aren't
any, but there will be.) Have maxima-user import all of MAXIMA as
well, so at this stage everything is defined pretty much everywhere.
The only important thing at this stange is that the package structure
exists and Maxima still functions.
c) Have all system packages import the default Maxima package. So
everybody knows about everything, the current state of affairs. At
this point, begin to move select code into special packages. These
will be the "low hanging fruit" such as plot commands, ode command,
integrate commands, etc. Remove these from the MAXIMA package, and
export them from their new packages into Maxima-user. If any of them
are internal to their package, internalize them. In this fashion, we
can begin to shift things into specialized packages gradually, without
breaking anything.
d) Refine the relationships as MAXIMA begins to become less populated
and strong links between other packages appear. If it makes sense to
import one package to another, set that up. This will take lots of
tweaking, but hopefully will be doable without major disruptions.
e) End with the most globally used functions in the MAXIMA package,
which will be renamed MAXIMA-BASE or some such. Other packages will
have evolved to their logical organizations.
At some point in the above, begin trying to get the Albert system to
intelligently handle the Maxima codebase. It will already analyze it
to some extent, but most likely things like global variables, as well
as some of the more odd def forms, will need to be handled. Macros
will need to be handled. This process will not make much sense to
start until some point in d) above, where less duplication of useless
names in all packages will simplify generating docs.
Once Albert is more or less working, we can begin creating unit tests.
The general rule will be:
a) document the function in the source for Albert
b) Once the purpose of the function is documented, write a few test
cases for it (stressful ones being more useful, as long as they don't
take too long)
c) It will be a "document as we go" approach, meaning no effort will
be made to ensure ALL code has a doc string. Preferable would be for
each exported function to have a doc string, but internal functions can
be handles gradually, as there is interest or need.
Does this sound reasonable to anybody? Am I totally off the wall here?
Cheers,
CY
__________________________________
Discover Yahoo!
Get on-the-go sports scores, stock quotes, news and more. Check it out!
http://discover.yahoo.com/mobile.html