Facebook Perl source code from 2005
gist.github.com
gist.github.com
The Mysql module was deprecated in favour of the unified DBI interface, cgi-lib.pl was a perl4 library that was replaced by a module called CGI (shipped with perl5 itself from 5.4+).
Calling functions with & is a perl4-ism and almost always the wrong thing to do in perl5, and C-style for is silly in most cases in Perl - for example; the loops in there would likely be better redone as foreach loops, or possibly just a grep.
And, of course, YAY not using placeholders in the SQL.
sigh
a) Serve b) Improve quality c) goto a)
Let's say things had turned out a little differently, and someone had used one of those SQL injections to irreversibly erase all of early Facebook's data. We'd probably never have heard of it again.
Code quality is a good thing - like scalability, and security. Ultimately, you might succeed without it. But it'll probably be easier if you do.
}
}
}
}
}
}
To be fair I've seen that pattern in just about every codebase I've touched, sadly.My problem with this code is not aesthetics. This logic is too deeply nested, by the time you hit the last conditional there is way too much going on[1].
Perl makes it especially nice to flatten logic due to RHS conditionals, eg "x++ if y;". Here is my two minute flattening job[2], it prob has syntactic errors but you get the gist.
[1] http://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_...
Seriously though, I use maps and greps a lot now, often chained to transform a data structure from one type to another. I'm annoyed when I have to drop to a for(each) loop.
Edit: I revise the terrible bit, it's a little terrible, as it has SQL injections.
Can you point out specific instances of where it is amateur? That would be more helpful to learners.
It's full of SQL injections, to start. (I really like using the subdomain name from the HTTP_HOST environment variable in a SQL query. That's a new attack vector I hadn't considered.)
It's full of silly inefficiencies, such as iterating over an array and preparing distinct but trivially parametric queries for each element.
It has a strange mix of effectively package global lexical variables and block-scoped lexical variables, which means that running this in any sort of persistent service model would be very buggy.
It looks like it ignores parts of the CGI standard.
It looks like it takes database connection information from cookies (except it never uses that code).
The `find_node` function looks like it's using the wrong data structure entirely, but that's okay, because that pattern's repeated a few times. That's doubly suspect, because this seems like the sort of thing a WHERE clause in the SQL query could handle (though to be fair, it might require a subquery, and the version of Mysql Facebook had deployed in 2005 might not have supported those very well; I don't remember).
sub morph {
my ($number) = @_;
return ((((($number % 7) * 13) % 17) * 19) % 23);
}
It appears to be some sort of quick authorization check (there is a later `$code == &morph($user)` comparison).http://www.wolframalpha.com/input/?i=plot+%28%28%28%28x+mod+...
If the input is only integers, the same pattern still appears:
http://www.wolframalpha.com/input/?i=plot+%28%28%28%28floor%...
(I quit sometime around '08 or '09, after they started going downhill.)
After you get passed all of that you are left with very little information that actually matters (status updates/pictures etc.) It's a combination of a problem with both the userbase and the platform.