views:

505

answers:

13

Surely some of you have dealt with this one. It tends to happen when programmers get a bit too taken by OO and forget about performance and having a database.

For an example, lets say we have an Email table and they need to be sent by this program. At start-up, it looks for anything that needs to be sent as follows:

Emails = find_every_damn_email_in_the_database();
FOR Email in Emails
  IF !Email.IsSent() THEN Email.Send()

This is a good from a do-not-repeat-yourself perspective, but sometimes it's unavoidable and it should be:

Emails = find_unsent_emails();
FOR Email in Emails
  Email.Send()

Is there a name of this one?

A: 

Stoopid Amateurs.

Seriously, I've only seen this one in people with Computer Science degrees and no professional experience at all. When I was teaching at Duke, my advisor and I ran a "Large Scale Programming" class where we made people look at exactly these sorts of errors.

Charlie Martin
+6  A: 

I'll have a go at it and coin the name "the lazy filter (anti) pattern".

1800 INFORMATION
Marked this as the accepted answer by popular vote
WW
+1  A: 

I'm not sure this is necessarily database related, since you could have a complex and expensive procedure (e.g., more than a flag) for applying a filter for a group.

I don't think there's a name to it, since the first design is simply not good, and it violates the one-responsibility-only principle. If you search, filter, and print the filtered you are doing multiple things, so you need to refactor it into "searched filtered" and print.

The only thing different than a simple refactoring here is that it also affects performance, in the same way that inner loops can be designed in ways that harm performance.

Uri
A: 

The performance of the first one can actually be fine, depending on the type of Emails. If it's just an iterator (think of std::vector::begin() in C++) then it's fine and better than storing all unsent e-mails in some container first.

In which case 1800 Information's name is still right. Efficient lazy filters are efficient!
Steve Jessop
My point was that all the records were dragged over to the app from the db for no good reason.
WW
It is silly to fetch all the emails from the database when most have been sent when the DBMS can do the filter and only transfer those that have not been sent. -1.
Jonathan Leffler
@jonathan: You misunderstood my post. What I said was that the provided pseudo code didn't necessarily mean that all the emails have been fetched from the database. It depends on the type of 'Emails'. If it's just an iterator then nothing has been actually fetched yet.
+4  A: 

I saw that once. That programmer wasn't around too long.

We called that the "firehose method".

Scott Whitlock
A: 

This antipattern has several possible names.

  • "Don't-know-SQL" antipattern
  • "Fascist-DBA" antipattern
  • "What-does-'latency'-mean?" antipattern
Steven Huwig
+2  A: 

To me it's Joel Spolsky's leaky abstraction.

It's not exactly an anti-pattern, but whoever wrote this code, didn't really understand where Active Record pattern abstraction leaks.

lubos hasko
This code made me think of ActiveRecord too, but the pseudo-code isn't ruby (they'd have "Email.send unless Email.sent" for example). How do you get around ActiveRecord's abstraction leak for iteration?
Andrew Grimm
The pseudocode isn't meant to be anything in particular. The first time I saw this it was in C++
WW
Yeah, Active Record is a generic pattern that could be implemented in any language. Ruby on Rails just happens to have a well-known implementation. It's also sometimes called an "Entity Class".
Jesse Smith
+1  A: 

Appear to have derived from the following anti-patterns:

The original developer would have possibly not been allowed to write the find_unsent_emails() implementation, and would therefore have reused the midget function. And then, why change it after development and testing?

Vineet Reynolds
+1  A: 

I call that "The Shotgun Approach".

jedihawk
+1  A: 

This is frequently due to it being a lot easier to use an existing query and then filtering in code than getting a new SQL query added. Maybe because the DBAs control all queries and getting a new query approved takes days, or maybe because the ORM tool you're using makes it very difficult to define your own custom queries.

If I were to name it I'd call it the "Easy Way Out" (anti)pattern. Whether it's an antipattern or not really depends on the individual situation. If it will always be a fairly small number of items you need to retrieve, doing the filtering in code really isn't a big problem. But if the number of items is large and has the potential to continually grow, then obviously the filtering should be done on the server.

Jesse Smith
A: 

There is a nice example at The Daily WTF.

Svante
+1  A: 

I've seen similar issues elsewhere, where instead of a simple array of things to do, there was a "transaction cluster" based on a "list cluster" based on a "collection cluster" based on a "memory cluster". Needless to say, the simplest thing turned into a great big freakin' deal.

I called it galloping generality.

Mike Dunlavey
A: 

Inspired partly by 1800's "the lazy filter (anti) pattern", how about "dysfunctional programming" (ie the opposite of functional programming)?

Andrew Grimm