# Programming Guidelines

If you're contributing code back into LiveJournal, be sure to follow the following guidelines:

## Security

- all GET/POST form values go into %FORM into BML, but check `LJ::did_post()` on critical actions. GET requests can be easily spoofed, or hidden in images, etc.

- never read in arbitrary amounts of input

- never use unsanitized data in a command or SQL

## General

- BML pages shouldn't interface with the database much. Use the LJ::* API & the protocol handler.

- always use the `LJ::` functions that take an explicit database handle. don't use the old `main::` functions that use the global $dbh.

- all files should have `<LJDEP>` edge dependency somewhere, usually at the bottom.

- using userids (integers) for things is better than using users (strings), except in URL arguments, where pretty is more important than speed.

- in BML page, use BML blocks defined in global.look: LJUSER, P, H1, H2, STANDOUT, HR, etc...

- all HTML should be XHTML compliant.:

  - lower case tags, `<BR>` ⇒ `<br />`

  - quotes around attributes <font face="helvetica">

  - no bare & chars ... always escape them: &amp; and <a href="foo.bml?a=1&amp;b=2">...</a>

- use of multiple files to do one function is deprecated. there should no longer be "foo.bml" and "foo_do.bml" like there used to. that's ugly.

- tab is a formatting command, not a character. (TODO: add note about save hooks for emacs & vi) there should be spaces in the files, not tab characters

## Database

- check your db index usage... mysql's "EXPLAIN" is your friend.

- between LOCK TABLES & UNLOCK TABLES, never call a subroutine.

- check the DB error code after an SQL statement. just because it worked once and the SQL is correct, that doesn't mean the table might not go corrupt, a disk might fill up, or index space within the file might not fill up. errors happen. deal with them.

- preferred way to break up a long SQL query:

        $sth = $dbh->prepare("SELECT cola, colb, colc, cold FROM foo ".
                             "WHERE colb<>cola AND colc=22");

- Note on variable naming:

  `$sth` | statement handle
  `$dbh` | one database handle (usually the master)
  `$dbs` | set of database handles [master(, slave)]
  `$dbr` | read-only slave db handle (used for selects)
  `$dbarg` | argument that can take a $dbh/r or $dbs
  `$remote` | hashref of remote user, based on cookies. will contain 'userid' and 'user' params, unless faster get_remote_noauth was used, in which case only 'user' will be present.
  `$u` | a user 'object' (a hashref)

## Performance & Scalability

- Large chunks of code should be preloaded in libraries. Code in BML pages is re-evaled on every request, so it should be small. If you need a lot of code, put it in a library and load it in cgi-bin/lj-bml-(init|local).pl

- don't write temporary files to disk... all LJ code should be able to run on a cluster of web servers with no session persistence

- if you're calling a function with a $dbarg parameter and you have both a `$dbs` and `$dbh` available, call the function with your `$dbs` ... otherwise the function and all its callees can't ever use the slave databases.

## Patches

- all patches sent in should be in diff -u format

- don't send in patches that comment out old code. if we want the old code, we'll go get it from CVS.. that's what it's for

## Perl Style

- `foo()` looks prettier than `&foo()`. let perl 4 die.

- lines longer than 80 characters are okay, but not great.

- if you're in package LJ and calling an LJ::* API function, go ahead and type the extra four characters (LJ::) even if they're not necessary... being explicit is nice for the reader.