Reconciling contradictory programming advice: get something working and iterate vs. really think it through before coding

softwareengineering.stackexchange https://softwareengineering.stackexchange.com/questions/213972

Question

I am an intermediate programmer with a few years of professional experience who is halfway through a masters degree. In learning to program I've often heard two pieces of seemingly contradictory advice.

The first piece of advice was get something working quickly, see how it works (either through prototyping or informal testing), improve the version , see how it works again, improve it again...and then repeat the cycle until you're done. This is sometimes called "spiral development" or phrased as "release early, release often."

The second piece of advice was: really think a project through before ever writing any code.

I've had success with both methods and I would say that I agree with each philosophy.

But now I'm starting to tackle much more complex projects that I have no idea how to complete (like distributed applications and performance-driven graphics programming).

How do I go about these projects?

Do I just start coding SOMETHING and learn (platforms/methods/languages/architectures) as I go -- or do I hold off from coding and do a ton of research/reading before I even open the IDE?

How do I reconcile these contradictory pieces of programming advice?

Was it helpful?

Solution

I'm not sure that thinking about a problem ahead of time vs. iterative approach are contradictory to each other. Just like many other things, I think you should strive to achieve the balance between the two. How do you find the balance? That's something you learn with experience and often time best lessons (i.e. stuff that gives you experience) is when you don't get it quite right (or even better lesson: just flat out get it wrong). As you already pointed out, there's a saying "release fast, release often". There's another similar one, "fail early, fail fast, fail often"

Thinking ahead is great and you should absolutely do it. But with experience, learn when to stop thinking and to just build something even if you don't have all the data. By building it, you'll be able to gain more insight into the problem domain and potentially come up with a much better solution. So I'd recommend don't exclude one from the other but make "thinking head" part of your iterations and over time I think you'll find the right answer to this question yourself.

Just a little example. The other day I was struggling with a software design decision. In hindsight it was relatively trivial but I had two alternatives and it seemed like both of them would work. I kept circling back to pros/cons of each one and then circling back and reconsidering my decisions. Looking back, it's a bit embarrassing how much time I spent thinking. Then I said to myself, f#@k it! And instead of using either one of the designs, I just went ahead and hacked some code together, completely ignoring all good stuff you learn about good design. I got the feature working in about 45 minutes. Then I went back, looked at my code and refactored it into something solid and something I wouldn't feel ashamed about checking into source control. The funny part is that after I got the hack working, to come up with "proper design" took about 15 minutes.

Another thing I'd recommend specifically for problems you are facing now (i.e. large, complex task looming ahead). Instead of doing things in serial, do them in parallel. Break up your day into chunks where you do research and then stop, switch gears and code for a while, at least on parts of the project which are not complete unknowns. This way staying close to the code will give you better perspective and you won't burn out by attempting to absorb too much information too fast. For me at least, after few hours of research, it's good to let the brain digest stuff, switch tasks and do something else for a while. Then come back to more research.

OTHER TIPS

There are certain decisions that need to be made ahead of time.

Are you making a web application? Then you need to know what the overall architecture is going to look like. Architectures like MVC already define what your large functional pieces are going to be (like routing, controllers, models, service layers, communication protocols and so forth); inventing all that from scratch is going to be a long haul, unnecessary, and probably inferior to that which is already invented.

Are you writing any kind of application that involves collections of objects or data? Then you're going to need to know about which kinds of data structures are most appropriate for your particular scenario, and what their performance characteristics are. Do you need fast lookup time? How about ordered data sets? Will an in-memory collection do, or do you need something more industrial-strength like a database? You can't just begin coding without thinking these decisions through, because if you make the wrong choice, you'll have to start over.

That said, once the technological decisions are made, you have freedom within the framework you have established. The goal then is to remain flexible, iterative and (dare I say) agile enough so that when the customer changes his mind about what they want, you can accommodate them with a minimum amount of fuss.

How do you do that? Experience, mostly. As someone once said, experience is what you get right after you need it. But if you follow the successful design decisions of others (as embodied in the platforms, libraries and other tools of the trade), you can learn from them and reduce your risk.

I don't view the two as mutually exclusive.

Like any sort of project management you need both a long term vision and short term goals.

Without the former you'll end up wasting time for example on features that may never even be used and without the latter you'll spend all day considering how to create the perfect application without finishing your project.

How often you release/etc. depends on the specific methodology you are using.

What you have to research depends on what you know versus what you are not comfortable with.

"Iteration" and "thinking it through" are not contradictory, instead they are complementary.

Even at their extremes, they reflect two paths to get to the same place.

  • The extreme of Iteration is a thousand monkeys banging away at a thousand keyboards. With enough time maybe you'll get something that meets the requirements.
  • The extreme of "think it through" is a Waterfall approach. If you're lucky the requirements haven't dramatically changed from the start of the project by the time you deliver code. Or you'll just end up with analysis paralysis and have delivered nothing.

You have to have some understanding of the domain and the problem before you start coding. This is the "think it through" part. Ideally, you'll see the high level path from beginning to end on how to solve the problem.

But you may only see major portions of that path, and certainly not every stop along the way. That's where iteration comes into play. You can start iterating through versions of the application and seeking feedback in order to:

  • Identify the roadblocks that come up in the lower levels of detail
  • See stakeholder feedback to clarify those murky areas in the high level path.

The latin root of decide means to "cut off". Iteration allows you to decide what works in practice instead of just theory and iteration allows you to cut out the other options that aren't feasible.

So you have to think the problem through in order to understand what you're going to do. But then you need to iterate through versions of the application in order to actually transform the idea into actual code.

My rule of thumb: if you don't fully understand any part of the problem you need to step back and fully think it through (I include prototyping and throw-away code to understand APIs etc. as part of "think it through"). If it's basically a collection of problems that you've solved before and you just need to figure out the best way to fit everything together in this particular instance, then iterate.

Honestly though, that's not a hard and fast rule. I really think you need to do a mix of both for any given project. How much of each you do is probably going to mostly depend on how close the project is to one you have already completed in the past.

Licensed under: CC-BY-SA with attribution
scroll top