Don't do big projects. Small ones have a lot more chance of success. In a small group, people are more likely to understand the overall requirements and architecture, so they understand better how their work fits into the whole thing. They don't need the heavy documentation and process of big projects, and they can change direction more easily when the requirements change, as they inevitably will. Agile methods like eXtreme Programming, SCRUM and DSDM have proved very successful in improving the reliability of software production (if they're adopted properly!); and they all rely on the project being a small one.
So the big question at agile conferences tends to be "How do we scale up? How can we apply these eXtremely successful agile ideas to real-life big projects?"
And here, folks, finally, is the answer: Divide your big projects into small independent ones.
OK, so we've always divided up big projects. But there's a particular point about the "independent". Less facetiously, I should write: Develop a big project as a Software Product Line.
A software product line is a family of related software products, created from a coherent kit of components. Think Lego, Meccano, electronic components, auto manufacture. Each Lego brick is designed not to fit only into a single end design, but into many. Automobile designers don't just design one car: they design a family, which will share many of the component parts.
In a traditional modular project, the designers of the separate modules should be independent of each others' implementation details, relying only on the interfaces defined between them. But they are strongly dependent on the overall requirements on the whole end system: when the system requirements change, the designs of the components usually have to change too. Because of this, the design of the overall system is still a 'big' project, in the sense that a lot of people have to be co-ordinatated in order to make changes.
In a software product line, the component designers and the overall project are less interdependent. The designers of Lego bricks or transistors don't know what the end-product buildings or radio sets will look like. The designer of each component doesn't know what other components theirs will be coupled with in the end-product assembly. The architecture of the kit is such as to allow many ways in which the pieces can be interwired: the pin-spacings or the voltages are standard across the kit. A change to the requirements on any end-product is unlikely to change the designs of the components.
Many product lines are a compromise between the generic and the specific. Car parts are generally produced to fit into particular places in the car, but can often be omitted or not, or subsituted between a small range of alternatives. End-products usually use a few specific parts -- such as the outer body -- together with many generic ones. Some parts are generic across the whole manufacturer or industry, and some only across a family. The design is as generic as it needs to be, but not more so.
Now of course, there's a cost to generalising a kit of parts. Designing a flexible kit of Lego bricks takes a lot of careful thought. So in general, the product line approach is most cost-effective for teams who do intend to produce many variants on a theme. The typical case is where a software design house has specialist expertise in a particular domain -- insurance or GIS or mobile phones -- and they want to be able to produce a wide range of products, customizing them rapidly for different clients.
But software designers are always working with a family of end products, whether we intend to or not. Requirements change, and so the system you aim to create near the end of the project is rarely exactly the same as you were aiming for near the beginning. The members of the family are all the versions that the requirements went through whilst the design was in process. The bigger the project, the more changes there are likely to be.
So we should approach every big project as if we intend to design a family of end-products -- not just one thing. The aim is to reduce dependencies: not just between components, but between the overall requirements and the component designs.