

There are many kinds of ugly - bartwe
http://www.gamedev.net/blog/355/entry-2250790-there-are-many-kinds-of-ugly/

======
joelthelion
We should ban the words "ugly" or "dirty" when refering to code. These
concepts are not clear, and are used to justify a lot of rewriting and
redesigning that is not always needed and often counterproductive.

If you want to criticize code, say exactly what's wrong with it, so we can
have a detailed and rational argument about it.

If you say "this script is ugly, it should be rewritten", there's not much
discussion that can be had about it. If, on the other hand, you say, "this
script is written in a way that is not modular enough", then we can discuss
whether modularity really is a requirement or not, for that specific script in
that specific project.

~~~
gbog
Yes, but when the guy pointing ugly code is a good coder, "ugly" is just a
shortcut for something that usually can be explicitly stated and is really
harmful. (A bad coder will say "ugly" for any kind of code he did not write.)
Here are some of the reasons behind "ugliness":

\- Wrong logic giving correct results (this is awful)

\- Hidden dependencies making remote changes dangerous (bèè)

\- Misleading variable or function name

\- Unnecessary use of magic (eg programmatically building function names),
this breaks a lot of code analyser, and makes your code base ungreppable,
which is very bad.

\- Code duplication and configuration factorization.

\- Nasty hack breaking the model (eg changing request parameters on the fly)

All in all, I agree with the OP premices, but not with his solution. Adding
comments all over the code is not going to save you, and making sure you
understand all corners of the module you work on before starting to modify a
comma is not that helpful either. In front of a montain of legacy code that
need some ordering, if it is a short cycles mode with versionning, I would:

\- First make sure my tools are accurate and fast. It mostly means tweaking my
grep alias, so I grep all the code and nothing more. I may mean to find a way
to run the modified code in less that 3 secs (unit tests can help for that
part).

\- Second, don't try to understand all the thing, start low, maybe rename a
few variables that are obviously wrong, for example marking them as private
(adding _ prefix in python).

\- You won't know were are the painful points in the begining, so you should
continue doing safe & simple refactorings, one step at a time, in order to
slowly "wake up" the code. A bit of temporay commenting can help, like "this
func returns a x-blob used by that module".

\- Then when you become familiar with the code you'll be in position to decide
if and where to do some real changes. Some people here seem to believe that
legacy code should not be changed except in case of earthquake. I don't agree.
Adding a pile of hacky crap over a pile of hacky crap to make the thing
temporary work is not a good bet on the future: do it only if you plan to
leave your company soon enough.

\- Doing a bigger change might require some iterations and lacemaker work. If
possible, you can bridge the legacy code, ie write a func_new and compare it's
result with func_old during one iteration, to kinda prove that they are the
same.

\- I noticed that it is sometime useful to take a big class, a big god-like
object doing too much, and cut it in much smaller pieces. Sometime you may
have to re-glue together some pieces because you went too far, sometime you
may even kind-of rollback your changes, but in any case these operations will
shaken the code base a bit, which is good.

These operations require courage regarding of the code base, because you will
feel lost sometime, you will fear regressions, you may even fix a
functionality that should not be working and, consequentially, break
something. Here, be careful, you should not be fixing broken parts and
refactor in the same operations, except if you know enough to be sure. One
purpose of refactoring is to allow you to fix broken (or slow) part later. I
insist on "later".

It is also requiring patience and tenacity in front of the operational team:
they will think you are doing nothing (they are right, from their point of
view, per the very definition of refactoring).

~~~
joelthelion
This is exactly why these words should be banned. What you fail to realize is
that "good" or "bad", when applied to all these things, depends a lot on the
context.

You don't expect the same level of quality from a one-page script that will be
used once, than from a crucial part of a large-scale program involving
thousands of people.

Spending two days making the script robust, modular, flexible and unit-tested
is just as bad as pasting an undocumented hack in the large program.

We need to try to be rational and stop mixing morals and code.

~~~
gbog
> We need to try to be rational and stop mixing morals and code.

It's funny because I think you are wrong. I would agree with stopping mixing
aesthetics and code. The highest poetry from, say Mallarmé, has qualities that
would be considered as stupid plain wrong pure evilness in code.

But morals and code have relations. A lot of relations actually. My moral
forbids me to steal and cook my neighbour's cat, not because it is forbidden,
but because I have enough self-respect to not behave like that.

The same applies when writting code. Even if operational pressure is high, I
am not the kind of guy who will let the shitty work to other coders behind me.
I have self-esteem, and don't want peer coder to think I am the worst shit in
the world, so I just won't add crap to a pile of crap without doing reasonable
efforts to do at least some cleaning.

Like in the toilets: let it as clean as would have liked to find it yourself.

Maybe we should first agree on what is "morals". For me it is not a set of
predefined values like "good / bad", it is the very reason why we behave
properly to each other (or not), it is a consequence of self-esteem.

Oh, and I think a one-shot script do not need to be refactored to be
"beautiful" mind you, no, I think it should be either trown away right after
use, or at the very last marked very heavily in the file name and as the first
uppercased line: one shot script, no fixing required.

------
josephg
I've followed a very similar road.

For me, the thing which halted that ivory tower mindset was changing
languages. I find that after spending a lot of time in a single language, I
start thinking along that language's lines when I'm designing software. There
are a lot of things which are a good idea in some languages and rubbish in
others. Eg, enums are great in C, but useless in Javascript. Interfaces and
abstract classes are silly in ruby.

I think there's a trap programmers fall into with this stuff, where we get
used to some method / philosophy. After awhile, its easy to forget that the
method comes with a price that is being paid daily. Only by periodically re-
evaluating all the little decisions you make can you start to get a real sense
for when those decisions are appropriate.

But as for the code rot problem, there are two solutions I've seen which made
a difference:

\- Test-driven development (full on, no cheating, tests before you write code.
95%+ code coverage) \- Code reviews before every commit

 _But both of these methods will slow you down heaps in the short term._

I find proper TDD makes me about half as productive in the short term. In the
long term, it slows down big redesign work because there's twice as much code
to change. The benefit is that you can formalise all your obscure edge cases
in tests. If your test coverage is good enough, you can safely refactor code
without breaking anything. This removes fear from development and lets you
make clear decisions about design. (Also, its amazing how many bugs you find
when you start writing tests. It is humbling.)

I suspect that most of the benefits of code review comes from simply setting
aside time to talk about code style. It consumes a lot of time. In exchange,
you get higher quality code.

How much you care about speed and code quality really depends on what the
project is. You need to try them both out some time to be able to make that
decision properly.

------
gldalmaso
One of the commenters says " The answer is probably just situational, but I'd
bet that elegance is unimportant for a lot of code."

IMO that is miles from the truth. I handle code that "just gets things done"
everyday and it is a real pain. Elegant code is not code that is just well
formatted and clean, is code that solves a problem in an elegant way, a way
that will scale better and that is easy to understand and maintain.

The real problem is that it's really really hard to get managers and clients
to understand to value of elegant code.

When hell that is left after code-like-hell to get things done gets in the way
of maintaining the code, the blame gets thrown in the programmer that didn't
write good code. But they never want to trade off time for quality. And when
we ask for time to get things done with quality, they assume it's an ego
thing...

~~~
JoeAltmaier
Agreed. Elegant code is thin, tall and streamlined. Half as many lines as a
quick-and-dirty wad.

If you have half as many lines of code, \-- it takes half as long to read it
\-- it may be twice as easy to explain \-- you may be able to fit it all into
your brain at once \-- it compiles faster \-- it may run faster

Remember the slowest processor on the planet is your wetware. That's the place
where space and speed are critical factors.

------
swah
Ideally it should be like his diagram from Code Complete:
[http://flylib.com/books/2/823/1/html/2/images/0735619670/gra...](http://flylib.com/books/2/823/1/html/2/images/0735619670/graphics/24fig02.gif)

------
5hoom
I agree with the premise that production code won't be as elegant as you might
like once the real world starts creeping in, but describing code as 'ugly'
seems to lack information.

Is the code badly formatted? Poor choice of variable names? Non-idiomatic
language use? Monolithic code blocks? Spaghetti code? Depreciated methods?
Dangerous hacks?

Ugly could mean any of these & more. Some are less tolerable than others.

------
lyudmil
There's an implied assumption in this post that handling edge cases or one-
off, extreme cases necessarily is done by writing ugly/dirty code. I think the
whole point about writing clean code is avoiding the hacky stuff even if the
problem is messy. We're in the business of articulating solutions to messy
problems clearly enough so that they can be executed by a machine. The best
professionals in our field do that, and also make it so that other people can
read and understand their work. That's what clean code is to me.

Admittedly, there's room for interpretation and a degree of subjectivity here.
However, this doesn't prevent us from knowing about what _dirty_ code is and I
don't see a compelling reason why we ought to tolerate it (e.g. long functions
with a lot of branching are difficult for _everyone_ to read, so you shouldn't
have any of those; same goes for badly named variables/functions/classes).

------
reemrevnivek
The Joel on Software article that he refers to is probably "Making Wrong Code
Look Wrong":

<http://www.joelonsoftware.com/articles/Wrong.html>

