

When To Write Bad Code - tnorthcutt
http://www.brandonsavage.net/when-to-write-bad-code/

======
alexkus
Write prototypes in a language that you don't use in production.

It allows you to get to grips with the problem and prevents you from just
copy-and-pasting large chunks of the "i'll rewrite this later" code into
production.

I tend to write my prototypes in Perl as I used to use it a lot in the past
for hacking things together. It translates well both to Ruby on Rails (front
end) and to C (with low level server magic).

~~~
brandonsavage
This is a great suggestion. I've done this with PHP (the first language I
learned) for work I'm doing in Python. It also helps sometimes when you have
to translate code from one language to another to use an intermediary
language.

------
powrtoch
"Nothing lives longer than temporary code."

Love this quote. I assumed it was an existing quote/idiom, but it looks to be
original.

~~~
brandonsavage
It's not original to me. Not sure where I heard it, but I know it's not mine.

~~~
npsimons
_Thus spake the master programmer: "Though a program be but three lines long,
someday it will have to be maintained." \-- Geoffrey James, "The Tao of
Programming"_

------
jsnell
I don't think this post goes far enough. It's not only ok to write bad code,
it's also ok to commit bad code, and to use such programs in anger. Most code
is not actually going to be important. It's ok for that code to be crap.
What's generally not ok is contaminating already existing high-quality
components with quick kludges. Likewise it's not ok for programs that turn out
to be important to remain in a crappy state, even if they started out as such.

I write dozens of shell pipelines every day. Some graduate to actually being
saved in files and cleaned up a bit. Some of those start needing new features,
and end up rewritten as quick and dirty perl scripts. A few of those see
constant use in more and more circumstances and end up accumulating an ever
larger number of features. Once that program grows large enough, it'll become
obvious that it'll become unmaintainable at some point. And you can either
evolve that code into a less crappy state when other changes are made, or you
can rewrite it from scratch.

And the thing is, you can't really know in advance what kind of a program a
given problem really warrants. Is it shell pipeline that'll only ever be run
three times, or will it end up as a core component of somebody's workflow.
Since you can't predict these things, you have to play the odds. If most
programs end up as important tools, it'd be insane to risk the need of
multiple rewrites. While if most programs end up just gathering dust
somewhere, it'd be insane to polish them to perfection before committing. And
even if "nothing lives longer than temporary code" is a nice soundbite, I
don't actually believe that for a moment. I'd bet that most temporary code
actually dies almost instantly. It's just some kind of observation bias.

------
yajoe
There is a similar dilema in the creative writing field: "I don't know the
right way to say this idea" or "I have writer's block." The general advice
from the workshops and masters is to write _something_ , even if you know it's
terrible, so you have a place to start and revise (what we would call
refactoring). The theory is that revising words is much easier and can be
helped along by someone else moreso than a blank page.

However, I've only seen it work in practice when you do go back and refactor.
Too often the smelly code gets left behind, and that is why I usually ask
others to think through code before writing.

~~~
stcredzero
_> The theory is that revising words is much easier and can be helped along by
someone else moreso than a blank page._

Amen. Nothing beats the instructive facility of running code and a usable UI.

 _> However, I've only seen it work in practice when you do go back and
refactor. Too often the smelly code gets left behind, and that is why I
usually ask others to think through code before writing._

Well, of course it won't work if you don't refactor. You get results analogous
to writing with no revision. There's also the trick of knowing when you've
revised enough -- amateurs stop before the pros.

------
jakub_g
In most of the code bases when 5+ people work on the same code, it's really
hard to add some non-trivial functionality by writing it the proper way from
the beginning. BTW I think sticking with the attitude "first specs, then code"
is old school in most situations. Some very rough spec will be fine, but a lot
of the things you haven't thought of, you encounter while actually playing
with the app/widget, or stepping through the debugger (unless you've worked on
a product for a very long time and know it inside out).

I find "write working code & then refactor" ridiculously easy when working
with Git. Add some tiny new things one-by-one and commit early each time it is
more or less stable (so you can revert quickly when you screw it later,
instead of doing some crazy debugging). When it's done, squash the commits and
refactor.

------
keyboardP
Isn't this just usual prototyping? I rarely consider best practices when
trying to implement a non-trivial prototype because flow and creativity is
broken when attempting to adhere to best practices at the same time (in my
experience at least).

My current project contains some non-trivial code so there was a lot of
prototyping. If I spent time ensuring this code was also well written, I doubt
the problems would've been solved because half of my energy and concentration
would be spent on scaffolding and not the actual building.

Having said that, I still find documenting the prototype as important as real
code. When it comes to refactoring the code, it helps a lot.

------
Zarathust
I used to say that "temporary is the state before permanent". Unfortunately,
the crappier the initial code base is, the crappier the production code will
be, unless you have a lot of free time to rewrite everything, which about
nobody has.

~~~
stcredzero
Having the time to eliminate your technical debt is just like having the money
to make your interest payments. You can go into debt for leverage, just don't
get caught in a cycle where it gets deeper.

------
eventualEntropy
This is my approach as well. This basically amounts to planning to throw one
away anyway (<http://c2.com/cgi/wiki?PlanToThrowOneAway>) or rapid prototyping
(<http://c2.com/cgi/wiki?RapidPrototyping>).

After coding the first implementation you will always realize things that you
didn't anticipate that could improve the design. It's easier to get it working
quickly, find the holes in the algorithm/design, then refactor it to be pretty
and maintainable.

------
r00fus
I think this varies per person's development style. If the thing that's
blocking is getting momentum, then sometimes writing tests and then code to
meet those test is easier (for those of us who are more comfortable with
documenting).

In the end it depends whether it's easier to _just code_ or setup scaffolding
(ie, TDD tests) to then write the code.

------
Deestan
While I agree with the underlying point, the title is an argument in semantics
(and I would say misleading and wrong - it is _never_ OK to push bad code).

It may be unelegant, it may lack any number of "best practices", but if your
code solves a problem, doesn't break other things, and can be refactored
effectively, it doesn't count as _bad_.

------
danso
> _When the code is working and you’re ready to move onto the next phase, then
> you can work on making the code pretty, readable, well-documented and
> tested. While this flies in the face of concepts like test-driven
> development..._

I disagree that writing "shit code that still works" and TDD have to be
mutually exclusive. In fact, if I'm going to go the "just get it done" route,
I will almost (but not always) try to set up a few tests for it.

Because nothing sucks harder then going back to crap code and trying to
decipher what it's doing. If it's crap code, then it's likely non-orthogonal
code, which means changing it will likely break something...etc. etc. Tests
help me do the refactoring later.

And, also, how do I know that my shit-code-just-works _actually works_?
Sometimes, it's helpful to write a kind-of-shitty-test to at least verify that
it kind of works, if not perfectly.

~~~
brandonsavage
The person I was mentoring (that prompted this blog post) was having trouble
getting ANY code down on the screen. Being able to write SOMETHING was the
hurdle for this developer to overcome.

In most cases though, I agree with you.

~~~
sinkhole
I write bad code all the time, I'm writing terrible code right now. I _check
in_ good code.

Some people can visualize an entire program in their head and how it will
interact. Not me. I hack at the core of the problem I'm trying to solve, until
I've solved it. Then I reorganize the code into something that (hopefully)
isn't crap. It seems inefficient, but it works for me.

------
m__
This is why you test from the outside in: You first write an acceptance test
where you just specify what goes in and what should come out. The
error/failure messages you get when running this test drive your design and
tell you which components you should write next.

The RSpec book is a pretty good introduction to this topic.

------
delongshot
From the sounds of other developers, I think much of the development community
is moving towards this paradigm. Developers have been so inundated with
needing to use patterns, designs and other forms that has lead to
inefficiencies in designs that were well thought out, but do not apply,
instead of inefficiencies from bad code.

------
lewisflude
This is a really interesting point of view.

