Stalk me on the internet

I was asked a seemingly-innocuous question lately that actually turned out to be pretty interesting: “Do you do much object-oriented programming in PHP, like design patterns?” (I’m paraphrasing, actually, I am terrible at remembering exact quotes.) And while I very frequently find myself pretty deep in class structures, I wouldn’t say I do a lot of design-pattern-style OO programming.

Honestly, I find that – at least for PHP – a great many design patterns are completely unnecessary. PHP has enough functional chops that you can avoid needing to implement many of the uglier patterns, although you’re going to find people who try, I’m sure.

Some Good Patterns, Though

The Observer pattern is pretty solid, honestly. Essentially, you can use it to allow objects to “observe” specific points in time and specific events, and then react to them. The really nice thing about intelligently implementing the Observer, is that it makes it very easy to extend a base engine with modular add-ons. You can then turn on or off these modules without affecting the rest of your application, and debugging becomes a lot easier too.

When Are Patterns Better?

There are definitely some situations where I prefer design patterns to functional programming, specifically in the case of factories vs. currying. Since I’m far more likely to be working with many sets of objects instead of bunches of discrete functions, factories are easier to understand and use, even though you can use currying to build your own frankenfunctions to do similar things.

When are Functional Methods Better?

Oh man, I love passing functions as parameters in PHP. How about for when you want to do a custom array sort? Or when you want to trim every string in an array? Or setting up that Observer pattern above, triggering events inside your main engine? It’s such good times.

Compare this to the Chain of Command Pattern. Just look at that crazy thing. Holy moly.

I’ll just pass functions, thanks.

So Why Shoehorn Design Patterns Into PHP?

If you programmed in Java, read Design Patterns: Elements of Reusable Object-Oriented Software and it changed your life, you may want to bring those same design patterns across to PHP. Some of them will be a good choice, but some of them will just be comfortable bad choices. They’re comfortable because you’re used to implementing and maintaining them, but they’re a bad choice because PHP provides you with better tools to get the job done.

The real trick – as with anything else in programming – is know when to use what.

Wait, nothing’s wrong?

Posted by on 13.01.2013 in Coding

I recently read a tweet that really set me to thinking:

I’ve had this same thought many, many times throughout my career, but I can’t help but notice that it’s been in entirely different contexts.

Phase One: Sweet! No Syntax Errors!

When first learning how to code, or later on when learning new languages, it can be pretty shocking when you hit the compile button and your console doesn’t light up like a christmas tree. You may not have typed a lot of code, but you didn’t have to Google any function signatures or anything, and it compiles and runs. Mostly. I mean, it doesn’t do what you want to do at all, but it still compiled, right?

Modern IDEs mostly mitigate this stage, due to real-time syntax checking. I don’t think I’ve had more than a syntax error per week since switching to a competent IDE (Sublime Text 2, if you’re wondering).

Phase Two: My function works!

Eventually, you get comfortable enough with a language to be able to write a solid chunk of code – perhaps a whole, medium-sized function – run it, and have it run as you expect. This is always a delight when it happens, as you’ve demonstrated the ability to hold the current problem space in your mind long enough to solve it and commit it to code. I imagine this is roughly how a juggler feels once they get the basic three-ball rotation down.

Phase Three: I AM A GOD.

It’s been maybe a half-hour, perhaps even as long as an hour since last you hit the compile button. You’ve been in multiple files, up and down the class structure, at all levels of project complexity. You’ve changed dozens, close to hundreds of lines of code, maybe even rewritten a whole class or low-level algorithm. You’re just… in the zone. Eventually you realize how long it’s been since you’ve tried out your changes, and ever-so hesitantly run them. Then, before your very eyes, everything works as intended.

The only possible answer? You are a tiny god, completely in control of your environs.

Phase Four: Oh no, where’s the bug?

Exactly the same as above, except you are old enough and wise enough to know that the fact that it didn’t break on run means that the bug is subtle, hidden, and dangerous.

Time to write more tests.

Just a head’s up – don’t use eBay to sell anything. Save yourself the time, effort, and money. That’s the tl;dr. But here’s the rest of the story:

So the iPhone 5 was coming out, and I very carefully determined the optimal time to start an auction for my iPhone 4. I wanted it to end after my iPhone 5 had arrived, and ensure that it arrived on a “good day” for last-minute bidders. I had spent a few hours on this, as I expected to get at least a couple hundred dollars and a good ending time could mean $50 or more on the price difference.

Mid-way through the auction, I saw that my little ol’ iPhone 4 was going for around $600, which is outrageous. Some quick Googling later, and I found out that this is apparently a very common phenomenon in the electronics category. Unscrupulous sellers will register fake accounts and bid up items competing against theirs to make their own auctions look better. The only solution is manually policing your bids and removing any from people with less than 3 positive feedback.

And that’s really the only solution! eBay offers tools to automatically block people with less than 0 feedback, but not any positive numbers. Further, eBay doesn’t offer any way to report these users (at least none that I found, and I looked for a while). So I spent the entire rest of the auction looking in on it frequently, manually pruning suspicious-looking bidders.

Finally, the auction wound down for a reasonable price. I contacted the winning bidder and… nothing. No response by email or through eBay or anything. I waited the requisite number of days and sent a second-chance offer to the next person on the list and… nothing. The same for the third and fourth. No responses from any of them at all.

A little upset, I decided to just leave negative feedback for the original bidder and relist. But… there’s no way to do that! Since I last stopped using eBay, they removed (or hid) the ability to leave negative feedback for a buyer, making their whole reputation system pointless and their automatic bid screening system useless.

Stymied at leaving negative feedback, I at least figured I’d relist, which I did with an additional paragraph about how I’d cancel bids from people with bad or no feedback scores. (Which is also difficult to do, by the way – a manual form found nowhere convenient to your actual bid list.) But the same exact thing happened, except this time the eventual winner didn’t read the auction clearly enough and didn’t realize that the phone was locked to a different carrier. All the other second-chance offers I sent out were completely ignored as before.

Frustrated, I cancelled that auction and decided to sell on Kijiji or Craigslist or through friends or something. I definitely wasn’t going to deal with eBay again.

Except that now I have to. It seems that they think I still owe them $2.00 for the privilege of wasting weeks of my life fighting scammers in their decidedly anti-seller system. I’ve tried to contact support by email, but that option doesn’t exist – the only option they provide for contact is a phone number that Google searches say can have up to hours long wait times that I have no interest in waiting through.

Eventually I found a vestigial web form for reaching out to customer support, where I detailed my case. It promised a response within 24 to 48 hours. Well, I got one within ten minutes, which directed me to phone them, and not to reply to that email because it is not monitored.

Look, in the end I just want to not constantly get these collection reminder emails. It’s not worth my time to spend an hour or more waiting for and then arguing with a customer support representative over this. So fine, I’ll pay it. Whatever.

But it definitely is worth a half-hour of my time to write up the truly awful, terrible, reprehensible experience I’ve had with eBay’s shitty service and customer support system.

eBay, I hope the word of mouth you get from this is worth the $2.00 it would have cost you to just refund those fees. You know, if you had a reasonable customer support system set up to allow for it.

When I was younger, I enjoyed an afternoon playing the board game “Stock Ticker”. It was a new concept to me (no board to travel around), it dealt with money (and getting rich), and I was playing it with some really great friends. All in all, it was an enjoyable experience.

But what stayed with me through the years was the question: “Wouldn’t this game be more interesting if the player had more agency?” As it was, the game was very, very random, with interesting decisions only really happening near the Off Market line – and even those were just betting with higher variance. Over the past few weeks, I’ve been thinking about how to do that, and I think I’ve come up with something fun to play.

I’ll definitely try putting together a prototype and guilting my friends into playing it, but for anyone else interested, I’m putting the rules online as well. If you try a game, let me know!

Insider Trading

Sometimes being a super-wealthy financial mogul isn’t enough anymore. You have to be the best super-wealthy financial mogul. And that involves proving your worth. You and up to five other players play the part of well-connected and unscrupulous capitalists, attempting to settle a bet: With just $5000 and your own resources, how much money can you make in five years? The winner gets the best table at the country club, while everyone else is forced to eat at the servant’s table. Ugh.


  • Game board: A tall board with 5 Price columns and five Quarterly Report squares. Five companies are depicted thereon, with each company having a column and a square all its own. The Price columns go from “BANKRUPT ($0)” at the bottom to “SPLIT ($200)” at the top in $10 increments. The $100 row is specially highlighted.
  • 5 Price Markers, one for each company.
  • 10 Quarterly Report cards. These cards have the numbers 1-6 on them, alongside a value adjustment, such as +$10 or -$30. When the Quarterly report is resolved by rolling a d6, look up the number rolled, and adjust the stock price by the value adjustment listed.
  • 50 Influence cards. These cards have Quarterly Report-altering effects on them, such as “On a 6, +$10″, or “For all rolls less than 3, roll again.” They also have a cost listed, indicating the amount of stock that must be forfeited to activate the Influence card.
  • A whole whack of play money.

Game Setup

  1. Place the game board on the table, with markers for each company in the middle of the board at the $100 level.
  2. Give each player $5000.
  3. Shuffle the Influence deck and deal out 3 Influence cards per player.
  4. Shuffle the Quarterly Report deck and deal one on each company’s Report square.
  5. Give the First Trader token to the winner of a roll-off (highest wins, ties re-roll).

Turn Order

  1. Purchase Phase:
    1. Play starts with the First Trader.
    2. Choose a single Quarterly Report card to secretly peek at. This card *cannot* be shown to any other player, but the peeking player *may* choose to share the information gained. The information shared does not have to be complete, accurate, or even correct.
    3. Buy stock from the board, or sell stock you own. Stock is bought and sold to and from the bank, and for the price currently listed on the board.
    4. Play passes to the next player clockwise, until all players have played.
  2. Influence Phase:
    1. Players may play Influence cards face-down on top of company Quarterly Report cards, provided they pay the cost of the Influence card in shares of stock *for* that company.
  3. Report Phase:
    1. Reveal each company’s Quarterly Report and Influence cards in turn from top to bottom. Then, roll for each company in turn from top to bottom and resolve their Quarterly Report and Influence cards.
    2. Any stock that has reached “SPLIT ($200)” has split! Anyone who owns that stock receives an additional amount equivalent to their current amount, doubling the amount they own. The stock’s price is moved back to $100.
    3. Any stock that has reached “BANKRUPT ($0)” has gone bankrupt! Anyone who owns that stock forfeits it entirely. The stock’s price is moved back to $100.
  4. Cleanup Phase:
    1. Quarterly Report cards go back in the deck, which is re-shuffled. Deal out one card on each company’s Report square, as before.
    2. Influence cards go into the Influence discard pile. Players draw Influence cards to bring their total back up to 3. Players may choose at this time to discard *one* Influence card, though they will have to wait until next turn to refill. If the Influence deck runs out, reshuffle the discard pile as the new Influence deck.
    3. The First Trader token is passed to the next player, clockwise.


The game progresses for five game years, or twenty game quarters. The winner is the player with the most value in their portfolio, including cash on-hand and stocks at current board value.

Recently, one of Retuers’ blogs was hacked, and false stories were posted as if they were real news.

Now, while that’s news in and of itself, the big takeaway that’s relevant to me and PanicPress is that if Reuters can have one of their blogs broken into, anyone can.

Obviously, they use secure passwords at Reuters, and have backups, and keep their blogging software up-to-date – the works. Well, okay maybe not “obviously”, but it’s a solid guess. They probably take as many precautions as the can, and they still managed to be hacked and have false stories posted.

Would PanicPress have made a difference? Very possibly! One of the most important concepts in security is the concept of layers – that is having a whole bunch of security systems in place, all working in tandem. PanicPress provides yet another layer of security that WordPress doesn’t otherwise offer, and even if a hacker managed to guess or steal a legitimate reporter’s password, it’s highly unlikely they’d be using it from a known IP. PanicPress would have detected that and alerted the administrator, who could have shut down the admin section before the hacker had a chance to post those fabricated stories.

I’m really looking forward to launching for real – the “todo” list is getting much, much shorter by the day, while the need for PanicPress grows.

Yes, yes he should.

Posted by on 05.08.2012 in Coding

Nerd humour time.

I’m having some trouble with my coffeescript compiler. Every time I try to get my webserver to compile a new coffeescript file as part of developing this new website of mine, I get the following error:

env: node: No such file or directory

Near as I can tell, this means that “node” doesn’t know where the “coffee” script is (“node” being the execution environment used to run the “coffee” script, which compiles coffeescript into javascript to be run in the browser).

For a little bit, I was concerned that this was because I didn’t have my environment variables set up correctly for the _www user (the user that Apache normally runs as), but then I recalled having changed the user Apache runs as… to me.

Perplexed, I uttered: “The hell? Dan should know where coffee is!”

Yes. Yes Dan should know where coffee is.

I’m gonna go pour myself a cup right now, actually.

EDIT: Solved thanks to the internet and this kind fellow.

Well, it sure has been a while since I’ve posted. I have that terrible habit, of course – I get so involved in Doing Other Things that I neglect the ol’ blog in-between. Apologies. Won’t happen again. (Yes it will.)

Now while I love doing what I’m good at, I wanted to take a break from not posting to share what I’ve been working on:

PanicPress – A WordPress plugin that adds a critical extra layer of security on top of your blog. The moment an attacker tries to access your WordPress administration section, you get a warning text.

But let’s take that one step further – reply to that text with one of your own reading “panic”, and the entire administration section will shut down with a convincing-looking PHP error, giving you the time necessary to find out and fix what’s broken. Once you’ve solved your problem, texting “safe” will restore the administration section and let you get back to posting uninterrupted.

I’m nearly ready to launch the site – about 90% or so. But as they say, the first 90% takes 90% of the time. The last 10% takes the other 90% of the time. I expect to launch with a Minimum Viable Product within a week or two.

If you’re interested in hearing about the launch on Day One, hit the Sign Up page anyway! I’m collecting email addresses from interested parties, and the moment I finish putting the site live for real, I’ll send an email out to everyone on that list. (And after that, I’ll discard that list forever, so please don’t worry about spam on my behalf!)

In the meantime, if you wouldn’t mind visiting the site and clicking the little “Like” button up in the corner, oh and if you could go and like this Facebook page too, that would be a real help. Anything you can do to spread the word!

So Much Fail.

Posted by on 14.05.2012 in Games

The only thing worse than this video:

Is the comments beneath it.

lol, is this supposed to be “hot” or something? I guess this kind of marketing works on virgins or something, but it’s funny how much this shit doesn’t even faze you once you get a girlfriend. Try again, Ubisoft — this bitch is hideous, your game looks generic, and you should probably fire your marketing department.
BTW, it’s pretty obvious that your marketing bots gave you 600 of those likes.

– SolipsistGrifter

Wow, this chick(?) is hideous… What terrible marketing. She looks like some Las Vegas tranny with bad plastic surgery (sorry) and this is supposed to make me want to play this game? Even if you didn’t objectify ugly women to sell your shit game I probably still wouldn’t play it; looks like every other generic brown shooter.

– phubans

I love how they purport to attack the sexism in the ad, while throwing out phrases like “this bitch is hideous” and “Las Vegas tranny”. My god, the irony in the sentence “Even if you didn’t objectify ugly women to sell your shit game”… So hold on, objectifying women upsets you, and you focus on whether the woman in the ad is pretty or not to judge her value?

The internet makes me so sad some days.

When writing code, so many things can go wrong. So many little things can be forgotten or overlooked and cause bugs and interruption. However, your time is finite and your patience is limited. Removing all these little causes of frustration pays incredible dividends down the line.

One of the frustrations I regularly encounter is failing to save a file in our backend tool after making modifications in SVN, which is caused by a permissions conflict. The user I run SVN as (me) is different from the user I run Apache as (_www by default), which means that if when I own a file, Apache can run into trouble trying to save it (such as through our backend tool).

For a while, I depended on a custom bash script that would recursively modify the permissions in my development folder, but I still have to remember to run that script every time I make certain modifications via SVN. Every once in a while I’ll forget and get glaring error messages. It breaks my flow, which slows me down and frustrates me. Thankfully, there is an easy solution.

Be someone else

If Apache runs as the same user that SVN does, suddenly these problems dissappear. They both have the same rights and access to the files, and no longer need I worry about running scripts to fix things.

Kick open a console:

$ sudo nano /etc/apache2/httpd.conf

Find the line that says:

User _www

And change “_www” to your username. If you’re not sure what that is, type “whoami” at the console to find out. With that done, save and restart Apache:

$ sudo apachectl restart

From here on out, your problems should be solved! (Well, you may need to change permissions on or remove certain files created by _www, like session files.) Apache will open and save files as you, so as long as you have access, so too will your web server.

Seriously, if you haven’t fallen in love with spreadsheets yet, you’re doin’ it wrong. I’m currently in the middle of figuring out a multiple-week game loop with really tight targets. How the heck would you ever get this done without a well-constructed spreadsheet? Trial and error would take forever. Guesstimates wouldn’t get you anywhere near what you wanted. No, you need constantly-updating formulae and graphs and colours and stuff. The difference it makes in your capabilities is insane.

A quick example

Say you have an enemy – a cute little slime-creature. And when he’s defeated, he drops a macguffin – but occasionally! Players need ten of these macguffins to progress to the next area, where there’s a boar who drops a similar macguffin. And in the next area, there’s the final creature – a gargoyle – and ten more macguffins to collect.

Three monsters, three macguffins. We want this area to be challenging, but not too frustrating, so let’s set some base assumptions: If it takes less than 100 encounters, it’s not challenging enough. If it takes more than 300 encounters, it’s too frustrating.

Now, we could just throw some numbers onto those creatures and hope, but I’ve got a better way. Let’s set up a spreadsheet with some intuition-based numbers and see how close we come.

Table 1: Drop Rates

The first thing we need to figure out is how often a player is going to get a macguffin drop from a creature. To do that, I’ve created the following table:

Column A is the name of the creature the player will be encountering. B is the chance they will beat that creature when fighting them. C is the chance they drop the macguffin they are looking for. And finally D is the number of expected macguffins from each encounter. So far, we can see that for every time you fight a slime, you can expect to get 0.07 of a macguffin. Seems pretty low, but we’ll find out just how low in a second. Let’s make a second table.

Table 2: Encounters Needed

Column A has the same creature names as before. B is the amount we need to collect before we can progress. And C is the number of expected encounters a player will need to go through to get the amount listed in column B.

And WOW are those numbers high! Seems our intuition was off, and it’s time to play with the numbers a bit to balance this out. We have some options:

  • We could increase the drop rate of the macguffins. This will not only speed up the collection, but also reduce variance for players. (Variance is a topic for another time, but in short, you want less of it. High variance means that you’ll have a lot of players who fall outside of your expected numbers, which is either exceedingly frustrating or boring for those players.)
  • We could decrease the difficulty of the encounters. This will allow players to collect secondary assets (gold, experience) more quickly while speeding up collection as well.
  • We could decrease the number of macguffins needed. Psychologically, collecting 10 macguffins at a 10% drop rate feels a lot less like a chore than collecting 100 macguffins at a 100% drop rate.

And that’s outside of doing something crazy tricksy, like adding or removing more creatures, allowing players to buy or craft macguffins, etc. So let’s play with the numbers some, and see if we can come up with something a little more fun.

Table 3: Some Interesting Numbers

It only took me about five minutes of tweaking to come up with this, and I can already tell that it’s a lot better. For one, it only takes 191 encounters to resolve – almost exactly in the middle of our 100-300 range. For another, see how the Encounters column in the second table gently rises? It didn’t when I first started playing around with the numbers, but I quickly saw how going from 50 encounters to 25 encounters to 125 encounters would be very weird, and altered my values to suit.

Of course, you’ll still want to play-test this to ensure it’s actually fun when you play it, but this is a much better starting point for your playtest than our original numbers, and it only took five minutes to find out, and five minutes to improve it a vast amount.

Hopefully you can see how much of a difference a good spreadsheet can bring to a game developer’s toolkit. I’ve still got a few more concepts I want to cover regarding spreadsheets (the LOOKUP function, conditional formatting, etc.), so stay tuned!