I’m afraid I don’t have any links. I can give you a feel for some of the problems that can crop up(and let’s hope I don’t end up conflating Agile with Extreme Programming)
Agile requires a very short development cycle. This is not appropriate for a lot of projects. Half of a feature is not always useful to the customer, and if you’re delivered half of a feature to the customer, you’ve probably committed yourself to maintaining that half-feature for all-time, even if you discover while completing the entire feature that the half-feature was ill-advised. Your development methodology can be as agile as you like; you can’t assume the same about your customers. If you can’t assume that your customers can deal with rapid change, then you need to limit your release schedule to protect your customers from change.
Another problem with a short development cycle is that it’s riskier. The faster your development cycle, the faster your code goes into production, and the higher the chances that a bug will sneak through your internal testing and only show up in the wild. If your customers are unwilling to face this risk then your development cycles must be longer.
Agile development assumes that requirements will change often and change can happen at any point in the development cycle. This is more true when you’re developing a custom application for a single customer. If you’re developing a single product for a lot of customers then it’s likely that no single customer will have very much of a say in the requirements, which means that your requirements can evolve slowly over time. Without the need to deal with rapid change in requirements I don’t see a lot of value in the Agile approach. This is one example of a situation in which delivering half of a feature might not be that useful: if one customer wants feature A, one customer wants feature B and another wants feature C, you’re much better off to find a general solution that subsumes all three features than to implement all three separately: that way, when yet another customer needs to solve a similar problem, you can point them to your general solution rather than coding a new custom solution. Again, when there’s only one stakeholder involved and it’s a custom system, feature requirements can be much more specific and providing the general solution might well be a case of overengineering.
My biggest gripe with Agile, though, is definitely the idea of that you should intend to throw your first iteration away. Let’s set aside the enormous pressure there is to release any working piece of code. The real problem that I have with this attitude is that it’s completely backwards. The moment that you think “this code needs to be re-written”, you probably need to re-write that code immediately. If the code is a contained within a single module, you might get away with leaving it there. But if the part that needs to be re-written extends to that module’s interface, the code has to be re-written immediately, because the longer that the bad interface is there, the more code that will be written against that interface, and the more painful the eventual re-writing effort will be. It is very, very easy to get yourself married to a kludge, and then you’re really in trouble. You can’t do a re-write because you have too much time and effort invested in the kludge.
And so if you’re starting to code with the thought that you’re just going to re-write the code anyway, you’re already at the point where you know that the code is going to be re-written, and any further effort is going to be wasted. Sit down, take some time and design it ahead of time. If you get stuck in analysis paralysis, de-scope until you can handle your requirements, and put together a design with an aim towards extensibility, and then code it up. Once that’s done, you can start adding more requirements back into the system. If you discover that any part of your design was flawed then discard that part and re-write it, but do your best to make those re-writes as painless as possible by designing things up-front. I really believe that much of your coding should be an almost mechanical process. Be prepared at all times to re-visit your design, and there are times when you have to test your design by coding it and seeing how it fits together. But if you don’t have a design in mind as you code, the result will be a mess.