Thursday, October 28, 2010

Rails is a Mature Framework

At a recent B'more on Rails meetup there were no fewer than 7 companies hiring.

Think about that.

In the midst of one of the worst economic climates of the past 100 years, any quality Rails developer has their pick of jobs, likely for excessive amounts of money. What this means to a developer with qualifications is that all of the hard work that you put in 4 years ago learning a then new framework is paying off. You can use the accumulated skills of 4 years to flow -- to push your skills to the maximum as part of exciting teams and be financially rewarded for it. What more could you want from life?

It is a very exciting time for Rails developers.

It shouldn't be. It should be terrifying.

7 companies hiring means that there is significant cash to be made. And if the current crop of developers is not capable of meeting that demand, you can be sure that commodity solutions are imminent.

"Oh, but there is no way to compete with my awesome craftmanship" you say. While that may be true, how to you prove it? More importantly is it really true? Are you providing so much value that your output at $100+/hr is that much better than offshore developers at $40/hr? Do you really think offshore developers incapable of awesome craftsmanship?

One more thing to note: offshore companies aren't stupid. They are already trying to make inroads into Rails development. They are finding that the old strategies that worked so well in the enterprise world are not of much use with most established Rails shops. They will adapt. They will learn agile. They will learn how to participate in agile teams -- maybe not perfectly, but well enough to compete.

So what to do? For now: flow. Make as much money as possible doing interesting things with energetic teams. Enjoy. But...

Start preparing today for the future.

If you love Ruby and Rails and can imagine wanting nothing more from life, now is the time to kick your personal marketing up a notch to keep yourself differentiated from the coming commodity market (might I suggest a nice chain?). If you cannot differentiate yourself, you will find yourself competing (and often losing) against the commodity market for less pay on less interesting work with lesser developers.

Even if you love Ruby and Rails, maybe it is time to learn something new. Not just dabble, but really learn (again, might I suggest a nice chain?).

Personally, I am going all in on node.js. My main motivation? Simpley that it feels like the Rails community of 3 years ago. The community has a bit of a chip on its collective shoulder. The established players scorn it as insufficient for all uses (which is true just as it was for Rails 3 years ago). And there is just a general level of excitement of newness and seemingly unlimited possibilities.

What are you going to be in 4 years? I will be in the flow. But I'll also be getting ready for the next big thing.

Monday, October 4, 2010

Priorities (This Is the End)

‹prev | My Chain | next ???

Effective immediately, I am breaking my chain.

I am incredibly proud of the effort that I have invested in learning over the past year and the year before. This particular chain is 245 days in a row. Every new day is a personal best. Every new day is a personal best that I will likely never surpass.

This chain is very important to me. Very important.

So, by voluntarily breaking it, I am recognizing that my priorities are shifting. For the past two years, my priorities have been:
  1. Family
  2. Day Job
  3. Learning
With the cessation of my chain, I am effectively recognizing that my priorities are now:
  1. Family
  2. Day Job
  3. Cool New Project
Learning obviously, will continue to be very important to me, but, in the Jim Collins tradition:
If you have more than three priorities, then you don't have any
I have an idea. It is a project about which I am passionate.

In short, it is going to be legendary.

Understanding full well the power of public commitment, I furthermore...

Commit to releasing a private beta within two weeks
Monday, October 18

And..

Commit to releasing a public beta within one month
Thursday, November 4

To make that commitment even stronger, I will directly commit to each of the Awesome Coders I Worked With to get this done (sorry in advance for the Twitter spam, guys).

See you on the other side!

Sunday, October 3, 2010

Readying Things for the Kids

‹prev | My Chain | next›

Up tonight, I need to start thinking about making things a bit easier for my kids to code my (fab) game.

I expect the entry point that will pull in the kids will be the frames animation that prompted me to write the animate-frames plugin for raphaël.js. The problem right now is that the responsibility for describing the frames is in the game room:
Room.prototype.player_frames = function() {
var standing = [
{ label: "left_leg",
style: "fill:none;stroke:#000000;stroke-width:0.99999779px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline",
d: "M 9.7001312,18.93142 C 9.4644309,22.702657 9.2287306,26.473893 8.9930303,30.24513" },

// ...
];

var walking = [
// ...
];

return [standing, walking];
};

Room.prototype.draw_player = function(player, color) {
var frames = this.player_frames();

// set x-y position from player.x, player.y
return this
.paper
.svg_frames(frames)
.translate(player.x, player.y);
};
It is not completely crazy that the room draws the player. The game board is responsible for holding the reference to the raphaël paper object that draws things. It also needs to keep track of players, makes sure that they do not stray out of the room and sends mouse events to the players.

OK, so that is pretty much a bunch of bull. The room might need to ask the player how the player ought to be drawn, but it has no business holding onto that information.

So first up, I make a player_frames global object, in a separate file, javascript/player_frames.js, that will hold that information. The kids ought to be able to get in there and play with things without being distracted by all the other code. As an intermediate step, I replace the player_frames() call with a reference to the global object:
Room.prototype.draw_player = function(player, color) {
// set x-y position from player.x, player.y
return this
.paper
.svg_frames(player_frames)
.translate(player.x, player.y);
};
I then need to pull that global into the page, which is done as a fab.js HTML app:
// ...
( SCRIPT, { src: "/javascript/room.js",
type: "application/javascript" } )()

( SCRIPT, { src: "/javascript/player_frames.js",
type: "application/javascript" } )()


( SCRIPT, { type: "application/javascript" } )
( board_js_string )
()
// ...
Reloading, I start getting all sorts of undefined errors. It takes me a bit, but I eventually realize that one of the problems with HTML (fab) apps is that the server needs to be restarted when changes are made—even to HTML pages.

Once I figure that out, I get things working. Ultimately, I make the Player responsible for the player frames:
Room.prototype.draw_player = function(player, color) {
// set x-y position from player.x, player.y
return this
.paper
.svg_frames(player.frames())
.translate(player.x, player.y);
};
Ah, much better.

That will suffice for tonight. Up tomorrow, I need to get some of the changes to the animate-frames plugin back into the main repository. I would also like to make sure that everything still works with the latest version of fab.js.

Never a shortage of things to learn.


Day #245

Saturday, October 2, 2010

Preventing Unnecessary Loss of Limbs in Games

‹prev | My Chain | next›

The players in my (fab) game are suffering some serious injuries:



Loss of limbs is not occurring immediately or even after a long time roaming about the game room. No, the player's legs are becoming detached after bouncing into each other repeatedly:



Crazy. Where does one even start to track down a problem like that?

Well, since I have made changes to it recently and since it is controlling the player walking animation, I start with animate-frames, my animation plugin for raphaël.js.

In there, I add an offsets() method to the individual frames making up the animation. The offsets calculate the x-y differences between the various strokes of the pen that comprise the frame (e.g. a pen stroke for a foot, leg, body, etc). The x-y differences are between each of the elements and the last element.
  Frame.prototype.offsets = function() {
var diffs = []
,main = this.getBBox();

for (var i=0; i<this.elements.length-1; i++) {
var box = this.elements[i].getBBox();
diffs.push([main.x - box.x, main.y - box.y]);
}

return diffs;
};
The individual offsets should always remain the same—a player's foot should stay 16 pixels away from the body if it was first drawn 16 pixels away. Looking at the first offset when the player first enters the room, I find:
[
0: -6.787272029958575
1: -16.76693459682566
]
After moving the player about the room for a bit, I find:
[
0: -6.787412453957089
1: -16.766913780265497
]
Almost exactly the same. I am not sure about the differences (in the 10,000ths decimal place). Is that caused by simple rounding errors? Maybe timing differences between stop() calls of individual elements is sufficient to cause that problem? Is that small a change even a problem?

Before investigating further, I try colliding my player with another player in the room. Then, I check the offsets again:
[
0: -6.039369453957079
1: -16.56494217026568
]
That is a much more dramatic change. Banging players together some more furthers the offset change:
[
0: -5.144486633957058
1: -16.511516330265806
]
Whatever the problem, it seems that the bouncing of players is the best place to continue my investigation.

But wait...

If I know the expected offset of the individual elements in a frame, can I use them to sync the frame back up to where it is supposed to be?

I think that I can run through each offset, calculate the difference between the current and original offset, then translate the affected frame element by the tiny offset it needs to get back to the right place:
  Frame.prototype.tighten = function() {
var offsets = this.offsets();
for (var i=0; i<offsets.length; i++) {
var x_diff = offsets[i][0] - this.original_offsets[i][0]
,y_diff = offsets[i][1] - this.original_offsets[i][1];

this.elements[i].translate(x_diff, y_diff);
}
};
Yay! That works just as expected. A player falling to pieces gets put back together (tightened up) with a single call.

To put that to practical use, I call it at the end of the translate() method of each Frame object. And, just like that, my players keep all of their limbs.

That is not an entirely satisfactory solution—I never did solve why limbs were flying away in the first place. Rounding errors seems a reasonable explanation, but reasonable explanations do not elicit learning the way that digging deep does. Something to investigate another day.


Day #244

Friday, October 1, 2010

Gah! I Still Don't Know Closures

‹prev | My Chain | next›

I ended a big refactoring of animate-frames last night with some less than DRY code:
  Frame.prototype.remove = function () {
for (var i=0; i<this.elements.length; i++) {
this.elements[i].remove();
};
};

Frame.prototype.show = function() {
for (var i=0; i<this.elements.length; i++) {
this.elements[i].show();
};
};

Frame.prototype.hide = function() {
for (var i=0; i<this.elements.length; i++) {
this.elements[i].hide();
};
};

Frame.prototype.stop = function() {
for (var i=0; i<this.elements.length; i++) {
this.elements[i].stop();
};
};
Let's see if I can DRY that up a bit.

For each of those methods (remove(), show(), hide(), and stop()), I set the prototype property of the Frame object to that repetitive function:
  var methods = ['remove', 'show', 'hide', 'stop'];
for (var i=0; i<methods.length; i++) {
var method = methods[i];
Frame.prototype[methods[i]] = function () {
console.log(method);
for (var j=0; j<this.elements.length; j++) {
this.elements[j][method]();
};
};

}
The only funky thing in there is accessing the method property on each element. element.stop is the same thing as element['stop']—both of them are functions that stop raphaël.js elements. Putting parentheses on either invokes the function: element.stop() and element['stop']().

At least I think that will work. Sadly, when I load that up in my (fab) game, the players do not move at all. Checking the output in the Javascript console, I see that the method being called is always stop()—even when the show() and hide() methods are being invoked.

What gives? Am I messing things up with the property method call?

Actually, no. I have messed up, but what I have messed up here is my Javascript closures. The anonymous function that is being assigned to the Frame.prototype method is itself a closure:
  var methods = ['remove', 'show', 'hide', 'stop'];
for (var i=0; i<methods.length; i++) {
var method = methods[i];
Frame.prototype[methods[i]] = function () {
console.log(method);
for (var j=0; j<this.elements.length; j++) {
this.elements[j][method]();
};
};

}
But the context that it is enclosing includes that var method. My mistake is that the context, the value of var method changes with each iteration through the list of methods. At the end of the iteration, the method variable is set to 'stop'.

What this means is that every one of the methods that I just defined is a stop() method. I do define Frame.prototype.remove(), Frame.prototype.show(), etc. But, when each is called, they use the method from the enclosed context—which is forever more set to "stop".

So what can I do to get the context to stick? I need to add more context—another function:
  var methods = ['remove', 'show', 'hide', 'stop'];
for (var i=0; i<methods.length; i++) {
Frame.prototype[methods[i]] = function(method) {
return function () {
console.log(method);
for (var j=0; j<this.elements.length; j++) {
this.elements[j][method]();
};
};
}(methods[i]);
}
For each method that I am defining, I set the prototype method to the return value of calling the anonymous function with the method name:
    Frame.prototype[methods[i]] = function(method) {
// ...
}(methods[i]);
Now, when I return the same function as earlier, the method variable is in a new, separate context—one that will be remembered when the methods are called. To state is more plainly—in order to ensure that a value in a Javascript closure is what you think it is, it must be defined inside another, enclosing function.

That was unexpectedly difficult. Still, I learned me some good closure. I think I will stop there and move on to resolving the weird bounce issue in animate-frames tomorrow.


Day #243