Lessons Learned while Planning an Unconference

Mobicamp was an extremely gratifying experience. I had a great time at the event but also learned a lot about planning such things. This is an abridged how to, a list of pitfalls, and a list of things I would likely change for Mobicamp 2010. Look for another post in the near future regarding some of sessions given at Mobicamp.

There are, of course, plenty of things to consider when planning an unconference:

  • Attendee limit
  • Venue
  • Food/Snacks/Drinks
  • Design/Web presence/T-Shirts
  • Charging Attendees
  • Sponsorship
  • Theme and Audience
  • and more that I’m likely forgetting

Attendee Limit:

Event size impacts everything on the list above. Figure this out up front and realize that the time to plan the event and the cost both go up as you increase the number of attendees. I suggest keeping the event reasonably small if you want folks to interact with a lot of others. In my opinion, the sweet spot is in the 70-100 person range.

Venue:

Finding a venue was reasonably easy for me thanks to the wonderful resources in Atlanta. I spoke to @lance at the ATDC and asked if the ATDC could offer space for the event. They were able to assist and the cost was very reasonable. If that had fallen through, @billcutts at GTRI was more than willing to assist. Many thanks to both. It’s not always the case that resources like this are easily available. Often venues are the most expensive part of events like Mobicamp. Shop around for quotes (you can try hotels, universities, tap into your network, etc.). If you’re going for a BarCamp, you probably need several small rooms.

Food/Snacks/Drinks:

Once you’ve figured out the number of spots you will make available at your event, shop around for prices on feeding that many people. Talk to managers at restaurants about their catering options. In my case, food and drink was a around $8.33 per person. I accounted for approximately 120 people with a guess that 70% would actually show up.

Design/Web presence/T-Shirts:

Find a good designer and ask for a logo and T-shirt design. If you’re not savvy enough to put up a webpage yourself, tap into your network. A wiki or blog works fine. You also need a way for attendees to sign up. I didn’t ask for T-shirt sizes, which made guessing a bit difficult. I’m asking for T-shirt sizes next year. I used Kingscreen.com, which worked out very well (they were able to print a two color gradient, etc. without issues). Shirts seem to range from about $6 to about $10 each. Again, shop around and find a good deal.

Charging Attendees:

Mobicamp was free. My rationale was more people would attend if there was not a cost barrier to entry. I believe I was wrong. If there is a modest fee, say on the order of $20, attendees have a vested interest and want to get their money’s worth. This makes them much more likely to attend. Since unconferences depend on attendees for content, it’s more important to make sure people actually make it to the event than other conferences. This is something else I will change if I host Mobicamp 2010.

Sponsorship:

If you’ve gotten this far, you have a good idea of how much your event will cost. Get in touch with evangelists from companies to see if they can help out. I was fortunate to have several wonderful sponsors for Mobicamp. In fact, none were pushy and interestingly the largest companies were the most easy going about things. I recommend creating a single “sponsorship package” — a list of stuff companies get in return for sponsoring your event. Make it worth your sponsors’ while and treat them equally. I recommend going with a slightly higher sponsorship amount and a handful of sponsors instead of many many small sponsors. It’s also a good idea to keep sponsors relevant to the event, although this generally a nonissue (usually only sponsors with some vested interest will offer).

Theme and Audience:

Having a theme helps keep your event’s topics focused. If the theme is too broad, users may walk away feeling O_o; if the theme is too specific, then you may not have enough users signed up to provide an event’s worth of content. Mobicamp was originally intended to be an event for mobile developers and students. This was broadened a bit, on advice from a friend, to include more business-y topics like marketing, etc. This absolutely added to the event because many relevant sessions about things like experiences with certain App Stores, new technology and its real world impact on users, what platforms to target, etc. that may not have come up otherwise. I highly recommend asking attendees for their mandatory session topic on signup. A major value proposition of unconferences is the sharing of information by all attendees. This is cut short if half or more of the attendees decide to stay in their “comfort zone” and listen instead. Make people step out of their comfort zone and watch amazing dialog begin to emerge.

Mobicamp 2010:

Although Mobicamp went very well, there are a number of changes I’d like to make next year. As you might have guessed, there will be a hard limit on the number of spots and I’m going to charge a modest entry fee. I will also make contributing by giving a session mandatory, ask people to send their topics early on and pick time slots based on the expected length of their talk (at the event). Topic focus was not an issue At Mobicamp, save one or two sessions.

Thanks to all of my friends who volunteered their time to contribute to and run Mobicamp.

Elven Architecture

Overview:
I’ve learned a tremendous amount about game development and architecture in the past 7 months at Elf Island (http://elfisland.com). I thought I’d share a bit about how our backend stuff works and our current scaling capacity, which we are refining. I’ll not delve into some of the “secrets” of Elf Island to keep this post at a reasonable length. I’ll visit the client at a later date.

We make heavy use of Amazon Web Services. All Elf Island servers run on Amazon EC2+Elastic IP. Since we’re cloudified and have a process in place, we can scale to handle tremendous load quickly. Here’s a bit of detail.

Elf Island requires the following servers to run:

  • app server (n)
  • smartfox socket server (n)
  • db server (1+n)
  • web server for assets like swfs, images etc. (n)
  • load balancer

where (n) means there are n running servers and (1+n) means there’s a primary server with some sort of redundant backup. This means we need a minimum of 5 servers to run the game.

The crappy diagram below (sorry, an artist I am not) is an approximation of how things are setup:

App servers are used for data which does not need to be “live,” such as inventory, buddies, in game mail, game data, analytics services, and much more. All services are locked down via auth/roles and AOP. Some services are locked per IP and other safeguards. In game mail, incidentally, is delivered to proper recipients (unlike Twitter DMs O_o I kid, I kid <3 Twitter).

Smartfox is a socket server we use to maintain user presence, chat, and live state. It is useful because it allows developers to extend it via “extensions.” We have thrown out the bulk of the built in functionality and built our “live” presence from the ground up as our game requires much more in terms of moderation and safety than a typical MMO. Chat, location and presence, room join logic, etc. are all custom.

We use redundant MySQL dbs in a master-slave setup. Not much to say here aside from all realms share the same db so users can travel from server to server and retain everything about their character.

Apache servers host our assets. We’re looking into CDNs like Cloudfront but we push assets frequently so there are caching issues to work through and more pressing things to deal with right now. We’ll be visiting this in the near future.

We have a load balancer in front of our web servers and our app servers.

We also have at least one machine dedicated to monitoring, which sends alerts if bad things happen. Amazon SimpleDB (bulk put) is used to log high volume data like chat.

Our uptime has been amazing. In the past six months, we’ve only been down twice for about 15 minutes (aside from closing nightly) because a script failed after a faulty deployment. That was not related to application stability. Our users like that.

A realm is a single Elf Island “server,” from a user’s perspective. A realm is really made up of several machines. A realm is a dedicated smartfox server plus any number of shared app servers. Specifically, we can scale smartfox servers independent of app servers since there is not a 1-to-1 mapping of smartfox server to app server. Currently, users on one realm cannot communicate with one another but we’ve talked about it as well as sharding realms over multiple smartfox servers based on load. All in the future. For now, realms are independent except for state.

Login flow:
When a client logs in, the load balancer directs them to an app server. The app server authenticates the user and presents a dynamic list of realms. We can literally spin up and bring down realms on the fly. Users then choose one of the available realms, at which point they are authenticated with smartfox and brought into the Marketplace (a room) on the chosen realm.

At this point, information regarding users in the room is pushed to the client and style information for elves is loaded from smartfox and the app server. We load as little data as possible at any given time to minimize load. Once the style data is received, the client loads the appropriate assets from any of a number of web servers. Our clothing system is complex but provides great versatility. Users can style the way their elf looks beyond most other 2D MMOs. Since Elf Island is a kids game, we can’t have nekkid elves. As such, while the various assets are loaded, we obscure each elf’s on screen representation. Although the assets themselves are vector graphics, we render, composite and cache them as bitmaps client side for maximum performance. This does increase the game’s memory footprint but it’s not too bad. At this point, users can interact with each other as well as Elf Island.

Chat:
Elf Island users may only use words in an inclusive dictionary. Users are clever, though, so we use heuristics to catch things that are not allowed, such as the sharing of telephone numbers, etc. Although we filter chat on the client, even stricter safeguards are in place on the server. If a user were to somehow circumvent client-side filtering, the server would not only drop their message, but alert the moderation team.

Moderation Tools:
Moderators have several tools at their disposal. I won’t go into detail, but lets just say they can view game events in real time so children on Elf Island are safe. Curious? ;)

Programming: Clever is good. Too Clever is Bad.

Sometime this week I was tasked with implementing some super-secret whiz-bang moderation tool for the Elf Island mod team. Since we’re big fans of code reuse (we have one hell of a dev team..you should have seen the code base when we inherited it 7 months ago…), I decided to piggy back off some functionality we added a few weeks earlier that supplied room list information to the client based on some filter parameters. The old code looked something like this:


for each (room in currentRooms) {
...
//Filter based on params
if (privateParam != room.isPrivate || room.isLimbo) continue;
...
}

This was clever because it let us filter one of two disjoint subsets in a single line given 3 parameters. Then came the natural extension (..oof..) of adding another param to get both sets for this whiz-bang feature.


for each (room in currentRooms) {
...
if (!allParam && (privateParam != room.isPrivate || room.isLimbo))
continue;
...
}

At first glance, this looked sensible. Unfortunately, it was brittle and fell apart when some “other” brittle code (that we did not control) did what average java developers do best (assume stupid things, eat exceptions, then throw nonsensical messages into logs). The issue was two things: the obvious order of operations issue and the larger problem of lack of intent expression. Sure it was fun to look at but it’s not easy to maintain. Had I refactored this into a separate method with a clearly defined flow, I wouldn’t have spent hours chasing my tail due to the aforementioned foolish error in the logs. The issue only cropped up under load (when the chance was ~100% a user was in a “limbo” room). The lesson to take from this post is to urge people to write readable code, even if it’s a tiny bit more verbose, instead of attempting to cram things like a 4 parameter filter with weird edge cases into a single line. Code should express intent and it should make sense at first glance, not try to get the job done in the least number of lines possible.

Overlay UIView on MPMoviePlayerController

So you wanna overlay a UIView on MPMoviePlayerController?

Tried


[self.view addSubView:myView];

to no avail, right? The reason that fails is that MPMoviePlayerController actually creates a new window and overlays that on your app. This means you can’t just add a subview — it’ll just be hidden.

Try this oversimplified example:


MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:myURL]];

[[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(playerFinishedPlaying:)
name:MPMoviePlayerPlaybackDidFinishNotification object:player];

[player play];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = @"Hi, I'm on your MPMoviePlayerController";
label.transform = CGAffineTransformMakeRotation(M_PI/2.0);
label.frame = CGRectMake(0,0,20,480);

[[[UIApplication sharedApplication] keyWindow] addSubview:label];

Wait, WTF? Clever folks might have tried [player _window], which works great on the simulator but fails to build for the device. The trick here is that the sharedApplication’s keyWindow IS the player’s window once the player is on screen, so adding a subview to that window overlays said view on the player. I did run into a bug where the keyWindow property was nil after the player was shown, so if you want to use that again later, make sure to call:


[self.view.window makeKeyAndVisible];

when the player calls back on your controller handling MPMoviePlayerPlaybackDidFinishNotification (in this case, playerFinishedPlaying:).

UPDATE: For iPhone 3.0, I can only get this to work with a bit of a hack — use a timer to show the overlay later. >.< Not sure I like this approach or think it’s reliable but it seems to work. Test it and YMMV for sure.


...

[player play];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(showOverlay:) userInfo:nil repeats:NO];
}

- (void)showOverlay:(NSTimer *)timer {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = @"Hi, I'm on your MPMoviePlayerController";
label.transform = CGAffineTransformMakeRotation(M_PI/2.0);
[label setBackgroundColor:[UIColor redColor]];
label.frame = CGRectMake(0,0,20,480);

NSArray *windows = [[UIApplication sharedApplication] windows];
UIWindow *mpw = [windows objectAtIndex:1];
[mpw addSubview:label];
}

mobicamp is coming to atlanta

mobicamp is coming. It’s my first event — go sign up! It’s going to be a blast.