As it turns out, no one at all except for little ol' me was able to make the work session. I decided that the thing to do would be to simply do whatever I could by myself and use this as a chance to compare with what happens when we have a whole team, do pair programming, etc.
First off, I wanted to spend much of the time working on stuff directly related to stories in the iteration plan, but also, we've been needing a way to do source code control for a while, and I wanted to make some progress on that.
I had already written some really simple code in a previous session that writes the Access code modules out to files, so they can be added to a source code control system, but I knew that wasn't enough. Our code consists not just of code text in code modules, but of a form, and a table that contains test input/output, and might someday contain reports, and even a macro or 2. I wanted the system to be able to write out all of that, and I wanted the system to be able to compare what was written into the export directory with what exists in a directory managed by a source code control system, and update the directory accordingly. Oh, and one more little thing. I wanted the module file extensions to be .bas for standard or .cls for class modules.
Ideally, this code would have had tests, etc., but this should be very simple code, it's a tool for our process, not part of our production product, and it's harder to do TDD alone than with a pair. So, I proceeded without tests. In this case, that seems to have worked out OK.
To summarize the simple parts of what I did, I factored out the code that loops through a list of AccessObject objects, and calls SaveAsText to write them to files, then called it once for each type of object, also passing a file extension. Also, in the case of code modules, I had to add code to use the VB IDE to determine whether each module is Standard or Class to add the correct file extension. When I got to tables, though, I had some issues.
So - tables. First off, the question of whether to save tables at all, or just table structures. Is a table part of the "code", or is it application data? Some people put application data in the same MDB file as the application code, but this is not considered a good practice. In general, a table that is embedded in the application MDB is considered part of code support, and that is true in our project as well, so i decided that, if the table is not linked, it should be saved to text. Something should also be done about links, but the link should probably be just a file with a connect string and attribute settings, or something. In any case, Access has no built-in capability to do any of this.
What I ended up doing is deciding that, for now, it would be good enough to just save embedded table data as a persisted XML recordset. To recreate the table from this data later, we would be missing information about indexes, etc., but this is far better than nothing, and a good place to start, so I press on. Since I;m going to use ADO anyway to save the recordset as XML, I go ahead and use ADOX to read the list of tables, figure out whether they're linked, etc. I have to bone up a bit, but it all works out OK. It seems like I should have been able to open the output file as a stream, and write to that, but I never figured out how, so for now, I am writing the recordset's XML to a stream in memory, then saving the stream to a file. What the heck - it works.
After finishing this work, I come to a couple of realizations that some of the team reading this now might have come to as well.
Realization #1:
All of the work to save code modules is duplicating work that has already been done on a story in the application itself: "Auto Backup". If I checked that story, I might have found that it was already done last week, and I could just use what's there. If it wasn't done, my efforts might have been better applied to getting it done. With a pair working with me, we probably wouldn't have made that mistake, and would have saved a lot of time.
Realization #2:
I'm writing code to save table files embedded in an Access project for purposes of updating files under source code control, but we're going to move this code into a VB project soon, and then we'll have to store that test data some other way anyhow, probably in some sort of text file, or something. Has that been a waste of time? Again, a pair could have helped make sure that question was asked sooner, and perhaps saved the time spent working on it if it was not worth doing.
Anyway, on to the stories...
I decided to continue work on "Context Parameters" since I've done a lot of work on that recently and have a good idea what direction it's going. When we last left off, we were doing a sort of "combing" refactoring of code to gradually push replace code that deals with "code text" with code that deals with arrays of our new clsVbModuleLine objects that contain the context information we're going to need. We figured we were mostly done with the steps of that refactoring before, so I kept going. In short order, I had converted all public methods that take code text into mere wrappers for testing purposes that convert code text into arrays of code lines before calling other methods, removed all calls to those methods from the class itself, and modified code all the way down the chain to use clsVbModuleLine arrays, not text or arrays of strings.
Aha - I thought. Now, I have all the information I need to generate XML with context information derived from what was stored in the module line objects when they were read from the code module by the module line reader! Not so fast.
I know have what seems to be 2 pieces of rope to tie together, but they don't quite meet in the middle. We have module line objects with context information, but where we need the information is in the context of a Macro tag. The trouble is that we don't build the macro tag, we get it from the comment line that comes straight from the raw code text. In order to expand the macro with the right context parameter data, though, I pretty much have to get the context information into that Macro tag where it's easy to find from inside the XML DOM.
The trick I worked out is to actually check for a '<Macro... line in the ConvertCodeLinesToXml function, if so, actually insert context attributes into the tag by inserting them ahead of the > that closes the tag. It looks like this is working, but now a whole bunch of tests fail. What's up with that? Well, when we re-create the code text from the DOM document, now the context attributes are in the Macro tags. The spec doesn't call for these to appear during macro expansion, and there's no reason they should, so what do do?
I see that what I need to do is pull those attributes back aout when I'm regenerating the code text from the XML. For some reason, I decide doing it in the DOM will not be adequate because what happens with white space counts, etc.? So I spent several hours writing code that seems to be close and is making most of the tests pass by paring and ripping the extra attribute text out of the Macro tags after expansion. I was thinking, this is not working in small steps, but couldn't think of a better way to procede.
I have made a number of choices here that should preserve whatever white space was in the tag prior to inserting the extra attributes, then I think to ask this question - if it makes sense to use this logic to preserve other white space formatting, why would the DOM not just happen to use the same sensible rules? So I comment out all the code I just wrote, and add essentially 2 lines of code to delete the context attributes from each Macro tag in the DOM immediately after expansion, and it works! More tests pass now than were passing when I left off with the text-based approach, so I just delete all that code.
At this point, only a few tests were failing - the ones that test for what XML to get after parsing code into an XML document module are new failing because they weren't expecting to see the new context attributes. I could have changed the tests to match the new output, but I figured those tests should not really care what extra context parameters get added later, so I added wildcards at those points in the test data, and changed the tests to use Like instead of Equals to do the compare. VB Lite Unit doesn't have an AssertLike, so I wrote one in the project.
Finally, now the tags have the metadata we need, and we just have to pull it out when expanding the macro. By now, this was totally trivial. Just get the macro definition body from the collection into a string, and replace all instances of each context parameter with the data from the matching attribute from the Macro tag at the expansion point. It works - all the new tests pass - hurrah! There's a small amount of duplication here, and there will be duplication in the future with what custom parameters will do, but for now, it's not enough to be worth fixing (the cure would be more complex than the disease), so I call it done.
What's still left to clean up later is that, now the methods that take text as input for parsing exist only to support testing with plain text, and they should probably be moved out of the class, and into the testing code. I made to-do notes for that because it was getting late, and time to quit.
Observations from the "Context Parameters" story:
I wasted a lot of time implementing a hard solution to a problem, when the easy solution turned out to pass all tests. I could have saved several hours by trying that first.
As I recall, the reason we have been wrapping every code line in a VbLine tag when inserting code into the XML document was so there would be a place to put the context parameter information later. If that's true, that work was for nothing because that turned out not to be the easiest way to get context info into XML where we needed it. We ended up puting it right into the Macro tag's attributes instead.
The better "XP" approach to coding for this story would probably have been to start from the other end of the code, and "fake it till we make it", before we even wrote the module line reader, etc., that we were "going to need [my quote, I'm afraid] to be able to get context information from the VB IDE". We first would simply write a test that expects the correct module name and type for a single procedure, hard code that procedure name into the macro expander, and make it work for the first test. Then we would have refactored that back up through the process to remove duplication. What we ended up with works, and seems sensible enough, but it we've had to take bigger steps in between tests, and we may have implemented several things that turned out not to be needed in the eventual solution.
At this point, unless someone can remember another reason why we wrapped all the code lines in VbLine tags, we should now actually take all that back out.
Observations for the session:
If I ever had any doubt about whether pair programming was at least as efficient as working alone, I don't have it anymore. Clearly, any time that would be "wasted" by having 2 people working at one computer with only one typing is more than outweighed by the number of times having a second perspective would have prevented doing unnecessary work or taking a harder path. That's in addition to the more obvious benefit of having one person able to think tactically about the lines of code being slammed out while the other keeps an eye on the bigger picture and can monitor when the "driver" is getting tunnel vision that could eat up hours on some trivial or off-topic item.