« The Deep Synergy Between Testability and Good Design | Main | TestNG And What We'd Like Code To Be »

July 14, 2010

Comments

Jdtangney

Eno famously used his "Oblique Strategies" https://en.wikipedia.org/wiki/Oblique_Strategies to engender greater creativity or circumvent creative blocks.
--johnt

SStone

That would be pretty easy for me, I could just leave out all refactoring efforts and it would quickly become a complete mess!

Bob Lauer

... Clemens Szyperski mentioned the notion of "design in the negative space", i.e. think about what features you do *not* want.

The code level may be a bit different though - bad code is probably not the code that fails to implement the right feature(s), but rather code that successfully blurs the association between features and code lines. In other words, it does not communicate, or (un)intentionally miscommunicates.

I encountered a nice C++ example today: A piece of legacy code defines an iterator type that has two methods:
T *current();

returns the current element, and

bool next();

moves to the next element *and* returns whether there is actually a next element. This allows for loops like this:

while(i->next()) {
...
}

The assumption is that you have to call next() before accessing the first element (so the internal reference pointer does not point to index 0 but to index -1 initially!).

So next() does go to the next element as you would assume from the name, but you have to remember to go to the "next" element initially to arrive at the first element.

Rexm

@Bob that design is actually correct... starting at -1 is the only way for the iterator to tell us if it is empty, without having to add a third member to the contract.

Florian Junker

https://gist.github.com/371740

Binary search on an ordered queue. The code itself isn't that bad, but the algorithm is.

Bob Lauer

@Rexm: The above design is indeed correct, but it does not communicate well. The "next()" method is used to move forward *and* to signal an end of the iterable container.

A clean design would be the C++ STL iterators or the Java iterators (with methods hasNext() and next() separating the two concerns).

Another kind of bad code is overly clever code. At university the following one was a common joke, but some people actually write code like that in production:

#define swap(x, y) x^=y;y^=x;x^=y;

Steve Knight

An interesting idea. I would guess that it's hard to write intentionally bad code because bad code is usually as a result of some misunderstanding. There is a paradox here because to deliberately create something that is the result of a misunderstanding you must first understand it!

Keith Braithwaite

The bad code that I see in the wild is mostly the result of well-intentioned (or, at least, not malicious) people working under great pressure in difficult circumstances. That seems as if it would be a hard thing to simulate.

And the badness accumulates over time, as the naked options created by bad code get called (see https://www.m3p.co.uk/blog/2010/07/23/bad-code-isnt-technical-debt-its-an-unhedged-call-option/)

To simulate this we would have to write some code under circumstances where we are under pressure, distracted, maybe frightened, rather than by deliberately making mistakes. Write some code while, quite literally, not giving yourself time to think, and see what happens.

Heikki Naski

I immediately thought of two possibilities of bad code and it's hard to know which one is actually worse:
1) Code that is hard to understand
2) Code that looks understandable but has a subtle yet devastating fault in it, like an unintuitive API or a missing character that makes the code do something completely different.

Mark Nijhof

Late reply, but this is interesting as I noticed this as well when trying to create code that is violating a certain principle (in order to demonstrate the principle) and that can be very hard to make something real and wrong when you are focused on it so much. Then then you are not, i.e. in regular code, you see the examples much easier.

So in order to achieve this task we should just write 'normal' code, then as a rule this will be bad code, except for some of use of course :)

And finally, just let someone else write the code as it is always sooo easy to find flaws in other peoples code ;)

Eric

Helping students to intentionally write bad code might be easier if you set them a problem that is closer to the things that go awry in professional work.

A kata that includes a few overlapping/interlocking business rules that allow you to make your code fester could suffice. Think about the simple things like:
* Ignore obvious encapsulation or inheritance.
* Repeat code (redundant code).
* Deeply nest your code.
* Construct complex boolean conditionals.
* Use conditions instead of procedures where possible.
* No/Not enough new classes.
* Let's have this all in the 'main' method shall we?

Would something along the lines of:
https://codekata.pragprog.com/2007/01/kata_nine_back_.html or
https://codekata.pragprog.com/2007/01/kata_sixteen_bu.html work perhaps?

The comments to this entry are closed.