Read this post-mortem fresh from the source, the project manager on Robot Rock. Robot Rock is an open-source interactive music framework built in 11 weeks by 5 UW undergrads for CSE 403, a software engineering course.
The Pragmatic Programmer
How To Win Friends and Influence People
At the beginningYou are the one to set the tone. Work as hard as it takes to get the project off the ground, and demonstrate what your expectations are. The sooner you demonstrate that the project could be a success, the sooner you win the rest of the team's dedicated efforts, and you can't get far without that.
This is the time for experimentation--it will never get easier to test out different concepts!
For example, Robot Rock started with separate demos of drum sounds in a loop and a trivial non-functional UI. Mashing these together was a major milestone and morale boost, demonstrating the fact that all of our technologies can live and work together in the same environment in a doubtful time when we still struggled to set it all up.
It also provided a tangible way to demonstrate that a lot of the hard work was already done, and was useful for settling disputes through experimentation instead of abstract arguments (for example, when designing architecture based on the performance limitations of our libraries).
Establish regular meeting times during the week, and hold onto this inertia. Meeting often is the best thing your group can do.
Don't think of yourself as any sort of authority, think of yourself as the sniffable glue keeping your team happy and productive and it's up to you to figure out exactly how to make that happen! If you read Dune you know that as soon as you start giving orders, people stop acting autonomously, so don’t command, lead instead.
TestingWrite lots of tests in the beginning, but keep them fairly general/flexible since things will be fairly tumultuous at the start and tests will die quick and noisy deaths.
You need the tests for just two purposes: to verify and enlighten. Tests help maintain confidence and momentum, and allow you to breath easy knowing that you aren't breaking anything as you hurtle with breakneck speed through the rapid development which takes place after the design is settled. Of course, with all this code, you need a way to demonstrate what it all does. Tests are a great way to communicate to your team mates how to actually use the code you're writing.
Don't let tests prevent refactoring--accept that you will have to some tedious effort fixing them up. If you hate the thought of this, don't go hog wild writing tests for things likely to change, and write professional tests which don't have lots of repeated code.
Don't leave your tests broken.
PlanningAssembla is a hugely valuable tool. It integrates a ticket system, file hosting, milestone tracking, wiki, and repository with online code browsing.
Use the wiki to maintain your documentation and deliverables. Use the milestone tracking to organize and shuffle your tickets around in time.
As soon as you think of something that needs to be done, create a ticket for it.
DesignSo, you're in 403, which means you're writing code for 11 weeks, then throwing it away, right? There's some truth to this, but if you write ugly code you can't use it to convince people to hire you. Often job postings require an example of code you've written to solve a non-trivial problem, and so this is your chance to shine to all future employers.
There are a lot of general things which constitute a good design, such as modularity, simplicity, modules which are decoupled, interfaces, etc.
This isn't really about bad design/good design though. You want a design which will make your high level goals natural to achieve.
For example, we knew at the start that it was critical for Robot Rock's music to feel very responsive and sensitive to user manipulations.
We also knew that we wanted the audio generation to have no influence over the rest of the design, in case we wanted to drastically change the way we generate the actual musical tones.
From these first principles, we could evaluate each potential design (everyone came up with a rough design as a homework assignment) and examine if it allowed for real time responsiveness, as well as decoupled abstract song data from the underlying generation. Once these requirements were met, we went on to examine other more general qualitative characteristics, such as separation of components and simplicity.
If we started with an arbitrary design goal, such as simplicity, we may have locked ourselves into a design where real time responsiveness was anything but natural, despite whatever other elegance is achieved. In other words, we would have picked A Good Design, but it'd be The Wrong Design.
FeaturesBuild the simplest thing that meets the requirements.
If there's a feature you want to add, consult your users first. Make a prototype before investing the time in something which the user may not actually care about.
No optimization until feature complete, or later even.
Understand when code is good enough...I'm just parroting The Pragmatic Programmer at this point, so just read that instead.
Grow ExpertsAssign each group member an area of ownership. It doesn't have to be something they are familiar with, just something they care the most about ideally. There should be no part of the project without an associated leader. Everyone can just refer to this person for questions, and it will deepen their understanding of the respective area. It also provides resume bullet points.
Not everyone will have the same knowledge level of the languages you use. It helps to have at least one person experienced with each language utilized, and they should oversee code reviews with the less experienced members, at least during the initial stages. It goes without saying that the instruction and learning are the crucial goals for these code reviews, never judgment.
TeamworkI forget where I read this, but the difference between a team and a group is that a group all leaves a meeting at its deadline regardless of where things stand, whereas a team will stay as long as it takes to get things to a satisfactory point.
In practice this makes no sense. Sometimes people really do have to be somewhere at a certain time, and sometimes despite your best efforts, you have to force a less than ideal resolution. But the idea is not to leave things open and unresolved at the end of the day. Make some sort of plan for the next session, or if someone can stay and play cleanup, they should and earn the gratitude of the group. Make sure it's not the same person every week.
Get the entire group involved. If someone's quiet, explicitly invite them to weigh in with their position. Assign homework to the whole group to prepare a decision on items which affect the overall team course. Send around status updates during times when everyone's too busy on different areas to meet.
Code and documentation is communal. If any problem is found, it's your problem to fix, regardless of its origin. No drawing territorial boundary lines, if it's someone else's code, take it as an opportunity to learn about its inner workings.
When Conflict OccursLet everyone speak their minds, and focus on the ideas, not the person.
Try to be the first to find and acknowledge the weaknesses of your own idea, and the strengths of each opposing idea.
Find common ground. Find and point out things about ideas you disagree that are positive, and be sincere.
If the discussion drags on, put it to a group vote. Once the group decides, that's it, no revisiting the topic until taking action to make things work as they stand.