Posted by Chuck Vose
Fri, 09 Jul 2010 23:50:00 GMT
Cross-posted at the Metaltoad Blog
While I’m certain that I could never work up to the standards of Peter Cooper his “Interesting Ruby Tidbits That Don’t Need Separate Posts” series was a great help to me when I was a ruby developer. You can see the original here: IRTTDNSP #1. I’ve not found similar for the Drupal community but I believe a lot of the things I do during the week are interesting but not at all worthy of a complete post of their own. So this will be my attempt to categorize and commit those very thoughts to memory. I hope that even one of these things sparks something for you.
How to get Views’ exposed filters to display in a block
If you create a block display and have some exposed filters you may have trouble getting them to actually show up. The problem is that blocks don’t seem to like to display their exposed filters unless two prerequisites are met: there must be a full page display somewhere and it must have a path, the block must be set to use ajax. I would have never guessed this either but if you look at the requests that are going across the wire they’re going to that page display and the results are coming back over ajax.
How to reorder taxonomy terms in Views’ exposed filters
On that same page we realized that we needed to order the dropdown in a reasonable way in part just to keep people from using it on the awards day to stave off some of the traffic. Analysis of traffic suggests we actually got the ordering wrong but whatever, you just want to know how to reorder taxonomy terms in an exposed filter.

Despite the ordering that Views seems to be suggesting below, the actual display order of terms is determined by the taxonomy weights page at /admin/content/taxonomy/. So you can feel confident that even though views doesn’t have a means to order your taxonomy selections, they will be ordered for you. Now the real question is though, is it possible to reorder those terms on just one page and not on another? I don’t know, maybe I’ll get to post about that later.

How to get an F5 Load Balancer to stop putting the Vary headers on your responses
When you’re using a CDN like Akamai having a Varies header in your response absolutely kills your caching despite all the hard work drupal puts into getting things right. We were seeing about 50-75% cachability through Akamai because of it. Mostly this was because Akamai couldn’t cache the JS/CSS which was clearly incorrect. After we figured out that it was the Varies header (props to Grendzy as usual :P), it was a hop skip and a jump to figure out which settings could be causing the actual problem.
Turns out the Varies header setting isn’t the culprit though it does in fact fix the problem we were having it also introduces some others. The culprit is in fact having Browser Workarounds on which fixes IE6 and gzip and not having HTTP/1.0 Requests on. Of course the manual doesn’t really describe what’s going on so massive props out to spark on the F5 forums for answering this question before I had the chance to ask it.

Conclusion
I’ve run out of time but I’d be grateful for any feedback. If people don’t find this useful I’ll not post it on planet but if you do please keep reading and encouraging me with your great comments.
Posted in Programming, Drupal | Tags drupal, f5, header, ordering, snippet, taxonomy, varies, views | no comments
Posted by Chuck Vose
Mon, 21 Jun 2010 04:59:00 GMT
Regular life post disclaimer
All apologies for a regular life post, for those that don’t know this blog can be sorted by category and the auto-rss feeds actually do work to separate by category. So my promise is that the tags Life and Programming will be stuck to religiously. If you only want to read programming related topics, and I suspect that is the case for most of you, this is the link to do so. Like any good Rails app that link works perfectly for both RSS readers and human readers.
Living guilt-free with a woman who is driven
I live with, and am hopelessly in love with, a woman who on the absolute worst days could be described merely as ‘driven’. Those of you that know her know that this word ‘driven’ pales in comparison to the actual manifestation that is my very-soon-to-be wife. At any given time she is volunteering, working a full time job, going to school or doing another volunteer position, planning a wedding, moving all our stuff from one house to another in her car instead of a truck, and making handwarmers or clothing for our cats. She is an amazing woman and I think this quote from a close friend of ours sums it up nicely: “How does it feel for everything you touch to turn into awesome?”
I on the other hand, work a job. Granted, it’s a hard job that requires lots of strenuous thinking from my ergonomic chair in a temperature controlled environment where everyone is required by corporate mandate to leave me alone, but well, actually I’ve lost my train of thought. Oh yeah, I don’t do half the stuff she does; I think I would be lucky to consider myself as doing a tenth of the incredible things she does. I merely fill a role in her life which is to be unendingly supportive and encourage her to stop working on occasion through any of a variety of methods including tickling or telling myself jokes and giggling.
The last piece of this pending nuptial catastrophe is thus: I was raised, either by my parents or my college roommates, to feel unbearable guilt and shame if someone in the house is working and I’m playing video games. There are a lot of roots here but I don’t think they bear analyzing at the moment.

Work budgeting (Conclusion)
Luckily, in addition to being ‘driven’, my beautiful love is also a complete and utter genius. I write this document to later remind me of how wonderfully smart she is (and because my memory is about 3 minutes long). How does one strike a balance when one partner relaxes by doing things, and one partner relaxes by doing nothing? Surely, even the slightest analysis suggests that this is going to end in tears when I feel guilty or she feels put-upon or under appreciated. It has, but as with all things she has come up with the following method:
We have created a chore budget. We are both required to do a small amount of chores and after that point, if she feels like continuing to work I am absolutely not allowed to feel guilty and she can feel free to derive all sorts of satisfaction from finishing things and checking them off her mental checklist. Now I know that there is an end in sight, after my chores are done I no longer get to feel guilty (she actually got mad at me and made me play video games instead of continuing folding laundry tonight).
I know that I’m not alone in the world, so if you find this blog by some happenstance and you’ve had a similar situation please let me know. Links containing various sexual enhancement drugs will probably not be accepted but it’s worth trying, I wouldn’t want to discourage anyone, especially robots.
Posted in Life | Tags compromise, Life, marriage | no comments
Posted by Chuck Vose
Fri, 04 Jun 2010 04:48:00 GMT
Cross posted at the Metal Toad Blog
I was trolling around the Internet today looking for benchmarks and I actually had a little trouble finding something current. Dries has one comparing D6 on PHP4 vs D6 on PHP5 but that was clearly ages ago. I also realize that this is going to be out of style in about 12 minutes, will probably be fraught with contention, and generally mocked by everyone; but in the interest of those few souls out there that really actually just want to know what is reasonable to expect from production hardware under some load I want to post these stats anyways.
Our setup
We’re using a gaggle of 1U SuperServers by Super Micro. The basic stats are here. We have them loaded with a pair of 4-core opterons and 32GB of RAM. Not entirely unaffordable nowadays for production kit.
These sit behind some firewalls and an F5 load balancer which helps make SSL a little quicker and makes sure that if things go down we can fail over to a different webhead. The truth is that all this redundancy stuff up front actually slows our pages down pretty heavily for small loads but when doing a lot of traffic on those happy spikey days it helps out a lot.
We’ve done a lot of the normal things to speed up the servers:
- Turn on APC, this is huge!
- Get rid of your .htaccess files and configure apache to do this at restart
- Use Boost if you can’t run Varnish, but run Varnish wherever you can
- Turn off all the devel modules
- Turn on as many of your drupal caching options as you can without breaking the site. Then figure out why the site broke and try to get those breaking caches online
- Turn on your MySQL Query Cache, it’s off by default and makes an amazing difference
- Put MySQL on its own disk, put logs and even the MySQL binlogs on a different disk if you can
- MAKE SURE YOU HAVE ENOUGH BANDWIDTH! Getting capped by your ISP will kill you during spikes since your servers will be resending lost data constantly
Commands Used
Since this article is about ab I’m not going to post our configs from SIEGE or JMeter.
Running from a box with an extremely fast network connection we were doing the following:
ab -n 10000 -c 100 -k -H 'Accept-Encoding: gzip,deflate' www.site-name.tld/
I like to run from a box within the network directly to the webhead as well to find out how much things are getting slowed down in the load balancers and firewalls. Since our webheads often do more than one site we have to use a Host header and the actual IP address as shown in the following snippet.
ab -n 10000 -c 100 -k -H 'Accept-Encoding: gzip,deflate' -H 'Host: www.site-name.tld' 192.168.0.27/
I also like to use relatively high concurrency and number of requests so that momentary spikes even out a little bit. There is a rule out on the net that you should take the average of three attempts for any benchmark and I think that’s totally necessary.
We’ve noticed that our servers start to really crack around 500 concurrent anonymous users. Peak performance seems to be around 100-200 so I stick with that so that the differences in config changes are the most obvious. If I go from 100 #/s to 250 #/s I know it’s a big change (or vice versa in a lot of cases).
Results
Without further ado, these are my results. I realize that there is certainly more that we should be doing to squeeze out performance and I also realize that my methods are pretty unscientific but I hope they give you an idea of what you might be looking for.
Internal – Test 1
Document Path: /
Document Length: 10716 bytes
Concurrency Level: 100
Time taken for tests: 40.694054 seconds
Complete requests: 10000
Failed requests: 9993
(Connect: 0, Length: 9993, Exceptions: 0)
Write errors: 0
Keep-Alive requests: 0
Total transferred: 112128752 bytes
HTML transferred: 106842680 bytes
Requests per second: 245.74 [#/sec] (mean)
Time per request: 406.941 [ms] (mean)
Time per request: 4.069 [ms] (mean, across all concurrent requests)
Transfer rate: 2690.81 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 2 84.8 0 2999
Processing: 61 379 809.9 147 12255
Waiting: 53 344 799.4 134 12255
Total: 61 381 814.4 148 12259
Percentage of the requests served within a certain time (ms)
50% 148
66% 170
75% 265
80% 345
90% 599
95% 1371
98% 3159
99% 4725
100% 12259 (longest request)
Internal – Test 2
Document Path: /
Document Length: 10683 bytes
Concurrency Level: 100
Time taken for tests: 29.175060 seconds
Complete requests: 10000
Failed requests: 5389
(Connect: 0, Length: 5389, Exceptions: 0)
Write errors: 0
Keep-Alive requests: 0
Total transferred: 111006011 bytes
HTML transferred: 105724371 bytes
Requests per second: 342.76 [#/sec] (mean)
Time per request: 291.751 [ms] (mean)
Time per request: 2.918 [ms] (mean, across all concurrent requests)
Transfer rate: 3715.64 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 5 123.8 0 3033
Processing: 41 273 445.8 135 11841
Waiting: 36 245 430.6 124 11840
Total: 41 278 463.5 136 11851
Percentage of the requests served within a certain time (ms)
50% 136
66% 150
75% 176
80% 287
90% 491
95% 1305
98% 1534
99% 3118
100% 11851 (longest request)
External – Test 1
Document Path: /
Document Length: 10472 bytes
Concurrency Level: 100
Time taken for tests: 31.161653 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 0
Total transferred: 110620000 bytes
HTML transferred: 104720000 bytes
Requests per second: 320.91 [#/sec] (mean)
Time per request: 311.617 [ms] (mean)
Time per request: 3.116 [ms] (mean, across all concurrent requests)
Transfer rate: 3466.66 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 13 199.5 0 3051
Processing: 46 273 414.5 138 4558
Waiting: 41 246 404.3 126 4545
Total: 46 287 457.2 139 4558
Percentage of the requests served within a certain time (ms)
50% 139
66% 156
75% 299
80% 336
90% 482
95% 1119
98% 1580
99% 3143
100% 4558 (longest request)
External – Test 2
Document Path: /
Document Length: 10472 bytes
Concurrency Level: 100
Time taken for tests: 29.336590 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 0
Total transferred: 110000000 bytes
HTML transferred: 104720000 bytes
Requests per second: 340.87 [#/sec] (mean)
Time per request: 293.366 [ms] (mean)
Time per request: 2.934 [ms] (mean, across all concurrent requests)
Transfer rate: 3661.67 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 3 95.1 0 3034
Processing: 50 264 447.7 129 4532
Waiting: 45 240 435.7 119 4528
Total: 50 268 459.6 129 6128
Percentage of the requests served within a certain time (ms)
50% 129
66% 143
75% 162
80% 295
90% 423
95% 1307
98% 1532
99% 3125
100% 6128 (longest request)
Posted in Programming, Drupal | Tags ab, benchmark, drupal | no comments
Posted by Chuck Vose
Thu, 06 May 2010 04:44:00 GMT
Cross posted at the Metal Toad Blog
When Webchick announced that Drupal was moving to Git at Drupalcon 2010, our office erupted in pleasure at the news. Lots of great Drupalists are already using Git and there’s even an unofficial Github branch of Drupal for your branching and stashing pleasure Github mirror. However, Metal Toad Media has been an SVN shop for a long time we still have a lot of processes that use SVN, so we elected unanimously to do a gradual rollout: new sites get a private repo on Github, old sites just use git-svn. Looking back I wondering why we ever delayed.
Standard Git-svn setup
If you’ve got a standard SVN setup (with trunk under trunk, branches under branches, and tags under a tags directory), then you’re lucky, because the standard Git-SVN setup is pretty much all you’ll ever need. In that case you merely need to use: `git svn clone -s https://repo.tld/repo`. After this step you’ll magically be able to switch branches super fast, commit to stage, etc.
If you have an old svn repo with just stackloads of changes use the -r flag to specify a range of revisions you’re actually interested in. We have one repo that’s well over 10k commits with tons of branches, this literally takes 20 hours to checkout with Git-svn.
Now that you’re here what do you do? There are only a couple commands you need:
git svn rebase | svn up
git svn dcommit | svn ci
git update-index --assume-unchanged path | ignore this file, great for settings.php
git checkout -- path | delete my current changes
git reset --hard | really, really delete my current changes
git merge branch_name | merge in the changes from the branch called branch_name
git stash | temporarily store my changes and check out master
git stash pop | restore my stashed changes and take those changes off of the stash list
When in doubt check out the git-svn cheatsheet and the git cheatsheet or install the cheat gem and get this direct to your command line:
sudo gem install cheat
cheat gitsvn
If you’re going to work with Github or a some other straight Git repo it’s well worth setting your Name and email address so that people know who you are and GitX can pull down your gravatar. You can do so with the following commands:
git config --global user.name 'John Doe'
git config --global user.email johndoe@example.com
I know that’s a lot of commands, it’s okay to bookmark this or the cheatsheets if you don’t want to forget. The beauty of Git is that you get to find the way that works best for you; these and a few others are all I ever need from git-svn.
Non-standard Git-svn setup
Okay, so the standard setup is all well and good but since SVN gives you the flexibility to drop branches and tags anywhere this can cause some problems for Git. Normally this is as simple and manually specifying the directories that it actually uses via the -T (for trunk), -t (for tags), or -b (for branches). However if you’re in the unlucky situation of having branches sitting alongside your trunk directory there is some additional love that you need to give.
First set up the repo as if it were a standard repo, get as much done right as you can by using -s or -T/-t/-b.
Once you have the repo checked out edit the .git/config file
In the svn-remote section take a peek at the braches/tags/fetch lines. If something doesn’t fall completely into one category add it as another fetch line. For instance, if you had a client branch that wasn’t in the branches folder you could do the following:
[svn-remote "svn"]
url = https:// svndomain.tld/svn/project
fetch = trunk:refs/remotes/trunk
fetch = client:refs/remotes/client
branches = branches/*:refs/remotes/*
tags = tags/*:refs/remotes/tags/*
After you’ve edited this you can do a `git svn fetch` to pull down all remote branches. Now when you’ve done that you should see other remote branches when you do `git branch -r` and you should be able to do awesome things like `git merge client && git commit -m “happiness is a fresh merge”`
Merging to client branch
After a while you’re going to get out of date with the client branch unless they’re doing a similar thing with git-svn. But merging into the client branch isn’t quite as easy as a normal git merge, or at least it’s not the same. Do merge from trunk -> client do the following:
git reset --hard remotes/client
git merge trunk
git svn dcommit
I’ve had varying results doing this. On some projects it seems to work great, on others it seems to switch me back to trunk instead of dcommit’ing. Worth a try at least.
Conclusion
Git has been amazing for us so far. Grendzy has been using it for about a year and I’m at about 9 months. Getting everyone else on board has been pretty easy and already I’ve seen more smiles around the office. Hope your transition is as easy and fruitful as ours is so far!
Posted in Programming, Drupal | Tags branches, drupal, git, merge, svn
Posted by Chuck Vose
Thu, 15 Apr 2010 16:30:00 GMT
Cross-posted on the metaltoad blog
Okay, as mundane as it sounds there are a lot of articles around the internet that are fundamentally misunderstanding the simplicity of this request: how do I reconnect my bluetooth device after it’s been disconnected from being in my laptop bag or whatever.
There is no reconnect option in Windows 7 and the reconnect option in OS X is fairly buried. As long as your device is in the bluetooth devices menu the following should work for you:
Mash buttons.
I know how stupid that sounds, but it’s been working for me for a couple days now and I’m staggered that I didn’t think of it earlier. I always wiggled the mouse or hit the alt key on the keyboard like I do to wake my mac from sleep, but it really needs a good ole mashing.
Posted in Life | Tags 7, bluetooth, keyboard, magic, mighty, mouse, os, vista, windows, x | no comments
Posted by Chuck Vose
Fri, 02 Apr 2010 22:04:00 GMT
During my last mini flash project I created a project designed to help me with async calls in AS3. I hope that it helps you too. You can find the project on my github account.
Intro
Required Sequence is a tiny AS3 library that mandates that certain bits of code run before other bits of code. I’ve heard that Senocular has an excellent version of this but I could never quite grok his library. There’s also the apparently magical BulkLoader which you can find here. Before I found those two libraries I had already written my own and it works quite well for me.
Background
Required Sequence is essentially an implementation of the Publish/Subscribe design pattern in AS3. It relies on the principle that when an important configuration process finishes it will dispatch an Event on the main class. Other processes that are interested in this merely tell their Required Sequence instance to listen for that Event and execute some code when it happens.
For example, if you need to load an XML config file before doing anything else you could easily write something like this:
rs.requireFlag(MyClass.CONFIG_LOADED,
function () {
// Do the rest of my program
}
);
Instructions
Build your RS listener as follows. This would be good to do for each class or each section of code but it must not die during execution until all bits of code are run.
Here is a complete running example of a program that requires the loadConfig function to be run before doing anything else.
package
{
import com.chuckvose.utils.RequiredSequence;
public class MyClass
{
public static const CONFIG_LOADED = 'configLoaded';
public var rs:RequiredSequence;
public function MyClass()
{
rs = new RequiredSequence();
// Ensure that we see the CONFIG_LOADED Event before doing anything else
rs.requireFlag(MyClass.CONFIG_LOADED,
function () {
// Do the rest of my program
}
);
}
public function loadConfig()
{
// Do some stuff
dispatchEvent(new Event(MyClass.CONFIG_LOADED));
}
}
}
Okay, that’s pretty cool, but does it do anything else? I’m glad you asked actually. The library does three other things right now that are really, really damned important; in fact, I would hazard that most people will only use these later functions but since they all descend from that somewhat simple use above it seemed like a good starting point.
Stubbornness
If you’ve ever dealt with URLLoaders you’ll know that sometimes they can be flakey. Wouldn’t it be cool if you could just write a bit of code to try a function n times once every m seconds until you get some signal?
rs.requireFlagWithRetry(MyClass.CONFIG_LOADED,
// Code that would be necessary to generate the interesting Event. You do
// not need to invoke this manually, it will run this code immediately.
function () {
loadConfig();
},
// Code to run after we see the interesting Event.
function () {
// Do the rest of my program
}
);
Or if you want to more tightly control how many times and the spacing between attempts you could do this:
var retries = 5; // Max number of tries
var period = 2000; // Milliseconds between tries
rs.requireFlagWithRetry(MyClass.CONFIG_LOADED,
// Code that would be necessary to generate the interesting Event. You do
// not need to invoke this manually, it will run this code immediately.
function () {
loadConfig();
},
// Code to run after we see the interesting Event.
function () {
// Do the rest of my program
},
retries,
period
);
Repetition
Naturally, being the subscriber/publisher pattern there will come a time when you want to listen repeatedly to something. For example, after I render something onto the canvas I usually want to refresh my scroll panes and hide any spinners that I’ve drawn, the following easily accommodates this desire.
rs.requireFlagRepeatedly(MyClass.PANE_LOADED, function () {
refreshCanvas();
hideSpinner();
});
Groups
Okay hot shit, what about if I just want to listen for a bunch of signals and I don’t really care about the order that they come in?
rs.requireFlags([MyClass.CONFIG_LOADED, MyClass.LOCATION_LOADED],
function () {
drawWeatherDisplay();
}
);
Manually
Okay, so maybe your desires don’t fall into one of the nice cases above, here’s what needs to happen in order for events to be registered. The heart is in the following 4 functions:
- isComplete(flagName): checks to see if a flag has completed. Run this before you start listening just in case the Event has already fired for a previous listener.
- addFlag(flagName): adds a flag to the list of flags to listen for. When we see an Event fire with this string in it we’ll check with all subscribers to see if that flag was interesting to them.
- completeFlag/uncompleteFlag(flagName): after you run your code you probably want to completeFlag so that RS knows to not bother you anymore and delete your listener. Similarly, a standard part of the require* functions is to run completeFlag so you may want to uncompleteFlag if you want to mark an Event as not having run yet.
- stopWatching/stopWatchingGroup: counterpart to addFlag these both tell RS to just stop listening for that flag or flags.
You can also look at the source, I hope that it’s easy enough to read.
Contact
If you have ideas for improvement you can always email me at vosechu+rs@gmail.com. Either that or just send me a pull request and I’ll probably rip it in lickety-split.
Thanks
Thank you to everyone that has ever sent me a message of encouragement. I really appreciate it; these are the fuel that Open Source developers thrive on.
Secondly, thank you to Metal Toad Media for letting me play with fun projects and paying me to develop outlandish little libraries like this.
Posted in Actionscript, Git | Tags as3, cs4, flash, github, requirements | no comments
Posted by Chuck Vose
Tue, 02 Mar 2010 22:50:00 GMT
Cross posted on the Metal Toad Blog
There’s a lot of good to be said about the Brightcove iPhone SDK, it’s easy, it seems to work really well, but there’s also a ton of gotchas and the docs are a little conflicting and/or out of date. The OnePlanet app is also out of date. This post is my attempt to rectify some of these things.
There are three things needed to get your app going:
You must be using your Read with URL Acccess token to fetch videos. Old accounts don’t have this so you’ll have to contact brightcove support to get them. Access this page from Home -> Account Settings -> API Management:

Next thing you need is to make sure that your UDS is enabled. You can find this page at Home -> Account Settings -> Publishing Settings:

Despite the documentation saying you need your videos to say Progressive Download it doesn’t actually matter. All you need to do is adjust your call to be like this from this excellent doc:
bc = [[BCMediaAPI alloc] initWithReadToken:@"your read with URL Access api"];
// This makes UDS happen. Without it there is no happiness in the world.
[bc setUdsSupportOn:YES];
videoList = [ [ NSMutableArray alloc ] init ];
NSError *err;
BCPlaylist *bcp = [ bc findPlaylistById:1234512345L error:&err ];
if (bcp != nil) {
for (int i = 0; i < [ bcp.videos count ]; i++) {
[ videoList addObject: [ bcp.videos objectAtIndex: i ] ];
}
}
Other notes:
- When using the OnePlanet app beware that the Headers/Libs have been set on the target as well as on the project so you need to amend their instructions to remove the Header Search Path and Library Search Path from the target.
- Also with the OnePlanet app the BCMoviePlayer.bundle needs to be reimported from your SDK or it’s not going to be happy.
- The README states that you can call the BCMediaAPI calls without the additional frameworks MediaPlayer, OpenGLES, and QuartzCore but you actually need all three or no project you build is ever going to compile.
- It’s already been stated in the docs but Geo restricted videos just don’t work yet. I’m not sure about the status of Localization yet.
- Use the error catching logic from the best practices page, it helps a lot and it’s actually pretty mandatory if you don’t want blank players and app crashes.
Posted in Programming, Brightcove, Objective-C, iPhone Development | Tags BCPlayer, brightcove, iPhone | no comments
Posted by Chuck Vose
Tue, 16 Feb 2010 22:53:00 GMT
Cross posted on the Metal Toad Blog
Imagination time: Imagine for a moment that you have an app, it has one button and one little window. When you click the button it changes the text within the window to something else. Now, when you get into flash development it seems like the easiest and clearest way to do this is to wipe out the contents in the window, but you would be wrong for thinking so. While it is the most obvious I intend to prove to you that to do so is both slower and prevents you from turning on the juice later with caching.
On to story time: We’re building an app for the OpenPeak tabletop device, it’s totally rad and you’ll love it I promise but that’s really not the point of the post. When we started the app we had what I considered a pretty awesome solution, we’d clear the state, build it onto a global, then write the global out to a window on the app. It actually worked great for a long time until we decided to start doing some caching where it became wildly apparent that I had actually written all three parts of that app dead wrong. It’s pretty exciting to do something wrong enough that you can write about it later. :)
Building on Globals (Horrible)
Okay, lets start with the most awful part of the lesson for me, that using globals is horrible and should never be done. Oh sure, they make certain listeners easier but it really does blow up fast when you start trying to cache things or thread. Here’s two scenarios that will inevitably bite you if you start using globals:
- When you start threading you’ll end up painting two scenes on to the global stage object at once.
- Even if you try to be synchronous you have to descend into an event listener hell since AS3 often decides to not dispatch Event.COMPLETE which means you’ll end up with a deadlocked app while a URLLoader tries in vane to do nothing.
- At some point you’ll accidentally use the same URLLoader twice or some other critical variable and the results will be completely random seeming as one gets overwritten on occasion.
So, how can you deal with this? As annoying as it is, define your variables at the beginning of your functions. I know it seems like a waste, but unlike that one global TextFormat object your URLLoaders really are totally different beasts and need to be treated as such. Same goes for almost all objects and display containers. I know it seems nice and elegant to use the same object all the time but what you may not be seeing is that all those globals need to have IPC methods defined on them or they’re completely useless in the inherently async world that is AS3.
Clearing the State (Wrong)
This one is simple really, I should have thought of it to begin with it but I wasn’t in OO space yet. Rather than thinking about pages or DisplayObjects as something physical that needs to be removed from the stage it’s much, much more efficient to just build a new Sprite() and replace the old stage that you were using. Best part is that when you just replace the display container you’re using you can easily stash this away in a cache object somewhere. Simple caching is only moments away but if you wipe the slate clean not only did you spend time killing all those children objects, you lost the ability to cache it away somewhere.
Metaphorical you of course, my apologies.
So what we did was to use an Object (we should have used a Dictionary but I didn’t know any better yet) with attributes that described the path we were writing to. We never wrote to a global stage object (we actually deleted those so we couldn’t). This way async calls could continue to write to the correct Sprite even in the background, the only place we needed to put a lock around was the drawing part as we drew out the content but rather than drawing a global DisplayObject we took the data from the cache and drew that which meant it was much, much faster, handled multiple threads just fine, and was extremely cacheable.
Conclusion
I hope this gives you some ideas; my hope was merely to get people thinking about two things: global objects require IPC, and that wiping the slate clean is wasteful. Let the garbage collector take care of clearing memory and make sure that you have only a few global objects.
Next time I’m going to talk about how I got a requirements engine running which would allow me to ensure that certain steps were always completed before anything else without creating messy spaghetti code. I think it’s pretty fantastic and I hope that you do too.
Posted in Programming, Actionscript | Tags 3, actionscript, cs4, evil, flash, globals, state | no comments
Posted by Chuck Vose
Fri, 12 Feb 2010 22:56:00 GMT
Cross posted on the Metal Toad Blog
Convincing Yourself
Convincing yourself of the value in 10% time is critical and is sometimes the most overlooked step in the process. Most people look at 10% time as nothing time; time you can’t bill for must surely be worth nothing financially right? And worse you might think, not only are you not billing but you’re robbing yourself of time that you could be actually developing so it feels like a double-whammy.
But can you think of a time when you’ve thought something like, “Man, this is repetitive but I don’t really have the time to script this.” Or maybe something like, “This code is just awful but I don’t really have any time to refactor it.” Or even better, “I should really release this to the community so that other people can help patch and debug for me but it’s not quite ready yet.”
Convincing people that 10% time is valuable can sometimes be a chore but I’m probably one of the luckiest guys in the country because my bosses actually want to do 10% time, but aren’t quite sure how to get to the point where we can afford it. But more than just being able to afford you it’s important to convince yourself, your coworkers, and your bosses that you can’t afford not to do something like 10% time.
Every one of those statements I find myself saying, but I never do anything about it and my perfectly good Open Source code languishes, my code goes unrefactored and I hate looking at it, and I often don’t script even some of the most business critical things because it just seems like it would take an insurmountable amount of time. But in my heart of hearts I know that this is completely insane. Releasing your Open Source code brings a notoriety that can’t even be approached by a fleet of skilled salesmen, refactoring your code so you can understand it or bear looking at it makes you a better programmer and makes you happier, and scripting business critical applications almost always saves time and certainly performs much more consistently in my experience.
So, I’m losing out on valuable press, writing hairy code, and doing things inconsistently. I think in most companies that should be considered grounds for expulsion but here we find ourselves doing it constantly. It’s not that we hate ourselves or our companies, but it is important to understand that to not improve yourself, to not invest in yourself, is to lose out on the most valuable resource that you have, yourself.
Now, if I’m feeling especially saucy I’ll continue this post later on. If not, I hope I’ve presented something half-cogent to chew on while drinking beers this evening with your friends and colleagues. Happy Friday!
no comments
Posted by Chuck Vose
Mon, 25 Jan 2010 22:58:00 GMT
Cross posted on the Metal Toad Blog
The toad just finished a small project involving the Facebook API and by far the most confusing aspect of the project was the terminology regarding the many, many different API’s and what each one actually does. I thought this merited a write-up and I hope you find it helpful.
FBML, Frames and the Canvas
“I’m interested in making a Facebook app that will live on Facebook.com but store data on my webserver.”
A long time ago Facebook was limited to creating apps only in their website which they called the frame. The components you were allowed to use on your section of the app (called your canvas) were instantiated by using FBML tags. In this style you would create an app on Facebook’s website and point your canvas url at your webserver. Your webserver would be interpreted through the rosie glasses of Facebook’s website; FB would make a call to your webserver and deliver the results to the end-user after making subtle alterations to your code.
XFBML and Facebook Connect
“I’m interested in making my website more interactive and allowing users to log in via their Facebook login.”
Not surprisingly making apps is not enough for many people and they want to extend their own websites instead of making Facebook better. To get Facebook integration into your site you’re going to be looking at XFBML, FBJS and FQL, together they can be called Facebook Connect though I don’t know if it’s officially defined as such.
Unlike FBML there is no frame and you’re relying on magic to get your XFBML parsed into a usable format. Rather than sitting in between your end-user and your webserver, this time your webserver uses the Facebook loader JS to construct iFrames which call out to Facebook.com, subtly change your XFBML tags into real HTML, and display the results.
What’s important to know though, is that the three different ways of interacting with Facebook (XFBML, FBJS, and the PHP/Language specific libraries) essentially do the same exact things so you can do whichever you feel most comfortable with or whichever gives you the most bang for your particular project. If you’re doing AJAX there’s a good chance you’ll end up with XFBML tags due to the limited interaction you’ll have with PHP/Whatever on the backend, but that’s totally up to you.
XFBML is not everything though and you’ll find yourself wanting to use fairly often to get at some of the juicier bits from FBML. Be not afraid, it is a kind layer once you get it developed. Best part is that serverfbml elements do know about each other so if you render a login and a hidden friend finder at the same time once people log in you can show the friend finder and it will have the friends of the now logged in user. Magic.
Glossary
FBML – Facebook.com specific tags for building Facebook apps.
XFBML – Facebook Connect markup language for adding Facebook functionality into your website.
FBJS – Facebook’s JS library that works on both Facebook.com apps and for Facebook Connect apps.
FQL – Facebook’s weird little query language for getting data quickly with no interface.
Facebook Connect – Namespace to describe stuff that you may want to do with your server.
Canvas – The main space on Facebook.com where you can find objects like your Wall.
Frame – The stuff around the frame like your notifications and the myriad ads.
Posted in Facebook | Tags api, facebook | no comments