Yes, you will not get it exactly right the 1st time.
Just like I did with my answer. I completely erased it after writing some 5-6 paragraphs, because I came to understand that my chatter might be answering your literal questions, but it was not really soothing your actual troubles. So I took a different path instead...
What counts as an iteration is almost always dictated by the task(s) at hand. Iterations of larger projects may last months on end, while smaller projects might benefit from weekly iterations. Sometimes you may find yourself improving the design on a daily basis. Make sure you have a realistic timing, otherwise, you end up changing the design too often and this will wear you out in the long run.
"Right" can be very evasive when designing... requirements change, and you will have to adapt your design at some point, regardless of having gotten it right previously. Yes, the process of design often starts out with a "requirement volatility" handicap. Try to discuss and negotiate what "right" means to you and all people involved in the process. Agree on the level of "rightness" you are all going to accept, so that you know approximately what you are aiming for.
You are not designing a system just for the fun of it (and chances are neither just for your own personal use). More often than not, you are creating code that actual people will use to achieve a desired task. Figure out the standard task (e.g. they want to quickly and easily convert documents to PDF files), make some perturbations to somewhat "amplify" the required functionality, so that you can err on the safe side. Be reasonable, for example it is reasonable to assume the users might want two-way conversion capabilities, or opening the converted file automatically in the end. It is not reasonable to expect that the user would want to make edits to the converted PDF files, that would be a different program, with different needs. Don't be hard on yourself, you can always enforce (reasonable) limits to what they expected.
- Find the junctions and shape the unknown.
Remember how, sometimes, your favorite development environment and APIs don't really hand you what you would like directly out-of-the-box and you have to write some really dirty code to prevent the MouseDown
handler from re-selecting your item on a listbox, while your manual code actually unselects it if it is already selected and you click on it? Notorious methods running two different code paths based on a passed bool
argument, one with a default value no less? Or would you prefer to feel the pain of manually doing dynamic dispatch by checking types at run-time? Some huge if-else branch chaos?
While I hate to downplay such important stuff, my point is that those are not your actual design problems and, still, they are quite representative of what you come across when you hear software developers complaining about what a big pile of mess part (or the entirety) of a codebase is and how it needs to be re-written. Your actual problems are bigger, but you can protect yourself easier. The real trouble comes from not building abstractions where they need to be, so that you can, at least, redirect the code to your very own "safe-houses", where you can play your dirty little tricks.
Junctions are those connections in a design, where you might want to do things differently, based on circumstances. The most typical example is the coupling of the GUI with functionality. The job of the Graphical User Interface is, typically, to redirect user interactions to you. This is a perfect example of a junction. Upon receiving user input, you can either couple the interaction to a single code path doing something very specific, you may, instead, define a junction, where you do different things on different occasions.
By "shaping" the unknown, I mean that you need to determine most (or all) holes of your design. And this is where it becomes an oxymoron... The art of designing (in my opinion, of course) lies not in knowing where you are stepping, but in knowing where you are not. So you have to decide and document the parts that you will never ever get to know adequately well, i.e. the parts that may be mobile, volatile, if you will. Which brings me to:
Design a screwdriver. You need to hold it with the hand and screw/unscrew, so you need a piece that goes into the head of the screw, and a rigid body (to withstand torsion), as well as a large part to apply a firm grip. Unless you are designing a screwdriver that needs to be held with something other than a hand, your grip does not really need any significant flexibility, it's a big strong block of material, prolonged, suitable for tight holding. Human hands are not that different after all.
Screws, on the other hand, have multiple different fits, lots of different cases indeed. Therefore, the part at the other side of your screwdriver, if you only design it with a specific shape, you are really only covering a very small range of your requirements and you will need to build another screwdriver with a different head to serve an additional part of the requirements. So, instead, make this piece undefined, build a hole. Create a screwdriver with a hole and expect that, somehow, a head will be magically fitted externally. I think you are getting my point.
In short, to ease the pain of iterations:
- Try to "need" less of them by...
- Finding the important things (junctions and holes) and only worrying about those. Don't let other kinds of problems get to you while designing.
- Focusing on your user stories to know what you are dealing with. If you don't have user stories, or haven't talked with someone that will use your system, stop designing. Imagination is rarely a good guide, we tend to go crazy when left alone designing our "dream system". Be real, talk to potential users, acquire user stories and build on those.
- Creating enough holes to make your design adequately flexible. Changing the implementation plugged into a hole is not an iteration; yes, functionality may change, but your design stays the same. It's good and adaptable and amenity to such changes is a wonderful attestation to that precise fact.