Experience Report: I Was a Smalltalk Gunslinger
by Kevin Johnson
kmj@acm.org
For most of the ‘90s I supported myself by writing Smalltalk as a freelance consultant based out of the Object Lab at the University of St. Thomas in Saint Paul. I worked just enough to pay the rent and keep myself supplied with beer and pizza. The rest of the time I spent pursuing the dream of building the next great design and development tool. Needless to say I never got rich, but I did learn a few things.
The Demo
Panic in corporate development land. The prototype of the thin client, web enabled customer service application is scheduled to be presented to upper management in a week and it still takes several minutes to get a query back. Call in the gunslinger.
I was a little hesitant about accepting this gig because I wasn't sure I could help. The Smalltalk dialect was unfamiliar to me and the problem domain (screen scraping mainframe terminal data and shipping it to a web browser) was alien. But I needed the money and I figured that if they were desperate enough to yell for help, I was probably better than nothing.
I spent half of the first day getting an overview of what they were trying to accomplish. Then I dived into the code with the help of one of the locals. We poked around with the browsers and debugger and I soon started to get a very sketchy idea of how things were hooked up. By the end of the day we hadn't found much, but we had eliminated a lot of places where the problem wasn't. I was optimistic and boasted to a friend that wed have the problem isolated by noon the next day not really expecting to succeed.
We didn't make the noon deadline, but we did have it an hour later. It turned out that deep in the bowels of the vendors EHLLAPI framework the default behavior was to create a new connection every time an application made a request. What if we cached the connection so it could be used again? We made the change there in the debugger and proceeded. Additional testing confirmed that performance went from nasty to acceptable and that there were no obvious harmful side effects.
Lesson: The method of least knowledge. I never did learn much about the system under development and I still know zip about screen scraping mainframe terminal data, but I was able to use the available tools like the debugger to drill into the code where it was possible to see a potential problem. In fact I think that if we had focused more directly on solving the problem from the start rather than on my understanding the system as a whole we might have fixed it the first day.
CAMS
The Classroom And Meeting Scheduler (CAMS) started out as a masters project at the University of St. Thomas. The person who had been doing classroom scheduling for 30 years (Frankie) was about to retire and the director of the Object Lab (Dave West) managed to convince the facilities department that he and a group of his students could build a software system to, if not replace her, at least smooth the transition. At the time the project was under initial development I was working on something else and so I came to the project after it had been in production for a year or so. All of the original developers had received their degrees and moved on. What design documentation I could find was largely out of date since the software had been finished after the motivation to produce documentation had been completed.
The initial work involved making minor repairs as needed to keep things working along with a lot of input data massaging and hand holding. We started by getting an overview of the system from Dave and later from one of the original developers. We made small changes, initially in the user interface, and avoided touching code we didn't need to. Performance was lousy which made testing difficult. This work was done under the pressure of a hard deadline (the class schedule had to go to the printer) and we were not confident enough to make changes that might break the system.
After struggling this way through a couple of releases at the end of each semester I decided it was time to try and solve the worst problem which was performance. I replaced the ODBC interface to a relational database with a simple binary file persistence mechanism. Performance was vastly improved, testing became easier, and we were able to move forward to add new features. The program is still being used to this day several years later.
Lesson: Courage is essential. The performance problems not only made it hard to use the system, but also made it hard to improve the system. Fixing them early, while seemingly risky, would have made the rest of the job easier.
Lesson: Worst things first. The incremental user interface improvements made in the first couple of releases were swamped by the overwhelming performance problems and resulted in little real improvement of the user experience.
Position Statement: A Deliberate Approach
Short term strategies (hours to days)
- Save a baseline so you can get back to where you started.
- Drill into the system using the most direct tool at your disposal. This is probably a debugger, but you may need to explore the code at a higher level to find where to set breakpoints.
- Pair with a local expert if possible to help with navigation and to have someone to bounce ideas off of.
- Small scale refactoring at the level of a single class can improve the readability of the code significantly and has only a small risk of breaking anything. The benefits of improving readability must be balanced with the need for speed. Cleaning up every class to make it more understandable is not a short term strategy, but cleaning up one or two classes that are central to the problem may be the best way to proceed.
- Take small steps and keep it working as you go. Its a better bet to spend the time testing after each small change so that it is easy to tell where you went wrong. If you make too many changes before you test, it can be very difficult to figure out which change caused the problem.
Medium term strategies (days to weeks)
- Start with operations that are initiated from the user interface and follow them from the view into the model making notes and/or drawing pictures as you go. I generally keep track of classes and their relationships as well as the interesting messages.
- Write tests as a way to help you understand the operation of the system even before you start to make changes. To start with the tests will probably be too high level to qualify as unit tests, but they will provide a safely net when you start to make changes.
- If the system has been worked on by many people over a period of years, chances are that it will have a mess of coding styles. Automated code formatting can help make the code more readable.
- Larger scale refactoring both at the single class level and more wide spread can be a low risk (especially when using a tool like the refactoring browser) way to improve the code and increase your understanding.
- I generally find that I donut really understand a system until I start making some fairly big changes. Or maybe it comes down to not having the confidence to make big changes until I understand the system. Either way you will need to make changes eventually.
- At this time scale you can afford to make larger changes and the courage to make them becomes essential. As noted in the experience report above, it can often improve your chances of success to start making changes sooner rather than later.
Longer term strategies (weeks to months)
- Expand the informal drawings you made above. I seem to get the most benefit out of a medium detail object diagram that shows the primary relationships. Sequence diagrams are too detailed. You need to be able to control the level of detail.
- Continue the refactoring effort started above. By now you should be able to afford the time to make some substantial simplifications and improvements.
- Continue to write tests. Starting with the central objects as you now understand them you can begin to write actual unit tests to verify everything that can possibly break. The central objects will most likely need to be reworked to make unit testing possible.
- At some point in the course of longer term involvement with a system it may become obvious that the only way to fix it (or at least certain parts of it) is complete reconstruction. Look for hot spots where bugs turn up more often than in the rest of the system or places that need to be more flexible to accommodate ongoing changes in requirements.
- If you stick with a system long enough eventually you will become the expert. At that point you should continue to work at making the system easier to understand for those that will come after you.
Tools I Use
In Smalltalk the tools that I use most of all are the senders, implementers, and references browsers. I use these tools to extract the static relationships between the objects. I record these class names and relationships using a text editor and a simple drawing tool.
Sometimes the static relationships are hard or impossible to infer using code browsers and so I use the inspector or visual inspector. The visual inspector makes it easy to keep track of the relationships between objects, but the one I have is fairly primitive and lacks several important features like printing.
The drawing tool that I use is the one that I wrote while I was at St. Thomas. For me, it has the advantage that I understand how it works, not to mention the fact that I can fix it if it turns out to be broken. Other tools would probably work just as well although I've never had the patience to learn a new one well enough to make it comfortable.
Occasionally I use a code formatter to make the code a little more readable, and I would probably use it more if I had a formatter that could be configured more completely.
The refactoring browser is indispensable for doing refactoring with confidence. I never, ever want to go back to grep and a text editor!
Sometimes I've used SmallLint or other code quality tools to point out places that need work.
I use SUnit to write tests. It works fine for what I do.
Tools I wish I had
A more complete visual inspector would be useful and it would be fun to integrate it with a drawing tool. What I would like in a drawing tool is something in between a generic drawing tool like Visio and a full blown CASE tool like Rational Rose.
An automated reverse engineering tool would also be useful. I don't want a tool to do “round trip engineering”. In my opinion, if you extract enough detail to generate code, you might as well look at the code. I want something that will help me draw the kind of medium detail diagrams that I currently do by hand.
</x-html>