We just handed in Iteration 1, and there are more iterations to come. Here are my thoughts on how this first installment of our group project came together and how it failed to come together. If you've ever seen the movie "The Pursuit of Happiness" with Will Smith, you might remember a number of scenes when the main character, Chris Gardner, had to do a lot of running. He was expected to run for coffee, make it on time to an interview, run down this and run down that. At one point, when he was trying to make a key appointment with a high-stakes client, he was asked to park the bosses car on the street in downtown Manhattan during daytime traffic. Needless to say, he missed his appointment. You may have seen this film, but we lived it during our Iteration1 development cycle.
What were the things that caused us to miss our deadline? What can we do differently, so this does not happen again in subsequent iterations? The answer to these questions, for us, involves doing some things differently, but also, it means just sticking to our guns on other things, and not doing them differently. Here are the strategies I am recommending.
Continue to work toward a division of labor
Pipelining needs to occur if we are going to get things finished on time. What I mean by this is that if we did everything in serial fashion, not starting the next thing until something was completely done, there would not be enough time to finish. It would be the worst of both worlds: no gain in productivity from two people working together, and neither of them going as fast as they could go on their own, because of the need to explain too many things to each other.
People working together are able to do more when they work on different tasks. This is why I felt no guilt about having each of us do things that required only the skills related to our unique individual strengths. I tended not to be very good with the regular expressions, and I am new to Make, but I know my way around code constructs and am very well versed in C++. We divided the work accordingly.
The advantages of working in a group are clear: we can draw on each others knowledge of the subject areas, and we can cut the workload almost in half (with teams of two people) if the various tasks can all be performed independently.
Another advantage to dividing up work is not quite as obvious. When people work together, I have observed that shortsightedness becomes more of a tendency. When people are intensely collaborating, and there is a lot of interaction, human nature begins to become oriented toward performance, and possibly toward proving that we are competent and valuable to the team. While this is, admittedly, something that is personality dependent, and not universal, working independently avoids this dynamic.
I first noticed this when I was working in the construction industry. People working together in a group often engage in a mad dash to be the fastest man on the job, but they, as a group, tended to neglect mission critical things. In short, assigning people to separate tasks is one way to give everyone a little bit of breathing space, and they can step back and plan their work more carefully. Without leadership and planning, this psychological tendency becomes dangerous.
Avoid half-baked plans to split up the work
Half-baked plans in a collaborative effort can spell disaster. We found out what it is like not to divide the work up into distinct parts. The fact is, for many of us, we do not have schedules that allow us to work together at the same time, at least not enough to complete a project iteration. We found that we needed to work on this group project at separate times. Having a hazy notion about working on different parts of the program, and not communicating about that specific issue, made it very difficult when we tried to work independently.
The worst thing that started to happen was akin to the dresser drawers popping open in a slap-stick comedy; whenever a person tried to shut one drawer, another would pop back open. That scenario can easily start to happen when you are working without immediate verbal feedback. You may be trying to shut all the drawers when your partner is trying to pull them all open. This is easily remedied by the rule that you leave comments when something is not totally obvious. This is not necessarily a hindrance to division of labor, but it is a risk that comes with working separately on the same code base when your communication about working on separate portions of code was inadequate. Having inadequate plans then becomes a pseudo-reason to avoid working separately.
I think the very thing I was afraid would happen, did happen. The fear was, even though I had worked on the basic framework of the solution and had left it the night before in working condition, it would be tampered with and then no longer be functional. That did happen. On the other hand, I did this same thing to my partner, in a more egregious way. I left things so our core processing loop inside of "scan" did not even execute because it began with "while ( 0 )". That was a diagnostic trick I was using so that I could determine what part of the code was generating segmentation faults. Why I went ahead and did a "svn commit" with that still in there I do not know. My partner was not too happy about this.
Recognize illusions about not splitting up the work
There are some fantasies that cause us to think about not ever working separately. Some of these are true for one team but may be completely untrue for a different team. Other illusions are illusions across the board.
Consider first that these illusions can stem from a legitimate understanding of some things. For example, we might rightly observe that there are huge benefits to working side by side, and then get an unrealistic hope of always working together with perfectly synchronized schedules.
There were numerous reasons to work together in lock-step. Working together, literally right next to one another on separate machines, we could confer about things easily. We could get a sense of when the other person might be holding back when they had an idea but were just being polite or something. Not only this, but also when we tried to work on things without being able to have that immediate feedback, it was a very difficult process. We would not be able to find the changes made by our partner that Subversion did not mark. At other times, we would have to deal with "ugly" merges, the kind where you needed to find out what was going on and compare notes, and then make a decision.
All of this provided us with a motivation and with a temptation to not use our potentially super-productive, face-to-face time wisely; in other words, to do planning, when we needed to do it. We may have bought into a falsehood that said that we could complete the project without a plan for how to work independently.
A second illusion said, "I can't work on this sub-component without having the processing loop working." This belief did not involve our physical location, so much as the location in the source code that we worked on. What became apparent is that we did not understand that Test Driven Development (TDD) does require us to write tests for smaller components. The "scan" function's main loop did not need to be finished nor even did it need to exist before we ran tests on the regular expressions. The test-driven approach did require writing some extra tests, but the same division of code that would have resulted, could also have been a basis for division of labor.
Intentionally deal with problems specific to working separately
We would have been much better off if we had taken time to clearly set out our goals. There were times when we would have benefited greatly by having an outline of what needed to be done, and have a person's name with each task to designate responsibilities.
Another thing that might have helped us is to make a list of high priority items. We did have a to-do list that we sent to each other by email. Sadly, handing in our work was not on the list. It doesn't seem like that would need to be there, but perhaps, here we might learn from NASA. They go through months preparing for a launch that takes a few-second countdown. The launch sequence has been decided upon far in advance of the launch date. We should implement the same thing. NASA also identifies a window in their calendar. They try to schedule their launches as early on in that window as possible, not just waiting until the last possible moment.
Another strategy that we should incorporate is to deliver a partially functional, bare-bones product so that we know that we can at least get full credit for some basic things getting handed in on time. Not having anything in the tags directory until ten minutes before it was due was unforgivable. What is even worse is having been that close to the deadline and having not understood how to submit our work inside a "tags" directory. This is not Will Smith, missing an appointment, this was Laurel and Hardy, or maybe even the Three Stooges (minus one stooge).
This leads to the question of control or leadership. We never made any kind of conscious effort to decide on a "leader". In my opinion, we both took turns being a leader and being willing to follow the other person's ideas if they had a moment of inspiration. The downside of this type of informal relationship is that there are times when a person might need to assert more 'authority', or at least be more inflexible when something critical is being missed and time begins to run out. This happened to us. I was very concerned about getting a tags directory made by whatever means possible, manually or by running tagit. It was ten minutes from the time Iteration1 needed to be turned in and we had not done this. My partner was trying to get our Makefile working right. In the end, I feel that neither of us really knew which was worth more points, getting a tag up on time or getting the Make file to work. In retrospect, the tag was more important.
One final idea, that I think will help us work in a coordinated fashion, but not crowd each other on the field, so to speak, would be to make some type of journal. Our professor made a very important point in saying that people who don't do something because someone else seems more qualified to do it, will never learn what is required in order to complete that task. (This is my own paraphrase of an approximation of what was said in class). A journal containing just a couple of concise entries about the key hurdles or issues that needed to be overcome could help the other team member stay abreast of what they need to know, in order to do the entire project themselves.
By way of summary...
Looking ahead to Iteration2, I feel that we can be successful if we continue to try to divide up the project tasks and also try to mitigate the problems that come with division of labor. The administrative measures I have talked about should help us do this.
Even though looking back,I can see how I've grown a tad bit, in my knowledge of Concurrent Version Systems (CVS) technology, software development methodology, make files, pointers, debugging, testing, and working as part of a team, It feels like we can do better. With the introduction of "context free grammars" and trees, I expect that all of us will be doing a lot of running, once again, in a mad race to the finish. I hope some of the advice I have offered here can help more of us get to the finish line on time.