Poll: Write elegant code, or solve problem quickly?

6 points by BigCanOfTuna ↗ HN
I really like to solve problems as elegantly as possible, while others on my team like to solve problems as quickly as possible (with less elegant code).

I know there is a time and place, and it depends, and yadda yadda yadda, but which do you prefer?

11 comments

[ 3.3 ms ] story [ 48.0 ms ] thread
Both. Hammer out a working solution and then refactor to something more elegant and readable later on. On the whole, you're likely to spend a lot more time reading code than writing it.
Design an appropriate interface, hammer out something quickly, move on, revisit if necessary.
Do the simplest thing that could possibly work.
Problem is, how do you decide what is simplest? For instance, if you can make it work by banging out five hundred somewhat convoluted lines of code now, or you could spend a while learning a framework that would make it fifty lines of simple code 500 pages of reading later, which one would you view as "simplest?"
This probably sums it up better than I ever could:

http://c2.com/xp/DoTheSimplestThingThatCouldPossiblyWork.htm...

My personal philosophy is to just get things done, but don't forget you've got to maintain what you write. So I guess I'm kind of in the middle of both camps. I just feel that developers sometimes unnecessarily complicate their work-flow because they want to maximize their productivity; and in between all the hand-wringing, they lose track of what they set out to do.

Thanks for the link, I'll check it out.

I generally lean toward getting it done in the minimum amount of time possible, but with an eye toward maintainability.

I absolutely agree with you about the dangers of trying to maximize productivity. I think that sometimes people spend far more time trying to figure out how to use someone else's wheel than it would have taken to just reinvent it, only to discover that the tires don't fit anyway.

any complex project that i expect to grow and evolve, warrants elegant solutions throughout the codebase where the code is expected to be reused or modified.

that said, the hammer and the forge go hand in hand.

I like to craft an elegant solution, but I should hammer out code quickly.

The "elegant solution" philosophy usually ascribes more importance to our code than it deserves. The reality is that most of your code will be thrown away, and most of the rest will be written and forgotten. There's only a small kernel in most programs that absolutely must be elegant, and usually the only way to find it is to write lots of crappy code first and extract the parts where the crappiness is really getting in your way.

Paraphrasing worse is better: hammer out the code to quickly solve half the problem, and then take the time to improve it.
For me test-first-developed-code is a big factor in what I consider to be good code, which is I think what you mean when you say "elegant code". Elegance is a funny sort of word that people struggle to define, and, not necessarily, a huge player in what good code is (for which there are some relatively precise definitions).

Ideally, I like to write everything with good tests first. However, this requires a small amount of up-front design, usually done in your head (the stuff you do in order to know what your first test is). Most of the time that small amount of up-front design is small enough to cope with but when you're working with someone else's API that you don't know, or you're doing something very experimental, small isn't small enough. Here are some possible ways you might solve that problem:

1. Prototype.

Write something to try out a design. "Hammer out", by all means. At this stage you want to ascertain whether your design is a good idea or not and you don't want to waste any time on code quality in case it's a bad one. Ruthlessly dispense with all unnecessary complexities, prove the concepts and nothing more.

If this doesn't work or you think you can do better with a different design you can throw this away. Suggestion: Commit it in your version control and then delete the file; it's around in version control if you need it again.

Sometimes your prototype will work in which case you should absolutely put in retrograde tests (the tests that you would have written if you were writing it test-first). Then, as others have suggested, refactor and refine.

2. Model

I still occasionally get out the ol' pen and paper and scribble some a loose UML class diagram showing the concepts I've identified and how they might link together. In my experience it's not worth spending much more than 30 minutes doing this and I never expect the design to work without alteration. Sometimes it deviates substantially when I start coding but it helped me get started so that's fine.

Other times you may find writing use cases or user stories more appropriate and there are number ways to do them.

This short blog post discusses the differences between types of modelling that I found very enlightening when I read: http://www.benjaminbooth.com/tableorbooth/2008/05/summary-di...

In the end it's whatever works for you to get a better idea of the problem. Mind mapping even! (Disclaimer: Never tried one that for code)

3. Pseudo-code

I rejected pseudo-code as one of those out of date techniques that has no place in the post-mainframe generation. But actually in select situations it's a nice compromise between a user story and a prototype. Typically the time you'll want to write pseudo-code is when you're working with something requiring a large number of procedural-like operations to be done to it in order to get a result. Stuff like data mungeing or gluing together a large number of systems or languages to achieve something.

I had a situation where I had to parse a file full of inconsistencies. Psuedo-code was excellent for that because it helped me identify the strategies I needed to deal with those inconsistencies. It ended up being a big-design-up-fronty sort of project but that was necessary because whenever I just dived into code I'd end up writing things that would work for one bit and then fall over on others; although a couple of those prototype components ended up being useful later on.

Possible Anti-pattern: The snowball prototype

If you are prototyping look out for the tendency to add to your prototype with increasingly more ambitious functionality. Once you prove one thing works it's very tempting to add the next idea you have to see if that works and so on. At some point you're going to have to stop and refactor otherwise you'll be programming spaghetti by the next day.

Alternatively create separate prototypes for each idea, refactoring out common components f...