At the Leiden Institute for Advanced Computer Science (http://www.wi.leidenuniv.nl/CS/) we have a one year IT course for people with a nontechnical background. As part of that course we have a five and a half week long practical course on software engineering. This year we are going to follow the ExtremeProgramming practices.
My boss is going to be the customer. He wants a simple management information system. Our thirteen students are going to be junior team members, four teaching assistants will be senior team members and I'll try to be coach.
During the first week we'll do the PlanningGame and some hacking to come up with decent estimates of IdealProgrammingTime required and our LoadFactor. In the remaining four and a half weeks we'll do three iterations. After that the teaching assistants and I will probably finish the project ourselves.
If Ward agrees, I'll keep a log of our progress on this page. Later on I can perhaps put our CVS repository online.
Could I ask the OfficialXpPersonnel for advice? I'm wondering about the following questions:
Are iterations of 1.5 weeks too short? Because we have a course on network security at the same time, the students will probably work three to four days each week. So the iterations will effectively only be 0.9 to 1.2 weeks long. We have decided to use 1.5 week (5 working days) iterations. We'll let you know how it works.
Somewhere on these pages it says that user stories are estimated as one, two or three weeks. Engineering tasks take anywhere from one to five days. Are these numbers related to the length of the iterations? I'll try to answer my own question. If you break up UserStories into EngineeringTasks to get early feedback on your schedule, the estimated length of the tasks must be small compared to the length of the iteration. You can also break up UserStories because you want to work on the EngineeringTasks in parallel. Then you must make sure the length of every task is less than the length of the iteration divided by the LoadFactor. If you don't break up UserStories, the same condition applies to the stories.
Should the senior team members sign up for tasks? Especially in the beginning they'll be busy teaching the extreme practices to the people they team up with. Perhaps it is better if they work with as many junior members as possible.
Most of the senior members will only be present for one or two days per iteration. We've decided that the senior members will not sign up for tasks themselves. We'll let you know how this works out.
Thanks.
August 6, 1999.
Well, the first week is over. We've learnt a lot from talking to the customer and everybody is enthusiastic about the project, but we're also eager to stop talking and having meetings and start programming. I think people are reasonably willing to follow the extreme practices. They did make jokes about not thinking ahead and about Standup Comedy (StandupMeetings).
The PlanningGame didn't go as smoothly as I had hoped. My boss didn't like the cards at all. He felt that I should be the one writing them. Our initial batch of cards wasn't very helpful as we found out during exploratory programming. We talked about this and decided that I would try to write a couple of cards and my boss would fill in the details. I believe the new cards are better than the old ones. Still, my boss couldn't easily make decisions about which stories we should do first. He felt that we asked him to make decisions with insufficient information of the effects. Also, we found that some of the cards weren't independent so we couldn't schedule them independently. In the heat of the action I forgot about WorstThingsFirst. Fortunately I don't think we put any risky story off. We agreed to do more work on the cards next week.
An amazing thing happened during the PlanningGame: we didn't have enough stories to fill our CommitmentSchedule. According to our initial estimates we only have 1.5 iterations worth of UserStories. We'll have to wait and see how that works out.
We mostly failed to follow the extreme practices during the spikes. We did do PairProgramming for our spikes, but we assigned certain tasks to more than one person. This made moving people around hard. The spikes weren't done the XP way. Only one person refactored and tested. We didn't integrate our code. We didn't make estimate tasks. Communication with the customer isn't ideal. My boss is trying to stay as closely involved as possible, but he's very busy. Our project leader can only be at the university for one day each week. The rest of the time we have to communicate by phone or email. This isn't ideal, but it's the best we can do.
August 16, 1999:
Some things are starting to go wrong. People are spending large amounts of time in Borland C++ Builder without making much progress. I knew about ModelFirst and SpartanUserInterface, so I could have seen that one coming. I should have warned people more clearly.
Some people complain about having to change partners once a day. I tried to show them how to work in very tiny steps and code unit tests first so they can switch to another task at a moment's notice. Four of the students are beginning to understand how this works. I hope they'll pick it up quickly and can start teaching others how to do it.
Some people still work alone regularly.
We don't have AcceptanceTests yet, but we do have drawn examples of the various screens. The project leader and I will turn these into AcceptanceTests on Thursday. Looking back, I think I should have sat down with the customer much earlier on and made sure we had good AcceptanceTests.
On the positive side, we now know how to talk to the Oracle database via OCI from C++. Now people can start UnitTesting their queries. One pair has started writing tests for their queries. Up till now, all we could do was enter the query into a file called schema.sql which everyone was supposed to run from SQL*plus after each update from CVS. This way we couldn't automatically check whether the answer was right, only that it didn't reference any fields or tables that didn't exist.
The data input from SAP also works fine.
Overall the people who weren't working with C++ Builder have done best. They've written code composed of tiny functions, made an effort to come up with good identifiers and have written unit tests.
We have code in Visual C++, C++ Builder, SQL and egcs on linux. The Visual C++ code is combined into a single executable for running tests. It uses rsh to make all linux code and run its tests (this doesn't quite work yet). It also runs the schema.sql file which update the current user's schema. The Builder code consists of two executable, a GUI and a testing executable which does the same thing (and uses the same code) as the Visual C++ executable. This way it is easy to make sure that specific modules are portable. Once the linux integration is complete (first thing wednesday morning) we should be able to work safely on different platforms.
September 10, 1999:
The practical course is over now. As a course it was very successful and everybody was very enthusiastic about it. The product however isn't in a workable state yet.
The PlanningGame didn't work for us. Looking back we now know that we knew far too little about C++ Builder to be able to give reasonable estimates of how much time we would need. We should have done far more exploratory planning. Also the customer couldn't make it to any (!) of the iteration planning meetings.
PairProgramming was reasonably successful. I had asked the students to switch partners once a day and to work on their task and that of their partners. People found it hard to work in very tiny steps. This meant that people didn't work on both partners' task.
MercilessRefactoring. I believe you can only teach this by example. Only a handful of students really cleaned up their code.
RelentlessTesting. We had automated tests for all SQL queries, but they were usually written after the query itself and only tried the queries on one set of data. The C++ code also had some tests, but not as many as I would have liked.
IncrementalDelivery. Only the last iteration resulted in (half) working product.
AcceptanceTests. The customer did write customer tests, but we couldn't find the time to write an interpreter for them.
After a short holiday I'll finish the product, probably on my own. The first things I want to do are to refactor the existing code, to clean up the user interface, to add little pieces of functionality to make the product workable, to make the AcceptanceTests work and to launch a first working version of the product.
I've enjoyed reading your experience report! I think your conclusion is good and you have learned a lot of things. You didn't indicate how much experience you had with ExtremeProgrammming? before you started however possibly this was your first attempt? XP seems like a road that you travel, and the further you walk the more you learn. If you persevere and reflect on your practice you can go a long way!
One thing I noticed in your description is that is seemed that you didn't test uisng a MockDatabase? It's quite desirable to test without using the real thing - the C2 guys talk about doing this a lot. It would have meant you would have had your UnitTests running a lot sooner.
I think you were right to drive home small increments - this is an important discipline. On our project we strive for 15 minute sessions to get things working in a test (maybe 30 mins is more realistic in C++).
The last line is a shame - working on your own is unfortunate, can you not find anyone from the experiment who will pair with you? You learn a lot refactoring in a pair. Its hard to do the simplest things by yourself - its easier having someone to question you (especially those "little pieces of functionality" that you are going to add). If you do end up going alone - there is material on here about how to approach it. Needless to say - sort out your tests first! Then write tests for any new functionality first! -- TimMackinnon
I had been trying XP for about a year. For our compiler construction course I wrote a simple compiler using XP for one. (In case anyone's interested, it's on my home page [http://www.wi.leidenuniv.nl/~mmeijeri]. Right now I'm working on it in my spare time. I want to build it into a Smalltalk-like IDE for C++. When it's finished I'll put it online.
About the MockDatabase. I'm not quite sure what you mean. Everybody worked under their own Oracle account, so everybody had a private copy of all tables. We had a file schema.sql that contained the table definitions. The unit tests automatically removed all tables from the current user's schema and executed the statements in schema.sql. Schema.sql was under version control in CVS of course. So in that sense everybody had their own MockDatabase.
You're right, it's a pity I have to finish the system on my own. I like pair programming a lot. For about three years I had a part-time programming job with my best friend and we always did PairProgramming. It was great. But all the students have left for their internships and most of the teaching assistants have graduated. The one or two who remain cannot work on the project full time.
I think you were right to drive home small increments - this is an important discipline. On our project we strive for 15 minute sessions to get things working in a test (maybe 30 mins is more realistic in C++).
This is one of the most important things I've learnt from XP. Right now I feel that Visual C++ is forcing me to work in larger steps than I'd like (about 15 minutes). So that's why I'm working on this Smalltalk-like IDE.
Just as you must learn to break refactoring into RefactoringMoves, I think you must learn to break coding into CodingMove?s.
One of our students who was working on the Hour Registration user story had trouble writing an SQL query that gave a monthly overview of planned and realised hours this month and cumulative planned and realised hours since the start of the project. The hours had to be specified by project, activity and employee.
I tried to show him to break the problem into smaller pieces:
In most programming classes they teach you to divide the solution into small pieces. From doing XP I've realised it is very important to divide the problem into (very) tiny steps first.
The tricks I used in the example were:
A MockDatabase is not a real SQL database - ditch the SQL'ness for a moment - a good MockDatabase is something that wraps a Vector- the result set you get back is just an Enumeration of the entire contents - this gets you running for a bit - as you just populate your test with the results you expected to get back. Once you get past this, you now need to test queries - well rather than digging into SQL, why not have a Critera object that you pass to your mock database that will do some filtering for you. A simple Criteria might be those customers in City X - you then write all your tests that sum up totals by city or the like (and this Critieria object is a simple one line if statement inside it). When you have gone through all of these things you can then look at how how your Critera could now generate an SQL query (it should be quite simple). If fact you can then test that it can render out the SQL you expect (another nice raft of tests for you). Your database object instead of returning an Enumeration on your collection can return one on a result set. The C3 guys seem to do this kind of thing - where you can switch the real database in and out quite simply. We started on this route figuring we could switch in the real database and so far we haven't had to - the number items has never justified the database (you can put quite a lot in a Vector) although one day the real story for the database will come in. For now we don't need it. -- TimM