DRY

Building Browsergames: DRYing out our stats

Over the course of developing our game, our database has sort of grown organically. As we added a new feature, we’d add the tables we needed to accomodate this feature. While this works(and has been working for us just fine), it’s not neccessarily the best way to design your database - because as you can see, we now have 3 stats tables(user_stats,monster_stats, and item_stats) when we only actually need one - as sepp has once again helpfully pointed out.

With that in mind, we’re going to create another table, to replace those three. Because lots of different things can have stats, I’m going to call the table entity_stats - although if you want to, you can call it whatever you want(but make sure to keep your change in mind when you’re working through this code). Here’s what we’re going to do to create the table:

CREATE TABLE entity_stats (
	id int NOT NULL AUTO_INCREMENT,
	stat_id int,
	entity_id int,
	value text,
	entity_type ENUM('User','Monster','Item'),
	PRIMARY KEY(id)
);

Now that we’ve created this new table, we’re going to need to customize our SQL queries slightly. Previously, we were only using an object’s ID value to retrieve the stats for it - now that we don’t have that separation, we will need to run the query based on two things - the object’s ID, and the object’s type.

Because we’ve been doing re-writing to our stats code, we’re actually in a good position to make this change - we only need to change the query in one file, instead of 3(or more). Our old SQL looked like this:

"SELECT value FROM table WHERE stat_id = (SELECT id FROM stats WHERE display_name = 'foo' OR short_name = 'bar') AND column = 'baz'"

The new SQL is going to look like this:

"SELECT value FROM entity_stats WHERE stat_id = (SELECT id FROM stats WHERE display_name = 'foo' OR short_name = 'bar') AND entity_id = 'baz' AND type = 'bat'"

One of the benefits of doing this is that we’re actually going to be cleaning up our new DRY stats code a little bit more, too - we get to trim it down to only take a ‘type’ argument, instead of the table and column names it needs to retrieve with. Think back to our DRY stats code from earlier:

PHP

1
2
3
4
5
6
7
8
9
10
11
12
function getStatDRY($tableName,$columnName,$statName,$trackingID) {
	createIfNotExistsDRY($tableName,$columnName,$statName,$trackingID);
	$query = sprintf("SELECT value FROM %s WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND %s = '%s'",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($trackingID));
	$result = mysql_query($query);
	list($value) = mysql_fetch_row($result);
	return $value;		
}

Perl

1
2
3
4
5
6
7
8
9
10
11
sub getStatDRY {
	my ($tableName,$columnName,$statName,$userID) = @_;
	my $dbh = $dbh;
	createIfNotExistsDRY($tableName,$columnName,$statName,$userID);
	my $sth = $dbh->prepare("SELECT value FROM $tableName WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND $columnName = ?");
	$sth->execute($statName,$statName,$userID);
	my $value;
	$sth->bind_columns(\$value);
	$sth->fetch;
	return $value;
}

And here’s what it looks like with the change made:

PHP

1
2
3
4
5
6
7
8
9
10
11
function getStatDRY($type,$statName,$trackingID) {
	createIfNotExistsDRY($type,$statName,$trackingID);
	$query = sprintf("SELECT value FROM entity_stats WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND entity_id = '%s' AND entity_type = '%s'",
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($trackingID),
		mysql_real_escape_string($type));
	$result = mysql_query($query);
	list($value) = mysql_fetch_row($result);
	return $value;		
}

Perl

1
2
3
4
5
6
7
8
9
10
11
sub getStatDRY {
	my ($type,$statName,$trackingID) = @_;
	my $dbh = $dbh;
	createIfNotExistsDRY($type,$statName,$userID);
	my $sth = $dbh->prepare("SELECT value FROM entity_stats WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND entity_id = ? AND entity_type = ?");
	$sth->execute($statName,$statName,$trackingID,$type);
	my $value;
	$sth->bind_columns(\$value);
	$sth->fetch;
	return $value;
}

Once we’ve made those changes, it’s easy to modify all of our code for the new database structure:

PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
 
include 'database.php';
 
function getStatDRY($type,$statName,$trackingID) {
	createIfNotExistsDRY($type,$statName,$trackingID);
	$query = sprintf("SELECT value FROM entity_stats WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND entity_id = '%s' AND entity_type = '%s'",
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($trackingID),
		mysql_real_escape_string($type));
	$result = mysql_query($query);
	list($value) = mysql_fetch_row($result);
	return $value;		
}
 
function setStatDRY($type,$statName,$trackingID,$value) {
	createIfNotExistsDRY($type,$statName,$trackingID);
	$query = sprintf("UPDATE entity_stats SET value = '%s' WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND entity_id = '%s' AND entity_type = '%s'",
		mysql_real_escape_string($value),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($trackingID),
		mysql_real_escape_string($type));
	$result = mysql_query($query);
}
 
function createIfNotExistsDRY($type,$statName,$trackingID) {
	$query = sprintf("SELECT count(value) FROM entity_stats WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND entity_id = '%s' AND entity_type ='%s'",
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($trackingID),
		mysql_real_escape_string($type));
	$result = mysql_query($query);
	list($count) = mysql_fetch_row($result);
	if($count == 0) {
		// the stat doesn't exist; insert it into the database
		$query = sprintf("INSERT INTO entity_stats(stat_id,entity_id,value,entity_type) VALUES ((SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s'),'%s','%s','%s')",
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($trackingID),
		'0',
		mysql_real_escape_string($type));
		mysql_query($query);
	}	
}
 
?>

Perl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package statsDRY;
 
use database;
 
sub getStatDRY {
	my ($type,$statName,$trackingID) = @_;
	my $dbh = $dbh;
	createIfNotExistsDRY($type,$statName,$userID);
	my $sth = $dbh->prepare("SELECT value FROM entity_stats WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND entity_id = ? AND entity_type = ?");
	$sth->execute($statName,$statName,$trackingID,$type);
	my $value;
	$sth->bind_columns(\$value);
	$sth->fetch;
	return $value;
}
 
sub setStatDRY {
	my ($type,$statName,$trackingID,$statValue) = @_;
	my $dbh = $dbh;
	createIfNotExistsDRY($type,$statName,$userID);
	my $sth = $dbh->prepare("UPDATE entity_stats SET value = ? WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND entity_id = ? AND entity_type = ?");
	$sth->execute($statValue,$statName,$statName,$trackingID,$type);
}
 
sub createIfNotExistsDRY {
	my ($type,$statName, $trackingID) = @_;	
	my $dbh = $dbh;
	my $sth = $dbh->prepare("SELECT count(value) FROM entity_stats WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND entity_id = ? AND entity_type = ?");
	$sth->execute($statName,$statName,$trackingID,$type);
	my $count;
	$sth->bind_columns(\$count);
	$sth->fetch;
	if($count == 0) {
		# no entry for that stat/user combination - insert one with a value of 0
		$sth = $dbh->prepare("INSERT INTO entity_stats(stat_id,entity_id,value,entity_type) VALUES ((SELECT id FROM stats WHERE display_name = ? OR short_name = ?),?,?,?)");
		$sth->execute($statName,$statName,$userID,0,$type);
	}	
}
 
 
1;

And with that done, our change is made! Now it’s just a matter of modifying the code we created for each stat specifically(only one shown):

PHP

1
2
3
4
5
6
7
8
9
10
11
12
<?php
 
require_once 'stats-dry.php';
 
function getStat($statName,$userID) {
	return getStatDRY('user',$statName,$userID);
}
function setStat($statName,$userID,$value) {
	setStatDRY('user',$statName,$userID,$value);
}
 
?>

Perl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package stats;
use DBI;
 
use statsDRY;
 
sub getStat {
	my ($statName,$userID) = @_;
	return statsDRY::getStatDRY('user',$statName,$userID);
}
 
sub setStat {
	my ($statName,$userID,$statValue) = @_;
	statsDRY::setStatDRY('user',$statName,$userID,$statValue);
}
 
1;

And once all of the changes are done, you’re good! Now all of the stat values will be stored in a single table.

But what about users who have already registered for your game, or monsters and items that you’ve already added?

We definitely don’t want to have to tell every single person playing our game to re-register - so we’re going to write some quick SQL to copy the values over for us, before removing the tables that we no longer need:

INSERT INTO entity_stats(stat_id,entity_id,value,entity_type) (SELECT stat_id,user_id,value,'user' FROM user_stats);
DROP TABLE user_stats;
INSERT INTO entity_stats(stat_id,entity_id,value,entity_type) (SELECT stat_id,monster_id,value,'monster' FROM monster_stats);
DROP TABLE monster_stats;
INSERT INTO entity_stats(stat_id,entity_id,value,entity_type) (SELECT stat_id,item_id,value,'item' FROM item_stats);
DROP TABLE item_stats;

Once we’ve run that SQL, we’ll have deleted our 3 new tables - but not before we moved the data over from them to our new entity_stats table. Once you make the necessary modifications to your stats code and upload it all, take a look at your game - it will still work just like it did before!

This might seem like a weird thing to get excited about, but it’s a pretty big deal - we just changed a significant portion of our database, and didn’t break any of our existing code at all. This is why the DRY approach is so useful to have, and why you should always strive to use DRY in your designs to begin with - because making this change with the database logic spread accross dozens of files would drive even the calmest developer batty.

Building Browsergames: DRYing out our database connections (Perl)

One piece of our code that definitely needs a bit of DRYing out is our database connections - we keep copying and pasting the exact same code anytime we want to connect!

We’ve been repeatedly writing out the exact same three lines, any time we want to connect to a database - in some cases, even multiple times in the same file! This is the offending code:

1
2
3
use DBI;
use config;
my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass,{RaiseError => 1});

While this has worked for us so far, it’s still a bit of a bad idea - what happens if our game suddenly changes and needs to work off of an Oracle database? You would need to go through and find every single file where this code occurs, and manually change it. Not fun.

With that in mind, we’re going to simplify things a little bit - by creating a file that exists purely to connect to the database for us. We’re going to merge our database code with some of our configuration file code, to create a file called database.pm:

1
2
3
4
5
6
7
8
9
10
11
12
13
package database;
 
use Exporter;
use DBI;
use config;
our @ISA = qw(Exporter);
 
our $dbh;
our @EXPORT = qw($dbh);
 
$dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass,{RaiseError => 1});
 
1;

And now that that’s done, we’ll never have to worry about copying and pasting those lines again! In any file that interacts with the database, all we need to do is add this line, right at the top:

use database;

Which means we can modify our DRY stats code from looking like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package statsDRY;
 
use DBI;
 
sub getStatDRY {
	my ($tableName,$columnName,$statName,$userID) = @_;
	use config;
	my $dbh = DBI->connect("DBI:mysql:$config{dbName}:$config{dbHost}",$config{dbUser},$config{dbPass},{RaiseError => 1});
	createIfNotExistsDRY($tableName,$columnName,$statName,$userID);
	my $sth = $dbh->prepare("SELECT value FROM $tableName WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND $columnName = ?");
	$sth->execute($statName,$statName,$userID);
	my $value;
	$sth->bind_columns(\$value);
	$sth->fetch;
	return $value;
}
 
sub setStatDRY {
	my ($tableName,$columnName,$statName,$userID,$statValue) = @_;
	use config;
	my $dbh = DBI->connect("DBI:mysql:$config{dbName}:$config{dbHost}",$config{dbUser},$config{dbPass},{RaiseError => 1});
	createIfNotExistsDRY($tableName,$columnName,$statName,$userID);
	my $sth = $dbh->prepare("UPDATE $tableName SET value = ? WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND $columnName = ?");
	$sth->execute($statValue,$statName,$statName,$userID);
}
 
sub createIfNotExistsDRY {
	my ($tableName,$columnName,$statName, $userID) = @_;	
	use config;
	my $dbh = DBI->connect("DBI:mysql:$config{dbName}:$config{dbHost}",$config{dbUser},$config{dbPass},{RaiseError => 1});
	my $sth = $dbh->prepare("SELECT count(value) FROM $tableName WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND $columnName = ?");
	$sth->execute($statName,$statName,$userID);
	my $count;
	$sth->bind_columns(\$count);
	$sth->fetch;
	if($count == 0) {
		# no entry for that stat/user combination - insert one with a value of 0
		$sth = $dbh->prepare("INSERT INTO $tableName(stat_id,$columnName,value) VALUES ((SELECT id FROM stats WHERE display_name = ? OR short_name = ?),?,?)");
		$sth->execute($statName,$statName,$userID,0);
	}	
}
 
 
1;

Into something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package statsDRY;
 
use database;
 
sub getStatDRY {
	my ($tableName,$columnName,$statName,$userID) = @_;
	createIfNotExistsDRY($tableName,$columnName,$statName,$userID);
	my $sth = $dbh->prepare("SELECT value FROM $tableName WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND $columnName = ?");
	$sth->execute($statName,$statName,$userID);
	my $value;
	$sth->bind_columns(\$value);
	$sth->fetch;
	return $value;
}
 
sub setStatDRY {
	my ($tableName,$columnName,$statName,$userID,$statValue) = @_;
	createIfNotExistsDRY($tableName,$columnName,$statName,$userID);
	my $sth = $dbh->prepare("UPDATE $tableName SET value = ? WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND $columnName = ?");
	$sth->execute($statValue,$statName,$statName,$userID);
}
 
sub createIfNotExistsDRY {
	my ($tableName,$columnName,$statName, $userID) = @_;	
	my $sth = $dbh->prepare("SELECT count(value) FROM $tableName WHERE stat_id = (SELECT id FROM stats WHERE display_name = ? OR short_name = ?) AND $columnName = ?");
	$sth->execute($statName,$statName,$userID);
	my $count;
	$sth->bind_columns(\$count);
	$sth->fetch;
	if($count == 0) {
		# no entry for that stat/user combination - insert one with a value of 0
		$sth = $dbh->prepare("INSERT INTO $tableName(stat_id,$columnName,value) VALUES ((SELECT id FROM stats WHERE display_name = ? OR short_name = ?),?,?)");
		$sth->execute($statName,$statName,$userID,0);
	}	
}
 
 
1;

Because we used the our keyword to put $dbh into the root scope, we don’t need to bother re-useing the database code that we’ve created - all we do is put a use statement at the start of our code file, and we’re in business.

There is one slight caveat, however - you need to be very careful about scope in a situation like this. Because $dbh is now in the root scope, it’s very easy to accidentally try to use it when another function is trying to as well - which causes weird bugs. A good way to prevent this is to just clone over $dbh in whatever function needs it:

my $dbh = $dbh;

At which point you don’t need to worry about scope conflicts at all.

What have we gained by making this change? Well, we’ve managed to make it so that we don’t have to write as much code - and, if the way we connect to our database ever needs to change, we’ll only need to modify one file, instead of every single file in our codebase. This is one of the big benefits of DRY, and if you ever get into a situation where you need to make a change like this, you’ll definitely appreciate it!

Thursday, July 10th, 2008 DRY, buildingbrowsergames, code, design, perl No Comments

Building Browsergames: DRYing out our database connections (PHP)

In the interest of DRYing out our code a bit, there’s another change we can make: our database connection code.

Every time that we want to work with the database, we need to connect to it in order to do anything - and so far, we’ve just been copying and pasting the same code over and over and over:

1
2
3
4
require_once 'config.php';		// our database settings
$conn = mysql_connect($dbhost,$dbuser,$dbpass)
	or die('Error connecting to mysql');
mysql_select_db($dbname);

While that works, it means that we have the exact same code in way too many places- which is a Bad Thing™. Instead of copying and pasting the code into each page or function that needs to interact with the database, we’re going to break the code off into its own file, named database.php:

1
2
3
4
5
6
<?php
require_once 'config.php';		// our database settings
$conn = mysql_connect($dbhost,$dbuser,$dbpass)
	or die('Error connecting to mysql');
mysql_select_db($dbname);
?>

And now, because we’ve made that change we can stop having to paste out all those lines - this is the only line you need in a piece of code that interacts with the database:

include 'database.php';

This means that we can modify our DRY stats code from this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?php
 
function getStatDRY($tableName,$columnName,$statName,$trackingID) {
	include 'config.php';
	$conn = mysql_connect($dbhost,$dbuser,$dbpass)
		or die ('Error connecting to mysql:');
	mysql_select_db($dbname);
	createIfNotExistsDRY($tableName,$columnName,$statName,$trackingID);
	$query = sprintf("SELECT value FROM %s WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND %s = '%s'",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($trackingID));
	$result = mysql_query($query);
	list($value) = mysql_fetch_row($result);
	return $value;		
}
 
function setStatDRY($tableName,$columnName,$statName,$trackingID,$value) {
	include 'config.php';
	$conn = mysql_connect($dbhost,$dbuser,$dbpass)
		or die ('Error connecting to mysql');
	mysql_select_db($dbname);
	createIfNotExistsDRY($tableName,$columnName,$statName,$trackingID);
	$query = sprintf("UPDATE %s SET value = '%s' WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND %s = '%s'",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($value),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($trackingID));
	$result = mysql_query($query);
}
 
function createIfNotExistsDRY($tableName,$columnName,$statName,$trackingID) {
	include 'config.php';
	$conn = mysql_connect($dbhost,$dbuser,$dbpass)
		or die ('Error connecting to mysql:');
	mysql_select_db($dbname);
	$query = sprintf("SELECT count(value) FROM %s WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND %s = '%s'",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($trackingID));
	$result = mysql_query($query);
	list($count) = mysql_fetch_row($result);
	if($count == 0) {
		// the stat doesn't exist; insert it into the database
		$query = sprintf("INSERT INTO %s(stat_id,%s,value) VALUES ((SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s'),'%s','%s')",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($trackingID),
		'0');
		mysql_query($query);
	}	
}
 
?>

Into this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
 
include 'database.php';
 
function getStatDRY($tableName,$columnName,$statName,$trackingID) {
	createIfNotExistsDRY($tableName,$columnName,$statName,$trackingID);
	$query = sprintf("SELECT value FROM %s WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND %s = '%s'",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($trackingID));
	$result = mysql_query($query);
	list($value) = mysql_fetch_row($result);
	return $value;		
}
 
function setStatDRY($tableName,$columnName,$statName,$trackingID,$value) {
	createIfNotExistsDRY($tableName,$columnName,$statName,$trackingID);
	$query = sprintf("UPDATE %s SET value = '%s' WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND %s = '%s'",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($value),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($trackingID));
	$result = mysql_query($query);
}
 
function createIfNotExistsDRY($tableName,$columnName,$statName,$trackingID) {
	$query = sprintf("SELECT count(value) FROM %s WHERE stat_id = (SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s') AND %s = '%s'",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($trackingID));
	$result = mysql_query($query);
	list($count) = mysql_fetch_row($result);
	if($count == 0) {
		// the stat doesn't exist; insert it into the database
		$query = sprintf("INSERT INTO %s(stat_id,%s,value) VALUES ((SELECT id FROM stats WHERE display_name = '%s' OR short_name = '%s'),'%s','%s')",
		mysql_real_escape_string($tableName),
		mysql_real_escape_string($columnName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($statName),
		mysql_real_escape_string($trackingID),
		'0');
		mysql_query($query);
	}	
}
 
?>

Can you see what we did there to reduce repetition? Because the variable $conn from database.php ends up in the root scope, we can access it from anywhere within our code - which means we only need to add that single line to the beginning of our code, and it will just work - without us having to repeat even that one line anywhere other than at the top of our code. Nice!

Wednesday, July 9th, 2008 DRY, buildingbrowsergames, code, design, php No Comments

About

Building Browsergames is a blog about browsergames(also known as PBBG's). It's geared towards the beginner to intermediate developer who has an interest in building their own browsergame.

Write for us!

Have you built a browsergame before, or do you have an opinion to share on the subject? Send an e-mail to buildingbrowsergames@gmail.com!