Session Recap -- Sunday, Oct 10
Twas just Steve and I for the first couple of hours. We decided to forgo the planning session until Kristi arrived in the afternoon, so our first order of business was to try to speed up the tests.
Running the entire test suite was taking a considerable amount of time, which is bad because it creates a situation where we'd want to avoid running them during development (for example, "well that was just a tiny change -- we can probably get by without doing all the tests"). So we did some time trials. It took just over one minute to run the 65 or so tests (split up among 7 or 8 test classes). Steve had implemented an optimization last week having to do with the VB Line Reader, but we learned that it didn't really save any time (maybe one second), so we took it out since it just made the code more complicated.
It was immediately apparent that the 'MacroExpander' test class would be the focus of our effort, since it was taking up almost half the time (28 seconds)! We did some straight-forward ("easy") refactoring and cut 10 seconds off the time -- not bad for a first attempt. We also realized that the macro expander was opening and closing the target project over and over again for each test. We figure that in the future we could cut down the test time significantly by isolating the project open/close function to just one test, and have the rest of the tests use pre-created text ('fake' modules).
---
When Kristi showed up, we began our planning session. Steve started off by telling us about an aspect of XP that we had been neglecting: writing 'user tests' on the backs of story cards. These user tests are "human language" explanations of what a feature will look like and how it will behave when finished. They do not need to be as thorough as unit tests, but the process of writing them did force us to flesh out our implementation ideas more thoroughly, and should help us stay on course as we work on each story.
We then calculated our velocity, which wound up being 3 stories per iteration. We had 4 story cards remaining that we wanted to fit into the release, and started discussing and prioritizing them. "Friendly Macro Error Reporting" and "Auto-Backup" were both partially complete (we had started working on them two weeks ago), so we decided that we would tackle those first once we finished the planning session. However, we wanted to talk more about the other two story cards, "Pre-Expansion Check" and "Macro Seeding" before we moved on. This wound up taking significantly more time than we anticipated...
---
The "Pre-Expansion Check" feature is intended to be used in situations where someone may have inadvertently altered code that had previously been expanded from a macro definition. In this situation, we want to make sure that the user would be notified upon subsequent macro expansions, so that the altered code wouldn't get silently overwritten (after all, just because the third party wasn't familiar with our spiffy macro system doesn't mean they didn't write some useful code).
As we discussed this, it became apparent that implementing this feature isn't as easy as it sounds at first. After all, how do we know that someone changed the code in the macro target section, as opposed to the macro definition itself being changed? We obviously don't want to alert the user every time the macro definitions change, since that's the whole purpose of using the macro system in the first place! After wrestling with this for a while, we narrowed it down to three possibilities:
Option #1: Utilize a "checksum" as an attribute of the macro target tag, which would be calculated each time a macro expansion takes place (the checksum value would be based on character count and/or numeric representations of the VB code content). Upon subsequent expansions, any macro target code section containing this checksum tag would first have the checksum re-calculated. If the current checksum value doesn't match the old checksum value, then we'd know that the content changed, and could alert the user before overwriting this potentially important code. Unfortunately, this wouldn't tell you exactly what was changed, but at least you would have an opportunity to examine the code before it gets overwritten with the new macro expansion.
Option #2: Each time a macro is expanded, "back up" the definition by writing a copy of its text to a "
Option #3: Drop the feature altogether. We could simply notify users of the macro system that they should never change code within a macro target's opening and closing tags. We could easily have the expander add comments to the macro target areas saying something like "WARNING: Generated Code -- Do Not Modify".
Our decision was to go with option #1. Option #2 was really overkill when we thought about the intended usage of the macro system, and we didn't want to so readily admit defeat by going with option #3. The checksum feature provides a nice balance between usefulness, simplicity, and ease of implementation.
We then talked about how to handle these potential occurrences in the User Interface. We decided to show the user all macro target sections that didn't match their checksums at the same time via a simple dialog box. The user could then decide to either keep the existing code, or overwrite it with the re-expansion (or just cancel the whole expansion altogether). We thought it would be extremely annoying to be prompted over and over again for multiple checksum-mismatches. In the future, we could add checkboxes to the dialog that would allow the user to selectively overwrite on a per-target basis, but for the time being it will be an all-or-nothing choice.
---
Okay, next was the "Macro Seeding" story card. This feature is intended to be used in situations where you want to put the same macro targets in every procedure throughout a project. The primary example of this would be adding consistent error handlers to code you inherited from someone else. The two issues we had to contend with were: How should the seeding code be stored, and what should we do about overwriting existing macro code?
Keeping consistent with the way we were doing everything else, we decided to simply have the seeding code contained within "
With that out of the way, we needed to decide what to do about overwriting existing macro code. This would be a situation where a project has already been seeded, but you want to re-seed it with something different. (note that if you wanted to change existing macro code, you could simply change the macro definition and re-expand). We came up with a few possibilities for how to handle this:
Option #1: If ANY macro code exists in a procedure, don't re-seed it.
Option #2: If any tags that appear in the seed code also appear in a procedure, don't seed it.
Option 1 doesn't allow for much flexibility, and option 2 sounded like a nightmare to implement, so we came up with Option #3: Allow for a special sub-section of the seeding code where the user can list specific "Don't-Seed" text. These pieces of text would probably be macro tags, although they don't have to be. Procedures containing any of these strings would NOT be re-seeded. This would be a piece of cake to code, and provides the user with a good amount of flexibility.
Now in addition to fleshing out the macro seeding story, we have some sample seeding code to include with our "Standard Error Macros" that will be distributed upon release.
---
Phew! As I mentioned, the planning session took up a lot of time (well-spent, of course). We had one hour left, and Steve worked on "Friendly Error Messages" (for macro language syntax errors), while Kristi and myself worked on "Auto-Backup" (for copying code before being overwritten by expanded macros). Steve reported that we have 2 friendly error messages thus far, and there will probably be 5 by the time we're done with the story card.
Auto-Backup is almost finished -- we just need one more test case for backing up Forms and Class Modules (as of now, we only have tests for backing up standard code modules). We did hit one nasty snag, having to do with writing the backup files to the filesystem. Steve quickly diagnosed the problem -- we unnecessarily called the Dir() function without passing it any parameters, which apparently you can't do if you didn't call it previously WITH parameters (uhh, right...). Anyway, let this be a lesson to us all about the dangers of copying and pasting code!

0 Comments:
Post a Comment
<< Home