Inheriting From Built-In Ruby Types
The string is a stark data structure and everywhere it is passed there is much duplication of process. It is a perfect vehicle for hiding information.
– Alan Perlis
I was teaching a class on refactoring and wanted a real-world example to demonstrate finding a class to extract. My students were Rails developers, so I immediately knew I wanted to show an example of an ActiveRecord model.
After skinny controllers and fat models became a Rails best practice ActiveRecord models have tended to grow without bounds. It’s easy to push code down into them, but developers seem to have some kind of mental block causing them to think they can’t create classes that aren’t more ActiveRecord models.
Though I’ve seen this often enough I couldn’t use any client code for my example. I scratched my head a moment and thought of Discourse, a new forum project. I went directly to the User model because it’s so commonly a god object. (Just to be clear, I’m not trying to pick on Discourse. This is a fairly minor improvement to address a very common problem.)
I scrolled down past the usual mass of associations, validations, and hooks to the method definitions. Here’s the first eight:
def self.username_length def self.suggest_username(name) def self.create_for_email(email, options=()) def self.username_available?(username) def self.username_valid?(username) def enqueue_welcome_message(message_type) def self.suggest_name(email) def change_username(new_username)
From this quick glance there’s a Username class waiting to be extracted. It’s in the name of several methods, it’s the sole argument to many methods, and most of the methods are class methods, implying they don’t maintain any state (class-level variables being rare in Ruby).
It’s discouraging to think about extracting a Username. It’s stored as a varchar in the database and ActiveRecord will choke on validations if it can’t treat it as a string.
The solution is straightforward: Username should inherit from String. Username is-a String, and keeping it in the built-in type is why this code sprawls.
I extracted the below class, changing as little as possible, mostly just removing ‘username’ from the start of method names and using self where appropriate. I left behind the unrelated create_for_email, enqueue_welcome_message, suggest_name, and the temptingchange_username, which was about editing aUser.
class Username < String
def username_length
3..15
end
def suggest
name = self.dup
if name =~ /([^@]+)@([^\.]+)/
name = Regexp.last_match[1]
# Special case, if it's me @ something, take the something.
name = Regexp.last_match[2] if name == 'me'
end
name.gsub!(/^[^A-Za-z0-9]+/, "")
name.gsub!(/[^A-Za-z0-9_]+$/, "")
name.gsub!(/[^A-Za-z0-9_]+/, "_")
# Pad the length with 1s
missing_chars = username_length.begin - name.length
name << ('1' * missing_chars) if missing_chars > 0
# Trim extra length
name = name[0..username_length.end-1]
i = 1
attempt = name
while !attempt.available?
suffix = i.to_s
max_length = username_length.end - 1 - suffix.length
attempt = "#{name[0..max_length]}#{suffix}"
i+=1
end
attempt
end
def available?
!User.where(username_lower: lower).exists?
end
# export a business name for this operation
alias :lower :downcase
end
And it’s used as:
u = Username.new 'eric_blair' u.available? new = u.suggest User.new username: Username.new('Samuel Clemens').suggest
The User class got a lot simpler now that it doesn’t know all the business rules about usernames. I left the validation in User because it’s the thing being persisted to the database, though if it wasn’t for the Active Record pattern I’d want to move that over as well.
Now Username is a simple immutable value object that’s easier to reason about and test. It adheres nicely to the SOLID principles, and it’s an uncommon nice example of inheritance working well in Ruby.
One caveat is that User objects Rails instantiantes will return Strings on calls to User#username. We’ll need to write a getter to instantiate and return a Username object, though Rails before 3.2 included composed_of for this:
class User < ActiveRecord::Base def username Username.new(read_attribute(:username)) end # or, pre Rails 3.2: composed_of :username, converter: :new end
(And to the curious: no, I haven’t contributed a patch back to Discourse. They have a Contributor License Agreement to backdoor their ostensible open source licensing.)
Social Media for Programmers
A friend of mine has been accepted to DevBootcamp and I’m pleased to see the coursework is beginning even before classes. He’s not so pleased — really, he’s puzzled by the emphasis on social media:
So far the hardest part of this entire Bootcamp experience is looking to be the social aspect of it.
The endless chatter on facebook that I have to pay attention to in case someone leaves a comment of actual importance. I had to create a twitter account for the application and now that is being reinforced with Socrates but I’d be surprised if I’ve checked the twitter account more than one in the last 3 months. They also want me to use Tumblr, LinkedIn, and Quora. I feel like I’ll have to spend 2 hours a day looking through the social media instead of actually working. [...]
Is this just a necessity of the field? Do you actually use all of these?
Wow, that’s tossing a lot of social media at you. I guess they want to be really sure that you guys talk and form a community. :) I think you’re experiencing a clash between the stereotype of a programmer as an extreme introvert who hides away in a dark office and the reality of programmers as a friendly, collaborative, argumentative community..
Yes, I use a lot of these tools, probably an hour or so a day of reading and chatting. It is not surprising that you might spend two hours if you have to look everything up along the way. :) You’ll hear about new techniques and tools, get help finding bugs, learn how other people have approached problems, see industry trends, and more. It is an investment in your future.
Actually, a lot of programming is keeping up with trends. I suspect web development moves faster than most programming sub-topics because we’re all online and we can build our own communication tools.
If you go work in a cave and stop paying attention to the outside world you’ve got about four years before you’re not familiar with current tools and will have trouble finding a job. The foundational skills of programming all stay the same (and those *will* be improved by reading the articles you find on social media), but tools turn over fairly rapidly. I didn’t think I’d bring it up until you were a couple years into your career, but the book The Passionate Programmer has excellent advice on how to build and maintain a good career.
You need to pick one consistent username for all these sites. Not only is it easier for you to keep track of, it helps people learn about you and hire you. Mine used to be ‘harkins’ or ‘malaprop’ but neither was unique, so I’ve moved to ‘pushcx’ to echo my blog. Opaque handles like this are really uncommon, most people use a variation of or wordplay on their name.
So let me go through the sites you mention and I use one-by-one:
Tumblr: I only browse this; there’s not much programming content. But if I ever want a cute animated gif or porny art, sure, I suppose. This is the only one in their list that seems odd to me.
Quora: A Q+A site that’s popular for biz/marketing topics. They were a social media darling a year or two back and are a decent place for finding info, but not a lot of code talk. I expect them to flame out before 2015.
LinkedIn: Facebook for business. A great way to find jobs and help friends find jobs, a must-have. I am probably shortchanging my prospects, even though I’m happy with my job and network, by not being on the site.
Gravatar: An avatar that can appear on every site you use the same email address on, generally only supported by small sites. Includes a broken movie-style censorship system. Incredibly annoying if you have more than one email address.
Twitter: Very popular among programmers. You should follow me, @pushcx there. Lots of links and community-building stuff happens here, this one I use actively. Though it’s really hard to separate signal from noise; some of the best programmers post also most the most random annoying bullshit.
App.net: Exists because Twitter is increasingly terrible assholes to people who build Twitter clients and services. If Twitter goes full-evil everyone will move here, but it’s safe to ignore it completely until then.
StackOverflow: Programming Q+A, an absolute must. You will find their pages showing up in search results for all sorts of programming topics, and you can ask questions here. This is an amazing resource.
Hacker News: Code + startup news. The comments used to be a goldmine, but in the last year or two they’ve sunk into general bickering. Worth keeping an eye on (nicer interface: Hckrnews) for industry events and the occasional tech post.
Lobsters: Tech-only Hacker News; sadly only has a tiny fraction of the traffic. Recently interviewed me.
Reddit: Don’t visit yet, it’s an incredible time-sink of humor and brain candy. There are a couple small subforums (“subreddits”) worth following, but that’ll keep until you’re done with DevBootcamp.
GitHub: Required. A really nice set of tools on top of git, a tool you haven’t seen yet for tracking work as you go and collaborating. Nearly all web developers are on the site. After a personal blog, this is where you can best build a reputation for yourself.
Because I am a voracious reader (and because I procrastinate by finding interesting things to read), if I read a good blog post I tend to subscribe for a while to read more posts, and I always have a technical book or two around. So in addition to interacting on the above social sites, I’ll spend at least an hour or two a day reading more about programming. I’m pretty sure it’s uncommon to read this much, but I really enjoy programming and care about learning everything I can.
Backpack Criteria
I spent all of 2011 traveling through interesting cities in the U.S. and Canada with a small backpack. I put a lot of thought into what I needed, so I wanted to share that in case anyone else finds it useful.
- Simple dark color scheme, no logos to attract attention. When you are carrying everything you own, you do not want thieves to notice you.
- Right size: 28L is mine, I could see a few L up or down
- Waterproof material (preferred) or builtin waterproof cover. Waterproof means I could wear in a nor’easter and everything inside will be bone dry, not “water-resistant”, which means “made of tissue paper”.
- Chest strap that connects the shoulder straps to better carry weight.
- External frame, maybe mesh back, to lift the pack off my sweaty back
- One main compartment, one quick-access compartment on the front. Maybe a mesh side pocket for a water bottle, maybe an internal pocket for small goods (use mesh so I can see inside), but a big flexible space and packing crates are the vest way I’ve found to organize. It’s painful to have to search for things and carry extra locks.
- Front-loading is superior to top-loading. That is, rather than a zip along the top of the backpack, it should be possible to unzip the entire front face.
- cloth/rubber/plastic tabs on the zipper pulls so that I do not jingle like Santa’s reindeer
- Some kind of compression straps. Compression/adjustment straps should not dangle like dreadlocks.
- Laptop pocket in the main compartment is a nice-to-have; my bag has a Camelbak space that works.
- Pockets with a single zipper should have some kind of small loop on the side the zipper closes on so that every zipper can be locked (I didn’t get this and regret it).
- Solid materials and workmanship, don’t want to have to replace on the road. Cost should be $100 – $200 USD; any less and you skimped.
- Equipment straps so I can tie/rubberband down gear when I’m traveling heavy or drying laundry (I have no shame).
- No zip-off day bag – if a pack includes a day bag, it’s too big to carry every day.
- Rides comfortably – I am taller and skinnier than average, this was a hard find.
- Fits in the (roughly) 14 in x 9 in x 22 box standing at the airport gate so I can prove it’s a carry-on and avoid checking luggage.
- Seriously, no goddamn logos. It’s a backpack, not a billboard.
Why I Rarely Use HABTM
I was chatting with Kori Roys about database design and I mentioned offhandedly that I almost never use has_and_belongs_to_many in Rails. Kori’s ears perked up and he asked why that is.
I’ve been pondering, and it’s related to my old Rules Of Database App Aging post, which has aged well (unfortunately). One more thing I’ve recognized is that those join tables between what I think of as two records very quickly pick up their own life.
To use the examples from that post, the guy who lives in one state and works in another needs to track what dates he started that relationship in each for taxes. The email going to multiple feeds needs different formatting applied for each. A state’s caucus may refer back to the results of the previous caucus to determine ballot order or election fund matching. Things with multiple categories may care about the order their categories are displayed in.
In all these cases and more, it’s plausible for that relationship to become a domain object in its own right (most often with timestamps and active/inactive flags, in my experience). It happens often enough that I find myself almost never using the implicit relationships provided by has_and_belongs_to_many in favor of new, explicitly-named objects with two belongs_to/has_many relationships. These can take on data and responsibilities in a natural way as needed and make the app easier to talk about.
Solving vs. Fixing vs. Introspecting
I liked this blog post Solving vs. Fixing (via). In my first job out of college I did support and maintenance on a medium-sized (250kloc) system that had spent a year looked after by a developer who only fixed things, never solved them. The code had started poor and gotten gotten steadily worse, but I always tried to fix bugs twice and slowly ground out improvements in the system.
So this blog post caught my eye, though I think this it misses two vitally important steps.
After you have fixed the bug and committed your code, stop and think, “How could I have found this bug faster?” Are there tools that you could’ve used to locate it quicker? Hypotheses you discarded too quickly? Some pattern in the code you overlooked? Why did it take you the time it did to find this bug, and what have you learned about how to do it better?
And then second, “Where did this bug come from?” Was it a typo? When you were originally writing the code, what test could you have written to catch it? If you misunderstood a requirement, what question could you have asked that would’ve exposed the mismatch? How could the system be redesigned to make this kind of bug impossible? What have you learned about how to code better?
Software development is design, it’s all mental processes, not a production process. The hard problems are all in the thinking, not in the typing. So you have to introspect and improve your thinking to get better at it. I don’t feel like an amazing developer, but when I recognize a design issue or a bug as something I’ve seen before I can jump ahead of colleagues to an answer. There’s no magic developer talent at work, it’s just deliberate, conscious practice, and these two questions are most of how I do that.
(If you’re wondering, the blog has been quiet lately because I’ve been putting all my free time into an art project. I’m now waiting on production and have spare brainpower again. I plan to post about it in six weeks or so.)
FTL: Simulationism Lost
All weekend I’ve been captaining a series of (mostly doomed) Trek-like starships in FTL, a new indie game. The gameplay is mostly derived from time management and roguelike games (more on that later), as you juggle crew between tasks, shift power between systems (straight up “more power to the engines and target their shields!”), and balance exploring the galaxy with fleeing from an ever-advancing plot device that’s too boring to describe.
It feels intimidating to start, but despite a half-hearted tutorial it’s pretty easy to pick up if you’ve ever seen a battle on Star Trek. Most of the time you’re figuring out new strategies for dealing with emergencies like fires, boarders, robot boarders, and damaged systems and then juggling your well-limited resources to “make it so”.
As you progress you can upgrade and reconfigure your ship with found and bought parts. With 9 ships (each with a variant layout, though all but the first ship must be unlocked through hidden in-game quests) and a heavy-handed random number generator, most games are about quickly strategizing in dire circumstances, which is where the game shines.
Simulationism
The buzz is that FTL is a roguelike, though I’ve only seen one good review explore what that means. The one thing missing from this writeup is “simulationism”. As you fight through the unending hordes of enemies in a roguelike, those hordes are part of the same simulation you are: they use the same hit point system, the same weapons, the same options available to you, and suffer the same pains you do. If your character can get frozen and have an arm broken off and soldier on partially dismembered, so can your enemies (the ones that have arms, anyways).
Roguelikes allow deep strategies by simulating complex systems (there are, of course, other ways to get deep games). Dying (and oh, can you have some fun getting the ship blown out from under you) is teaching you new ways to destroy the enemy starships that you can see run on the same rules you are. You could build up shields and let environmental hazards destroy your enemies; or send over a boarding crew; try to burn out their crew or space them; use automated drones to harrass; bring overwhelming firepower to their defenses — and these are just some of the core strategies.
It feels like there’s a ton to do and try, and there is, but your choices are badly constrained by a flaw I’ll discuss under the spoiler heading below.
Complaints
Cruising the galaxy isn’t all the fun it could be. In each game you’ll pass through 8 sectors of ~25 stars (though you only have time to explore around half of those). A narrow majority of systems have an enemy to fight, the rest of the time you’ll have Trek-like events where you have to negotiate with aliens, investigate an anomaly, or react to some peril. After two or three games, you’ll have exhausted most of the events the game has to offer, which is boring because they’re all simple dialogue/action choices that only occasionally care what kind of crew or equipment you have.
Not only do they get boring, they’re very random with harsh consequences. You find a derelict freighter, do you want to investigate? Maybe you get a little bit of scrap, or maybe you get a game-changing weapon, or maybe one of your 3-8 crewmembers dies outright. There’s no way to assess or influence the odds, and (painfully for such a Trek-inspired game) you can’t even send a redshirt to do the deed. In one event a mine attaches to your hull, flip a coin to learn if you lose a vital, painstakingly leveled-up crewmember.
There’s also heavy randomness in what’s available to you. Because the plot device keeps you from exploring too much, you may see few of the ~16 stores per game and never see one you can buy vital upgrades from. FTL’s randomness is great for generating new circumstances of encounters and new strategies, but the wide variance can make games impossible to win, however well you may be playing. (As a quick example: instead of selecting store type completely at random, fill a deck of cards with a distribution of store types and draw from it as the player arrives. Random generation with reduced variance.) Nethack has a lot of randomness and I almost always die thinking “Oh, I should have…” Even after I’ve learned most everything about FTL I’m sometimes left feeling “Yeah, I couldn’t have done any different, it was out of my hands”.
Aside from these major problems there are a few nits to pick in the UI: it’s hard to see crew health (especially enemies), you can’t rename crew in the middle of the game or carry names between games, you can’t direct crew to open or close doors if your control is down, and if your sensors are down (due to damage or being in a nebula) the only indication that an unoccupied compartment is on fire or leaking air is easily missed. The big UI frustrations are that there are few keyboard shortcuts and after almost every combat you’ll have to do 20 seconds to three minutes of routine, totally safe clicking to repair and reorganize back to peak form.
Summary
On the whole, the game feels unpolished and flawed. It has some great moments and emergent gameplay undermined by too much variance, UI, and big bad design decision (to be discussed below).
If you’ve been waiting to command your own Trek-style starship, really like lasers that go pewpew, or sorely miss the subsim genre, you should absolutely buy FTL.
If you’re at all on the fence, though, I’d say wait. It has some rough edges and the endgame is a mistake. There will be a great game coming in a few months, or maybe in a year or two. I don’t know if it’ll be a DLC, a sequel, a fan mod, or a clone that gets it right, but someone will polish this rough gem into a classic.
Simulation Lost (Here Be Spoilers)
In talking about variance I touched on fairness. Roguelikes, as brutally difficult and unforgiving as they may be, feel fundamentally fair because of simulationism. The same hazards that are your bane as you learn can be turned into weapons against your enemies. This breaks down in FTL and leaves the game feeling seriously unfair.
A minor example of this (“minor” because the player is less likely to notice a flaw that works in their favor, not because I’m going to be terse) ship engines are upgraded and powered both to improve how likely a ship is to dodge incoming fire and how quickly they offer the option to flee combat. When you are in battle, your FTL is continuously charging; when full you can click to jump away instantly. Charging takes about 30-60s (which is often too late to avoid crippling damage).
Enemy ships will only occasionally try this (even though in-plot every enemy without overpowering superiority should flee at the first opportunity) and you’ll get a pop-up to warn you. Which is odd, because if their FTL works like yours, it should already be powered up when you’ve jumped into their system – or at worst it should be powering up all through combat just like yours. Because it would be frustrating to have enemies constantly jumping away with no warning, the devs added an explicit notification that the enemy crew is selecting that strategy. Fixing this inside the game system would mean a lot of rebalancing: maybe engines aren’t used for evasion and so are not powered up except to charge for FTL, or maybe there’s an entirely different system of FTL that’s less Battlestar and more Trek. This one doesn’t have an easy answer, but the game has rough spots because issues like this got a band-aid instead of a redesign.
The real problem, and the big spoiler, is that the last sector isn’t about exploring but hunting and fighting a boss ship that is far more powerful than any previous ship. It has huge shields, tons of weapons, strong crew defense, and you’ll have to defeat it three times.
Because of its unprecedentedly powerful equipment, the boss battle is gear check (thanks to @davidRovani for the term). You lose if you don’t have one of the couple weapons powerful enough to break down its super-shield. And because it has more weapons than anything before, you lose if you don’t either have the single piece of equipment that can fix hull damage (hull repair drone) or you get really lucky with the three disappearing, probably-not-close-enough repair ships or you lose. It’s that stark.
You can play your best but go an entire run without once seeing the items required for the boss. You had lots of fun strategies available for attacking previous ships, like using boarding parties and special weapons to target the enemy crew. In the boss battle, the devs decided that those strategies were simply wrong, and even if you succeed over the record-large crew and its unprecedented defenses, the game tells you “no” and, like being told the enemy wants to escape, you’re told an AI takes over for the crew. If you didn’t build your ship around a handful of strategies, you can’t win.
It’s deeply unsatisfying for every game to end with a simulation-breaking fight with an opponent that is roughly twice as strong in every single aspect than the best of any enemy you’ve seen before. I’ve seen a lot of complaints from people about the random number generator, and I think this is what’s at the core of that. Either you get lucky enough to get the equipment for the viable boss strategies or you lose. All the deep gameplay earlier is swept away.
The worst part is it’s probably easier to fix than the engines. Instead of one boss that overpowered in every way, create a dozen ships that overpowered at one or two of the strategies, then require the player to face down three or four in succession. Then the endgame isn’t a lottery the player has happened to win, it’s a test of whether the player has built and commanded an all-around capable starship, with a bit of luck that you don’t get a bad matchup.
So this is why I think FTL is a fun but flawed game. I’ve enjoyed playing it and I’ll play some more, but it’s not the game that people will remember for delivering on the promise of this setup.
Added Sep 28: found another good response that makes an important point about positive feedback loops in FTL’s power curve.
Open and Closed Platforms
I keep having to explain why I don’t own a smartphone. There’s one big reason, but let me quickly run some other things that matter before I get to it.
I don’t like the idea of having a distraction in my pocket at all times. I know I’m prone to procrastination, so I’d rather not have a spinning roulette wheel distracting me with potential fun new things. I also don’t like the idea of having a tracking device in my pocket at all times, especially not when they’re being actively abused.
But the biggest reason is that I don’t want to spend a lot of money to not own something. The smartphones are locked down, with limited controls and a gatekeeper approving any program you want to run. There’s little visibility into what the built-in apps do on the network or any ability to change them. (Heck, you can’t even set a screensaver on the Amazon Kindle.)
The common objection I hear is that it’s possible to jailbreak these devices to solve some of these problem, but why would I want to buy a jail in the first place? And then deal with poor support, broken upgrades, or other hassles because I have unauthorized access to something I paid money to not own?
It just frustrates me, on a lot of levels. I concede that building a walled garden can be a great business decision, but I don’t like feeling controlled, and I don’t like having a toy to play with in predetermined ways instead of a tool to create anything I want.
Now I’ve explained it several times in the last few weeks, I changed my mind about a different platform. The Ouya is a gaming console designed to be open and hackable. I hate the name and decided to pass because it has huge problems ahead of it marketing to customers, attracting developers, getting retail placement, etc. But I decided to buy one in this last two days of their Kickstarter campaign.
I know that maybe nothing will come of it. Actually, I think Ouya’s schedule is fairly unrealistic, and there’s a real chance I won’t receive a console at all. But I’d rather take a risk supporting something open than have the certainty of getting something closed.
Legacy Bitmask Puzzle
My friend David had a puzzle in his legacy app. There’s a bitmask called ErrorCode. The table ErrorCodes lists the meaning of each bit:
- 1: Invalid code
- 2: Invalid entity
- 4: Invalid address
- 8: Missing connection
- 16: …and so on
David needs to look up a complete list of the descriptions of every flag from the database. Normally this would just be a simple select * from ErrorCodes.
However, there’s a wrinkle that adds difficulty to the puzzle. The site was maintained by a DBA named George who didn’t understand bitmasks and degraded the code rather than learn. (George is a psuedonym, it came to mind when I thought about an incompetent steward).
An ErrorCode of 6 indicates both an invalid entity and an invalid address, but that confused George, so now the table actually looks like:
- 1: Invalid code
- 2: Invalid entity
- 3: Invalid code and entity
- 4: Invalid address
- 5: Invalid address and code
- 6: Invalid entity and address
- 7: Invalid address, entity, and code
- 8: Missing connection
- 9: …and so on
There are 17 error codes, so the table could have 131,072 rows instead of the 17 we want to select. (Though some combinations are mutually exclusive or didn’t happen to occur in production before George departed.) The table is a kludge, a redundant mess, and there’s an unknown amount of code depending on it.
David’s task was to build this query and get out with minimal risk and change, not find and fix all the misguided code that George left behind. This is how legacy code stays legacy: it’s too risky or expensive to fix, but too valuable to delete. In this case, not only would it cost too much developer time to fix all the code, it would be too risky to add a column to the table to mark which errors are the primary errors we want to select out.
(If you want to solve it for yourself, do so now. Here’s how we solved it.)
David’s first idea was to create a user function that uses bit shifting to check to see if only one bit was set, but that didn’t pass his smell test. When IM’d for my help, I realized a less ugly way to do it and responded with:
SELECT * FROM errorcodes WHERE log(code, 2) == floor(log(code, 2))
Because there’s just 1 bit set, the primary error codes are all powers of two, so the log base 2 of any of them is a whole integer. It means doing math for every row in the table, but that’s one of those small, annoying pains that accumulate when you don’t pay down technical debt.
If you’re curious, David translated this into a LINQ query for his codebase (and accounted for error code 0, “No Error”, an odd exception in its own right), getting:
PpErrors.Where(pe => pe.ErrorId == 0 || Math.Log(pe.ErrorId, 2) == Math.Floor(Math.Log(pe.ErrorId, 2))).OrderBy(pe => pe.ErrorId)
David notes: it’s mostly only “long” because I’m putting it in method notation, instead of query notation, and because I have to reference libraries instead of just having a “floor” and “log” static method in the local namespace. I could write it 12 different ways. You know how that works.
Not Dead
i was just confused as to why you walk out of a car wreck and your biggest concern is missing my fake birthday
Last Monday the top item on my to-do list was to give my friend Rob a call for his fake birthday. Then I got distracted.
I’d borrowed a car for a weekend trip to Madison and was returning on Monday, March 19. I was in the right lane of I-90 when a pickup in the left tried to lane-change into me in his haste to cut around the guy ahead of him. When I braked to avoid a collision, I spun out on the wet pavement and ground backwards to a halt along the crash barrier in the median. The back bumper disintegrated, the side of the car was scraped deeply enough to tear off a door handle, the front bumper was hanging half off.
With luck, and many thanks to automotive and highway engineers, I was uninjured. (The pickup drove off, of course.) The rest of my day was taken up with a police report, insurance report, damage estimates, and an early bedtime. All the usual fallout of a car crash.
The next morning I was trading email with Rob and I told him the whole story of the crash, ending with:
Oh, which is all a long, elaborate excuse for saying I’m sorry I missed your birthday yesterday, Rob. Happy belated!
… thank you?
Wasn’t it March 19 what you moved it to like 20 years ago because you were sick of having a birthday up against Christmas? I thought it was 3/19 and I’m sure it was some lead singer’s birthday…
guitar player. it was Pete Townshend from The Who
you got the date right. i was just confused as to why you walk out of a car wreck and your biggest concern is missing my fake birthday
I’ve been chewing on this question, but the answer is easy: I’m really happy with where I am and what I’m doing with my life. The crash hasn’t made me think “Oh no, I’m wasting my life! I need to quit my job and work on NearbyGamers full-time! Or quit NearbyGamers and work 90-hour weeks! Or join a nunnery! Or win a triathlon!”
I wanted to get right back to what I was doing. I’ve thought deliberately about what kind of life I want, and I’m living it. And I can’t think of a better way to celebrate being alive than to enjoy a fond old joke with a friend.
Timing
Luke, who writes backwards like DaVinci did some more game design with help from #bbg (on irc.freenode.net – anyone’s welcome to drop by to talk browser game development, it’s a great place). Reading his note photo, it looks like he’s breaking cards down into Settings, Characters, and Monsters. There’s not a lot more info, just that he’s spending his hours planning out his game.
Speaking of hours, I missed responding to something in his previous update:
Eventually, I’m going to create web interfaces for a lot of this stuff, but for now I’ll have to do any settings and etc. by hand in the database. By the way, the interface work isn’t strictly game-related and can be handled outside of So Play We All hours.
After the first week we said hours had to be budgeted towards code, but not marketing and blogging. It’s vague here, Jim, what are you referring to working on? If “interface” means HTML frontend, that’s code that’s gotta get counted, Luke and I both did a bunch of template work on budget.
Anyways, this week Jim’s got some nice top-to-bottom functionality done in his rendering engine. It felt a bit like my update about finishing off code from last week. He’s rendering a basic page:
We do not have DisplayRegions yet, so I am just some simple text. However, this page is now valid XHTML and not simple plain-text!
Congrats on the milestone, Jim.
- Cool conference for women devs in NYC next month: http://t.co/ZkV62aQE5i