
Anti-Patterns Every Programmer Should Be Aware Of - willk
http://sahandsaba.com/nine-anti-patterns-every-programmer-should-be-aware-of-with-examples.html
======
ffn
I like how the first three or so anti-patterns are in the exact opposite
direction as the last three or so. The art of being a programmer is literally
"don't waste time over-thinking things, but also don't ship under-thought
trash". For all our fixation on simplistic and ease of use, programming is
actually incredibly difficult and way more art than science.

And it's exactly this requirement of masterful manipulation of balance that
makes me love this field so much and long to get better at it. Getting a
handle on the artsy spirit of programming is really what separates the wheat
from the chaff in terms of programmer skill. There is no formal programmer
guild in real life, but if there was, and there was some sort of test a
journey-man programmer must undergo in order to become a master programmer, it
would be the test of being given a large project and then deciding correctly
exactly how much technical debt to take on to be able to ship a product within
a reasonable time-frame and yet have its internals not be complete
unmanageable spaghetti.

~~~
bottled_poe
It reminds me of the quip: "I can deliver your project quickly, cheaply and of
good quality - pick two". That said, in my experience, clients tend to see
software quality as the least important attribute of the three.

~~~
crdoconnor
>clients tend to see software quality as the least important attribute of the
three.

It's the one attribute they can't see.

~~~
zaphar
It's the one attribute they can't see immediately. But they _will_ see it
eventually. When fixing critical bugs take months and their customers are
breathing down their necks they will see software quality at work. It's our
job to educate them about these risks since they have a delayed appearance.

~~~
crdoconnor
I don't think "educating" clients about quality is worth the effort. Just
deliver code to a quality you are happy with and tell them that it takes as
long as it takes (giving them feedback as regularly as you are capable of, so
they get a sense of progress).

Good clients will understand and bad clients will filter themselves out
quicker (which is a blessing in disguise even if they do sometimes give you
money).

I prefer to let cold, hard reality do the teaching.

------
chriswarbo
> Fear of Adding Classes

I've seen this a lot, and is often made worse by attaching a load of
unnecessary baggage/repurposing to classes.

For example, I've worked on PHP projects which, over time, have gained coding
standards like:

\- All classes should be in separate files, named to match the class name

\- All classes should be built from a PHPSpec specification

\- All classes should have their own test class

\- No class can instantiate another, unless it's a "Manager" class which does
only that. Everything else is dependency injected.

\- Test classes can only instantiate their associated class; everything else
must be mocked

And so on.

Now, each of these has its merits, but as each new practice was added, it
increased the 'fear of adding classes', even if just subconsciously.
Refactoring to break up classes became less and less common, since a simple
code change would require:

\- Whole new test classes (OK)

\- New files (seems a bit like Java-envy, but OK)

\- Injecting new instances wherever the old class was used (seems a bit
overkill...)

\- Mocking the behaviour of the first class in tests for the second, and vice
versa (this is getting a bit silly...)

\- Creating 'Manager' classes to instantiate the new classes (hmm...)

\- Creating new test classes for these managers (erm...)

\- Mocking the dependencies of the managers...

In the end, it was just far easier to just throw all new logic into existing
classes, which grew and grew.

~~~
mercurial
I've worked on a codebase where objects inherited from a class named
"Abstract" which contained, apparently, methods used in more than one class,
regardless of purpose.

Other fun anti-pattern: make a Facade class hiding services. Then:

\- add logic directly in your facade

\- make the services using the facade depend themselves on the facade
(circular dependencies FTW)

This an excellent way of ensuring your code will NOT be reused.

~~~
eonw
oh come on, circular dependencies are fun and you know it! ;)

------
jammycakes
I always get a bit nervous when I see Knuth's quote about premature
optimisation. While the points the author makes are valid, the fact that it
gets bandied about as an out-of-context sound bite results in a lot of code
getting written with a complete disregard for any optimisation whatsoever.

Another far more common antipattern that isn't mentioned here is premature
abstraction. You see a lot of this in enterprise .NET codebases -- such as the
widespread "best practice" to build ineffective and obstructive abstraction
layers "just in case you might want to swap out Entity Framework for a web
service."

~~~
mduerksen
The word "optimisation" should not be confused with _considering computational
complexity_ , and I believe we are in dire need for a catchy word for the
latter.

One of the most important steps in programming is:

How many elements could this code actually have to process, and if there could
be many: is this datastructure/algorithm suitable for that?

This is almost never premature. This should NOT be called optimisation.

I would like an own word for that. Suggestions?

~~~
danieltillett
Yes you should always think about optimisation, even if you never end up
coding for it. Every function I write I think about what is the effect that it
will have on the rest of the code and what will I need to change if it later
turns out to be a bottle neck. The advantage of this is I sometimes avoid
writing some dumb code - even if it never matters from a performance
perspective I have thought a little bit more deeply about what I want to
accomplish.

To answer your question how does thinkthencode sound?

------
lugg
If you're a dev and have never read these two wikipedia links, I highly
recommend it.

[http://en.wikipedia.org/wiki/Code_smell#Common_code_smells](http://en.wikipedia.org/wiki/Code_smell#Common_code_smells)

[http://en.wikipedia.org/wiki/Anti-
pattern#Examples](http://en.wikipedia.org/wiki/Anti-pattern#Examples)

~~~
petjuh
I read A Big Ball Of Mud while in high school, left a big impression on me.
Unfortunately, I've since seen that my projects all gravitate towards it at
the end.

~~~
Xophmeister
I'm pretty sure this is just the nature of the universe; increasing entropy
and all that.

------
sulam
You forgot the most important anti-pattern of all:

"Not Invented Here".

The urge to rewrite things that you encounter is strong in software engineers,
and you should always be suspicious when you find yourself thinking "I could
do this so much better." Especially when it's true!

~~~
vosper
The "not invented here" pendulum has swung a long way, and I think that
there's now a real, hidden anti-pattern in industry: "never invent here".

At some point, it's important for us as programmers to indulge that "I could
do this better" instinct. If you're right you could make a real contribution
to your employer or the community. If you're wrong then you'll still be a
better engineer (and possibly a domain expert) for the effort.

If everyone embraced "not invented here" as a philosophy then the whole
industry would stagnate.

~~~
wvenable
Most of the time I can do it better because my problem space is so much
smaller.

And sometimes I look at components and I'm so disgusted by the code or the API
that I merely use it as an example and re-write the code for my own purposes.
Just because somebody put it on Github or built a package doesn't
automatically make the code good.

Most of the "not invented here" I come across is from developers who never
look for 3rd party solutions. It doesn't even occur to them. And it's usually
obvious stuff like XML or JSON parsing! Which is why the message of "Not
Invented here" is a good one to repeat over and over.

~~~
xamuel
>obvious stuff like XML or JSON parsing!

There is one case when those wheels can be worth (partially) reinventing: if
you only need them to parse some files which use XML or JSON in a very
restricted way. Say you've got a bunch of XML files which only go one level
deep, only use ASCII, don't use namespaces, etc. A full XML parser comes with
a whole ton of bloat you don't need for that! Plus, if there's ever a problem
with those files, the outsourced XML parser will tend to give the end-user
absolutely useless error messages.

~~~
chriswarbo
This is often a slippery slope. Assumptions tend to erode over time, eg. I've
seen code assuming ASCII-only input fall over due to people copy/pasting from
Word (which automagically turns hyphens, quotes, etc. into non-ASCII).

Also, whenever there's a lot of data being looped over, it can be very
tempting to add new features to the existing loop, rather than adding a new
pass (inefficient) or trying to collate the results after they've been spread
out (complicated & error-prone). This can turn a simple parser into a core
piece of business logic, and of course it's then only a matter of time before
custom, XML/JSON-incompatible 'directives' start creeping in to control that
business logic.

------
fsloth
I think example 9. (the stack that wraps a linked list) is not a necessarily
an antipattern. Removing degrees of freedom and adding obvious constraints
make systems simpler and easier to comprehend.

~~~
stinos
Fair point. Especially because what is called _anti-pattern_ here also exists
as an actual _pattern_ which does have it's use, namely 'Adapter'.

~~~
ygra
And Façade. Depending on whether you need a bridge between APIs or between an
API and a developer, I guess :-)

------
arbsn
Surely the purpose of the LabStack example is to restrict the interface of a
LinkedList to that of a Stack? Defining a new type to present a more
restricted interface is not useless... it helps one reason about what has or
hasn't been done to an object.

~~~
DSMan195276
I agree - Defining a 'Stack' class is useful even if it's just a wrapper over
LinkedList, because stacks have an expected way to act, and while a LinkedList
fits the bill it does more then a stack actually has to do. And with that,
nothing says you have to implement a 'Stack' with a LinkedList, it's just an
easy way to do it. By defining the 'Stack' class, you could always go back and
improve it to not use LinkedList and instead do it yourself.

That said, I do agree with the author that, in the context of a programming
class, writing the 'LabStack' class is absolutely useless because it teaches
you nothing about actually using a linked-list to implement a stack, which I'm
sure was the real intent of the assignment. The 'LabStack' class is useful in
the context of being used in a larger program, it's not really useful for
learning how to actually implement a stack because it just passes the
implementation off to 'LabStack'. (That said, because Java doesn't support
defining objects as value-types, using the 'LabStack' interface adds an extra
level of indirection you may want to avoid - You have to access 'this.list' to
get the LinkedList object, instead of just accessing it directly. This is more
a fault of Java then anything else though.).

The note about programming class isn't really relevant to programming as a
whole though, which is where the disconnect happens.

~~~
xxs
Unless the stack has to be lock free, array backed ones (ArrayDeque in java)
are better on the current hardware.

------
erikb
I'm a little confused. I'd say that an anti-pattern is something one can
avoid. Sure, I can think about every optimization I'm doing, and if I already
know well enough that I'll need it and doing it right. But I can't really
avoid discussing about something that is unimportant in my eyes, because the
person who will discuss about it usually thinks it's important. I'd say that
in the "bike shedding" regard my anti-pattern would be that I ignore some
complaint as unimportant because I still don't understand it well enough.

Other things are also hard to avoid by myself, like

\- God Classes (I could refactor here, but then the anti-pattern is fear of
refactoring)

\- Management by Numbers (I'm not a manager, what can I do about it? Actually
I'm happy if my management is already that good that they have numbers.
Nothing is more horrible than management who doesn't tell you explicitly what
they want and then complains about details for half a year, then starts with
the next project without declaring the last one to be finished or anything.
I'd say numbers are good, finding the right ones is tricky, though.)

\- Useless classes are avoided by simply not writing them? No, they develop
when code gets refactored and nobody had looked at the responsibility of that
specific class for some time. Nobody writes classes without having a goal for
them in mind. Mostly calling methods of another class is fine. It happens in
design patterns like Observer, Delegator, or Compositor.

------
kristopolous
I read this many years ago. Let me find the source.

Edit: I can't find it. Anyone else remember reading this? The mysql job queue
reference was from a popular article that went out about it at the time

Edit 2: the job queue article is from 2011.

Edit 3: still can't find it. But I know every part of this article before
seeing it ... I tested myself and remembered all the details... Where is this
thing from?

Still can't find it. My confidence in the permanence of the web is pretty
destroyed right now. I can't even find references to it existing.

~~~
jrgnsd
I think you're referencing this article about MySQL job queues:
[https://blog.engineyard.com/2011/5-subtle-ways-youre-
using-m...](https://blog.engineyard.com/2011/5-subtle-ways-youre-using-mysql-
as-a-queue-and-why-itll-bite-you/)

~~~
kristopolous
Yes. This article came out after that. I realized a few paragraphs in that I
had read all of it. I tested it by guessing the content and was 100% correct.
But I can't find it.

This isn't the first time I wanted a searchable version of archive.org that
effectively timecapsuled the interactive internet. Things fall off the net far
more than common folklore suggests

Anyone got $10 mil to drop on that project?

~~~
cxseven
I'm glad to see someone else echoing my anxiety. I had the impression that
Uniform Resource Locators were meant to be treated as bookmarks into a web of
knowledge, so it's like brain damage when they break. It's too bad it happens
so frequently, because for a few blissful years my urge to hoard was quieted
by the assumption that the internet was doing it for me.

Those enormous URLs that describe nothing but a document GUID are also a sin.

~~~
mercer
I've resorted to capturing every single interesting link as a complete HTML
page to DEVONthink, which is a mac application specifically meant for storing
large amounts of data. It's already proven quite handy in two ways: 1\. I can
access articles that have disappeared off the net 2\. I have a very powerful
search function and 'similarity engine' constrained to only the information
I've found useful so far. It's often the first place I look for certain kinds
of information before I try google.

I can strongly recommend using such a tool to make sure you don't 'lose' stuff
on the internet that is important to you.

~~~
unionpivo
Anyone know of anything similar for linux or windows?

Right now i am using chrome, to save whole page as zip, but that becomes in-
convenient when you have several hundreds of them.

------
Hermel
How could they forget premature generalization?

~~~
leni536
I always fall into this.

------
Kiro
> God Class

I don't understand how to avoid this even if you break it up in smaller
classes. You still need a point of entry where the logic begins and where it
is decided which components to use. ThIs always means some kind of Manager or
Main class for me. How do I fix it?

~~~
adrusi
Well there's an entry point of course, but it shouldn't know much. Your entry
point knows about your option parser which knows about the high-level actions
your program performs which know about the sub-processes involved in
accomplishing them, etc.

It's important to keep this graph as acyclic as possible, and to try not to
have any one component directly interact with too many other components,
because then your abstraction is too fragile.

------
aidos
Enjoyed this list. Over the years I've become better and better at spotting
these issues, but even still sometimes it's hard to see them creeping up on
you.

The worst for me these days is analysis paralysis. I'm currently working on my
own so I don't have anyone around to bounce ideas off. For smaller tasks it's
not a problem, but there are bigger design decisions that have ended up taking
longer than probably should. When you're left to figure them out on your own
it takes a lot longer to convince yourself of the "better" way of doing
something.

~~~
valisystem
To me, the problem in choosing the "better" way of doing something is that I
can't stop comparing diverging design choices.

I like to think that the best way to choose between seemingly equally
advantageous designs is to start with the one whose first step(s) is(are) the
most straightforward. The thing is, while I prepare myself for implementation
of that first step, I've a background loop in my mind that constantly checks
against other implementations choices. What I am losing here, what I would
gain otherwise.

In the end, I never really make definitive decision before starting. I start
with that background brain noise on the “most simple first step design”, and
when the background noise stops and the raw pleasure of coding kicks in, I
known I'm on a good track.

~~~
aidos
I guess I do go through that process once I start work, but I'll definitely
keep your advice in the back of my mind. Don't let the choice become
overwhelming, get started knowing that it's ok to change your mind during the
process.

For any feature / bit of work that's in isolation, I don't really worry. I
figure out an approach and I implement it. When it comes to changing data
structures / larger changes within the product there's a fear of getting it
wrong and having a mess to unpick later.

------
jongdubois
"It seems that perfection is attained, not when there is nothing more to add,
but when there is nothing more to take away."

Great quote - It reminds me of the story of when Michelangelo unveiled the
statue of David, someone asked him how he managed to create such a masterpiece
and Michelangelo answered "It was simple, I just chipped away all the rock
that wasn't David".

~~~
lukesan
"To clarify, add detail" \- E. Tufte

I don't think reduction only leads to perfection. If it would be, then our
starting point must always be the right one. But in practice you start
somewhere, reduce, move forward, add stuff, move sideways, try out and test.
Sometimes you need to add stuff to make it clearer to your users.

------
techar
Is
[https://en.wikipedia.org/wiki/Facade_pattern](https://en.wikipedia.org/wiki/Facade_pattern)
a God class? I like the idea if it only delegates to other classes. Its
downside is the dependencies to many classes.

------
acbart
#5 is a classic example of the Expression Problem[1]. Are you trying to add
more shapes or more functions that operate on shapes?

[http://c2.com/cgi/wiki?ExpressionProblem](http://c2.com/cgi/wiki?ExpressionProblem)

------
paulus_magnus
Having worked for big corporations in Europe, I'd like to see manager types
spend 10% of time technical people spend on self-optimising themselves, their
working environment, post-mortems, understanding antipatterns, productivity
etc.

------
dvh
Most of the evil done in my company seems to be by Ctrl+C Ctrl+V and then
changing 1 line of code.

~~~
stinos
Same here, unfortunately. It drives me nuts. It's oh so easy and tempting to
vialoate the DRY principle. But what's even worse is people actually defending
their Ctrl+C Ctrl+V behaviour with false/uninformed arguments such as

\- why waste time with creating a function when I can copy-paste?

\- but I'm never going to have to change this code anymore

\- but it's more readable else I have to figure out what the function will do,
browse to it, ... (well, good luck navigating any codebase at all)

\- but it occurs only twice (ok, twice is debatable, but still: before you
know it the same is used again in another place an there we go again..)

\- but it's faster because it doesn't require an actual function call (this is
by far the worst one: they claim this without having even measured it, without
having checked if there even is a bottleneck, without realizing that in
compiled laguages any decent optimizer would inline and generate assembly
anyway)

------
NoMoreNicksLeft
Half afraid to read this, I think they might be our programming conventions at
work.

------
Sami_Lehtinen
It's nice to notice that top three actually does not have anything to do with
programming. Those are absolutely general issues when ever doing anything at
all.

------
dmichulke
Isn't it blasphemy to quote _Greenspun 's tenth rule_ right after insisting in
two consecutive rules that people create enough classes?

~~~
current_call
No, because CLOS is awesome.

------
smegel
> "Magic Numbers and Strings"

I don't know about this one...we need something have a chuckle (or cry) about
over beer after work, and to make sure software archaeologists in 100 years
time have an interesting job (not to mention plenty of opportunities to write
blog-spam)!

~~~
s_tec
It's not bad advice, if used in moderation. The problem is that most
developers take it too far, to the point where no number is safe from becoming
a named constant.

My default these days is to write numbers as numbers, plus maybe a comment if
things are unclear. I only turn numbers and strings into named constants if
they are used in more than one place, or if they are true configuration values
that need to be tweaked.

This makes the program easier to read (the ultimate goal) by avoiding the need
to jump around in the codebase. Comments are better at explaining things than
cryptic variable names anyhow.

~~~
sken
Definitely, although there can also be refactoring benefits to look out for.
In the article example it would be much easier to change the default popup
window size (800x800) across the project if they're all using the same
variable.

On the other hand, tools like CheckStyle can make people do some strange
things when they take it too literally.

I once reviewed code that defined: static final int ONE_HUNDRED = 100;

~~~
kibibu
Could have been worse:

    
    
        static final int ONE_HUNDRED = 200; // Changed to 50 to optimize

~~~
a3n
I'm still laughing.

And it's funny because it's true.

And ... the funny could have been eliminated if the named constant had just
had a useful name, or been replaced by a function, rather than a passive-
aggressive response to a code analyzer or coding standards ("There, I fixed
it."). The conflict between the name and its value would have been eliminated,
and the comment may have never been written in the first place.

------
allan_s
for

" Writing a task scheduler for your web-server in PHP"

Is the author talking about "at" and "cron" instead ?

~~~
jrgnsd
There's a number of solutions, depending on your stack: at and cron are good
OS level solutions. Sidekiq is great for Ruby.

I think the problem lies in that PHP wasn't designed to be a long running
process, and for a scheduler you need something long running.

~~~
contingencies
Having done this (years ago), there are good reasons sometimes. At the time I
was working on a relatively complex hotel reservation system with a
distributed database and the need for batch execution of background processes
(things like sending emails and digital fax from a queue).

The master interface to the database was a series of PHP functions since the
data massaging that had to occur (to facilitate correct interaction in
multiple human languages across disparate timezones versus user preferences
and time of day, etc.) ruled out direct DB access from anywhere else, back-end
processes included.

I think the end solution was something like 'every minute run PHP X from cron,
which checks if there are jobs, if so successively spawn children to handle'.
It was basic but it worked. Godawful pain with MySQL replication over lossy
Chinese internet WAN ... never again.

~~~
jrgnsd
I inherited a similiar system. It was painful to say the least. I didn't
realise how painful until I started using proper queueing systems and Sidekiq.

~~~
contingencies
Sidekiq doesn't really look that different to what we used.

Anyway, neither decent ruby unicode handling nor _RoR_ nor _sidekiq_ existed
back then. I actually considered rewriting the whole system in _ruby_ at one
point, but the unicode support was still dodgy.

