Stuff For Sale
2004 Summer Tour
About
Blog
Class Stuff
Email Me
Events
Gallery
Home
Info Ark Products
In The Press
Newsletter
Services
Smalltalk
Veggie Van Gogh
Credits
© 2002, Bytesmiths
|
Please patronize sponsors of this page!
Bytesmiths no longer is involved in software consulting. Maintenance of this web site is currently subsidised by unrelated business activities. Please pass the word to other interested folks, so I can continue to host this page!
- Bytesmiths Editions -- large, archival, fine-art photography on unusual materials
- Bytesmiths Press -- artists' services: web design/hosting, jury slides, giclee reproductions, opening announcements, brochures, etc.
- Champagne Beadworks -- handcrafted jewelry and beadwork
- Crafted By Carol -- handcrafted jewelry and beadwork
- Dharm Atma Yoga -- Kundalini yoga instruction
- EcoReality, an organization devoted to establishing a sustainable ecovillage
- Ecovillage Newsletter -- Diana Leafe Christian's news of her travels.
- Environmental Education Outreach -- providing environmental education worldwide.
- Gemini Gypsy -- Carole Good-Hanson's fused glass frames
- Green Chipper -- light forestry and environmental services.
- Salt Spring Island Society for Community Education -- community education on our island of 10,000.
- Veggie Van Gogh -- two artists' mobile warehouse and living quarters, petroleum-free!
- Veggiemog -- life and times of Kelly O'Toole's Unimog, running on biodiesel
Your site could be listed here, for as little as $12 per month! Go to Bytesmiths Press for details.
This site has been selected by PC Webopaedia as one of the best on this topic!
This site has been awarded a Links2Go Key Resource Award in the Smalltalk category!
Originally published in The Smalltalk Report, July 1995.
Managing Modifications
by Jan Steinman
Originally published in The Smalltalk Report, July 1995.
Managing Project Documents 2
by Jan Steinman
In the last issue, we
made a case for "continuous documentation," and outlined what that
entails. We also promised to give you some concrete examples and
source code, so you could begin to implement a continuous
documentation process.
First of all, we'll need to change how classes store their
comments... WE INTERRUPT THIS COLUMN TO BRING YOU A BASE IMAGE CHANGE
ALERT! ALL USERS WITHIN 200 KILOBYTES OF THE IMAGE MUST EVACUATE
IMMEDIATELY! WHEN YOU ARE ALLOWED TO RETURN, YOUR PRECIOUS, CAREFULLY
CRAFTED, WORK OF ART CODE WILL TAKE ON STRANGE AND (we hope)
WONDERFUL NEW BEHAVIOR! HAVE A NICE DAY!
Whew! We almost slipped one by the Base Image Police there, but
they caught us! So, let's retitle this column and proceed.
Managing Modifications (or "Who Changed basicNew?")
Pity the poor Smalltalk vendors! You buy an object library in C++,
and you typically get linkable object code -- it works, or it
doesn't. But when Smalltalk customers don't like what they got from
their vendor, they simply change it -- which often introduces bugs,
which are often subsequently reported back to the vendor! (All of
this applies to third party code as well.)
Consider the myriad ways that basic Smalltalk can become polluted:
- Beginner naivete: "Delay := Delay forSeconds: 1."
- Enough knowledge to hurt yourself: a seasoned
ST/V user tries VisualWorks, and writes a clean up method that
does "MyClass allInstances do: [:inst | inst become: nil]."
- Enough knowledge to make it look random: the same
code above, but cleverly made conditional upon rare low memory
conditions, and then forgotten.
- Unintentional overrides: such as implementing
nextPutAll: in a Stream subclass that normally inherits it.
- Forgotten halts and other test or debug code:
beginners often put halts in system code (rather than putting
halts in their own code, then stepping into the
system code), and sometimes they forget to take them out.
- Well meaning changes gone awry: such as the
datacom specialist who changed Integer
printOn: so that if the shift key is held down,
they print in hexadecimal. (This one didn't quite make it to
production before someone noticed strangeness when extending
selection in a table by shift-clicking...)
- Downright malicious: nah, no Smalltalker would
make malicious changes, right? But if someone did, say a
disgruntled soon to be former employee
Always keep in mind that base changes are the enemy of re use. One
of the big wins of re use is that less testing is needed when you re
use previously tested code. The down side is that changing code that
is heavily re used increases the testing burden, since you aren't
really sure all the uses of the changed code agree with each other.
Why are changes necessary?
In team programming, base changes fall into two categories.
Personal changes are necessary for individual
developers. Individuals need to be able to experiment with base
changes before foisting them on their teammates, or they may
experiment with base changes in order to better understand the
environment, or they may simply want to customize their own
environment. If you are using a code management system (such as ENVY
or Team/V), you generally have numerous options for balancing the
needs of the team for stability against the needs of the individuals
for experimentation.
The second category is where the trouble begins. Although you
should do whatever you can to discourage it, sometimes you need to
make project or corporation wide base image
changes. These changes might include:
- Fix bugs in vendor's code: this is fairly
unusual, but if you do find a bug that is getting in your way, and
it has an obvious fix, you will probably want to incorporate it
into your base. Also, maintainers love getting bug
reports with fixes, so if you fix the bug carefully, document it
properly, and submit it with your bug report to the vendor,
there's a good chance it will be in the next release from the
vendor, which makes your re integration job that much easier.
- Make enhancements to the vendor-supplied tools:
this is the category for which the Base Image Police caught us!
The combination of dynamic compilation and full source code means
you can easily tailor the Smalltalk development environment to
your organization's specific needs. These kinds of changes have
little possibility of getting into a vendor's product, and so they
must be done in such a way that facilitates re integration with
future vendor releases.
- Make enhancements to the vendor-supplied framework
classes: this is similar to the previous case with one
important difference. The changes you make to framework classes
will be delivered with your application, and so must be more
robust than changes made to development tools. This should involve
regression testing to ensure that the framework still functions
with previously written code.
Limit scope and impact
of changes
Base image changes can be categorized by their scope. You should
carefully analyze your needs, and limit the scope of your change to
the greatest degree possible. For example, it may first seem that you
need to add an instance variable to a base image class and add two
methods that use that new state, but further analysis might show that
you really only need to change the use of an existing instance
variable, and then hide that change by changing the methods that
access that instance variable. The following change categories are
roughly in order of desirability.
- Single method , non state changes are the
best. Such changes should not change the arguments
or answer of the method, but only it's side effects. The answered
object should have the same behavior, and no additional
constraints should be placed or assumed on variables or sent
methods.
- Encapsulated state changes put different objects
in instance variables , but manage those changes
through the methods that access those variables. These changes
tend to have small impact in any given vendor release. For
example, you might need something better than simple truncation of
window labels to use as icon labels, so you could change the
label instance variable to be a two element
Array that either answers a full, title bar length
label if the window is open, or a custom short label if the window
is iconified.
Another useful encapsulated state change is arranging for an
instance variable that normally holds a method selector so that it
can hold a block. This can be a useful change to "pluggable views"
for increasing the dynamic behavior of your system, and if
properly done, is essentially invisible to old code.
A big problem with this technique is that object state is
directly visible to subclasses. If some poorly written subclass
directly accesses the state you have changed, rather than going
through the access methods you changed in tandem, there will be
trouble, and it may be difficult to diagnose.
- Method overrides don't seem like
changes, but they can have tremendous impact. (If you don't
believe us, override Behavior
basicNew with a new implementation in
Object class, then purposely introduce a bug and see
what trouble that causes!)
Overrides are tempting, because they do not change actual base
image code, but for that same reason, an override is difficult to
track and debug. They are more trouble when re integrating new
vendor releases -- none of your comparison tools will detect the
override as a change, but it may well conflict with vendor changes
in the new release.
Finally, there is usually a reason for the inheritance of such
methods -- if an override seems attractive, be sure that the
change shouldn't actually go into the inherited method.
- Changing message arguments or return
objects begins to get messy, and should be
avoided. Constraining arguments or returned objects, such as
requiring that an argument be an Array rather than
any kind of collection, might work for your particular case, but
it is certain to eventually break someone else's code that didn't
share your assumption.
- Changing object shape , or the
number or ordering of instance variables, is one of the most
invasive changes you can make, and is to be avoided. Adding
instance variables by itself is not terrible, but if such a change
is really necessary, most of the time it is because the
fundamental behavior of the class is being changed -- behavior
changes are what subclasses are for!
- Changing inter class interfaces
is really dangerous. You might track down all uses in your
context, but third party software won't know about your change,
and your Smalltalk vendor's next release certainly won't know
either! If changes this extreme are required, be certain to
document them well, to ease the inevitable problems that will
eventually result.
"Conditionalize" changes
Especially in the latter categories mentioned above, it becomes
increasingly important to factor your change in a way that makes it
easy to back out. For example, if you want to add some special
processing to what happens when you compile a method, it is tempting
to simply put your modifications in line, but a better way is to make
all your modifications in a separate method, then conditionally send
that message if it exists, by using testing methods such as
respondsTo: or canUnderstand: .
Note that these tests can have a performance impact, but so can a
broken change that you can't isolate!
This "base change boundary" is one of the few places we tolerate
the use of isKindOf: . Using
isKindOf: as part of your program logic is contrary
to good OO design, because it imposes the sending method's viewpoint
on another object, rather than obtaining the other object's willing
collaboration.
However, at the base change boundary, isKindOf:
is useful for testing the existence of base changes, so that they can
be easily backed out without once again changing the base. It still
isn't good OO design, but it's a bit more justified when used to
verify module interface boundaries.
Another useful technique for managing changes is to make them
conditional upon an arbitrary "signature" method. For example, you
might implement hasBeenHacked in Object
, and then bracket your changes inside (self resopondsTo:
#hasBeenHacked) ifTrue: [...]. This way, if a particular
module of enhancements are present, they are used by changed base
methods, but if they are not present, the base changes skip the
conditional changes.
Positive Identification
There are two principle reasons to keep track of exactly what you
changed: it will make your integration with the next new release from
the vendor less painful, and it will help you to back out a change if
it proves to be a mistake. Identification needs to happen at the
method, module, and system level.
For method changes, we've implemented a "hot key" that inserts
"Modified by [user] on [date]: ." where "user" and "date" are
properly filled in, and the cursor is positioned before the period to
encourage the user to further describe the change. We use this two
ways. In a short method, we simply place it after the normal method
comment. In a long method, we bracket our changes by placing this hot
key comment both before and after the change.
Common code management systems allow version names for code
modules. Keep in mind that your base image changes are not the main
development stream; they are a branch! So if you modify a code
component that the vendor named "R1.43", you should not call your
version "R1.44", because that will most likely collide with the
vendor's next release!
We use two techniques for naming changed base image modules; both
help indicate a branch has taken place. The simplest is to append a
"dot level," so the above example becomes "R1.43.0". This can get
messy if you have a number of changes from different sources, so we
often prepend some identifying information, such as "Bytesmiths
R1.43.0". Either way makes re integration with new vendor releases
easier.
At the system level, a separate document that records every change
or addition, organized by module, class, and method, is highly
useful. These release notes are necessary even if your
source code management system provides a version comparison tool; it
is very useful to have a linear document to review when things start
breaking!
In some cases, your code management comparison facilities can be
harnessed to survey changes and build templates for these release
notes (we plan to demonstrate this in a future column), but
documenting why and how the change was made
will remain a human activity.
Organizational Issues
In organizations with multiple Smalltalk development teams, there
is usually an individual or a committee that has authority to decided
whether a particular change to the base image will be allowed. This
role of base image "Keeper" is particularly important when there is a
shared corporate-wide version of all base image classes.
A trial period for changes is a good idea. The Keeper cannot
always tell that a particular change is benign to all the development
teams' applications. If any team reports a problem with a change to
the base image, the Keeper can then modify or back out the change to
correct the problem.
Even when there is only one Smalltalk team, the integrity of the
base image is usually guarded by a Keeper who is the sole developer
allowed to release changes to the base classes, also based on a trial
period. In our experience, a trial of about one development cycle
(six to eight weeks) is a good idea.
Conclusion
Now that you know how to make base changes in a way that is
limited in scope, conditional, identifiable, re integratable,
documented, and "back outable," we return you to your regularly
scheduled column. In the next
issue, we'll give you some actual base image changes to practice
with as we proceed with examples of "continuous documentation."
Go to the previous column in
the series, or the next
column in the series.
|