Monday, July 2, 2012

Simple Spaceship in HTML 5

Today's post extends last week's orbit by allowing you to control the spaceship.

Demo


Mult:    Refresh: ms   


JavaScript
This code uses the same 3 classes as the previous demo. To keep the math simpler, I assume that the spaceship starts out 1 unit from the center of the solar system and has a speed of 1. Unlike the previous demo, the acceleration follows the inverse square law to improve realism.

Ship
The ship is still a position, velocity, and acceleration, but now it also has a direction and a concept of a thruster.
  1 var Ship = function() {
  2     this.pos = new Vector();
  3     this.vel = new Vector();
  4     this.acc = new Vector();
  5     this.color = "255,255,255";
  6     this.dir = 0;
  7     this.max_dir = 12;
  8     this.thrusterOn = false;
  9     this.thrusterForce = 0.1;
 10     this.size = 0.01;
 11 }
 12 
 13 Ship.prototype.turnRight = function() {
 14     this.dir = (this.dir + 1) % this.max_dir;
 15 }
 16 
 17 Ship.prototype.turnLeft = function() {
 18     this.dir = (this.dir + this.max_dir - 1) % this.max_dir;
 19 }
 20 
 21 Ship.prototype.angle = function() {
 22     return this.dir * 2 * Math.PI / this.max_dir
 23 }
 24 
 25 Ship.prototype.adjust = function(time) {
 26     if (this.thrusterOn) {
 27         this.acc.x += this.thrusterForce * Math.sin(this.angle());
 28         this.acc.y -= this.thrusterForce * Math.cos(this.angle());
 29     }
 30     this.vel.adjust(this.acc, time);
 31     this.pos.adjust(this.vel, time);
 32 }
 33 
 34 Ship.prototype.draw = function(ctx) {
 35     ctx.save();
 36     ctx.translate(this.pos.x, this.pos.y);
 37     ctx.rotate(this.angle());
 38     ctx.strokeStyle = "rgb(" + this.color + ")";
 39     ctx.scale(this.size, this.size);
 40     ctx.beginPath();
 41     ctx.moveTo(0, -10);
 42     ctx.lineTo(5, 10);
 43     ctx.lineTo(-5, 10);
 44     ctx.lineTo(0, -10);
 45     ctx.stroke();
 46 
 47     if (this.thrusterOn) {
 48         ctx.fillStyle = "rgb(" + this.color + ")";
 49         circle(ctx, 0, 11, 1);
 50         circle(ctx, -2, 13, 1);
 51         circle(ctx, 2, 13, 1);
 52         circle(ctx, -4, 15, 1);
 53         circle(ctx, 4, 15, 1);
 54         circle(ctx, -1, 15, 1);
 55         circle(ctx, 1, 15, 1);
 56     }
 57     
 58     ctx.restore();
 59 }
Simulation
The simulation has the same responsibilities as before, but also scales the display so that a radius of 1 in ship space corresponds to halfway out on the canvas.
  1 var Simulation = function(ctx, size) {
  2     this.ctx = ctx;
  3     this.size = size;
  4     this.reset();
  5 }
  6 
  7 Simulation.prototype.drawStar = function() {
  8     this.ctx.fillStyle= "#FF0";
  9     circle(this.ctx, 0, 0, 20);
 10 }
 11 
 12 Simulation.prototype.draw = function() {
 13     this.ctx.fillStyle = "rgba(0,0,0,1.0)";
 14     this.ctx.fillRect(0, 0, this.size, this.size);
 15     
 16     var dim = this.size/2;
 17     
 18     this.ctx.save();
 19     this.ctx.translate(dim, dim);
 20     this.drawStar();
 21     this.ctx.scale(dim/2.0, dim/2.0);
 22     this.ship.draw(this.ctx);
 23     this.ctx.restore();
 24 }
 25 
 26 Simulation.prototype.step = function() {
 27     var ship = this.ship;
 28     var acc = ship.acc;
 29     var angle = Math.atan2(ship.pos.x, ship.pos.y);
 30     var d2 = ship.pos.x*ship.pos.x + ship.pos.y*ship.pos.y;
 31     acc.x = -Math.sin(angle) / d2;
 32     acc.y = -Math.cos(angle) / d2;
 33     ship.adjust(this.mult);
 34     if (d2 > 16) {
 35         this.stop();
 36         alert("Ship Left Orbit!");
 37     }
 38 }
 39 
 40 
 41 Simulation.prototype.reset = function() {
 42     this.stop();
 43     var ship = new Ship();
 44     ship.pos.x = 1.0;
 45     ship.pos.y = 0.0;
 46     ship.vel.x = 0.0;
 47     ship.vel.y = -1.0;
 48     this.ship = ship;
 49 }
 50 
 51 Simulation.prototype.run = function(mult, refresh) {
 52     this.stop();
 53     this.mult = mult;
 54     var self = this;
 55     this.timer = setInterval(function() {
 56         self.step();
 57         self.draw();
 58     }, refresh);
 59 }
 60 
 61 Simulation.prototype.stop = function() {
 62     clearInterval(this.timer);
 63 }
Helper Function
Both the above classes call the helper function "circle" for drawing filled in circles.
  1 var circle = function(ctx, x, y, rad) {
  2     ctx.beginPath();
  3     ctx.arc(x, y, rad, 0, 2*Math.PI, false);
  4     ctx.fill();
  5 }
Onload
We need a few more controls, so the onload portion has a little extra functionality.
  1 $(function() {
  2     var canvas = document.getElementById("canvas");
  3     var size = 500;
  4     canvas.width = size;
  5     canvas.height = size;
  6     var ctx = canvas.getContext('2d');
  7     var sim = new Simulation(ctx, size);
  8     sim.draw();
  9 
 10     $("#run").click(function() {sim.run($("#mult").val(), $("#refresh").val())});
 11     $("#stop").click(function() {sim.stop()});
 12     $("#reset").click(function() {sim.reset(); sim.draw();});
 13     $("#ccw").click(function() {sim.ship.turnLeft(); sim.draw();});
 14     $("#cw").click(function() {sim.ship.turnRight(); sim.draw();});
 15     $("#thruster").mousedown(function() {sim.ship.thrusterOn = true; sim.draw();});
 16     $("#thruster").mouseup(function() {sim.ship.thrusterOn = false; sim.draw();});
 17 });
HTML
Again, the HTML is just a canvas along with some controls.
  1 <canvas id="canvas"></canvas>
  2 <br />
  3 Mult: <input id="mult" type="text" value="0.01" size="4" />
  4   
  5 Refresh: <input id="refresh" type="text" value="15" size="3" />ms
  6   
  7 <button id="run">Run</button>
  8 <button id="stop">Stop</button>
  9 <button id="reset">Reset</button>
 10 <br />
 11 <button id="ccw">CCW</button>
 12 <button id="cw">CW</button>
 13 <button id="thruster">Thruster</button>

Monday, June 25, 2012

Going in Circles via Html5

Today's post is just a simple little HTML5 animation using canvas that moves a spaceship in orbit around a star (not to scale).

Demo

Mult:    Refresh: ms   

JavaScript
This may be over-engineering for such a simple program, but there are 3 javascript classes used to accomplish this.

Vector
(not a Java Vector but a math vector)
  1 var Vector = function(x, y) {
  2   if (arguments.length == 0) {
  3     x = 0.0;
  4     y = 0.0;
  5   }
  6   this.x = x;
  7   this.y = y;
  8 };
  9 
 10 Vector.prototype.adjust = function(v, mult) {
 11   this.x += v.x * mult;
 12   this.y += v.y * mult;
 13 }

Ship
A ship consists of 3 vectors (position, velocity, and acceleration), and also knows how to draw itself.
  1 var Ship = function() {
  2     this.pos = new Vector();
  3     this.vel = new Vector();
  4     this.acc = new Vector();
  5     this.color = "255,255,255";
  6 }
  7 
  8 Ship.prototype.adjust = function(time) {
  9     this.vel.adjust(this.acc, time);
 10     this.pos.adjust(this.vel, time);
 11 }
 12 
 13 Ship.prototype.draw = function(ctx) {
 14     ctx.save();
 15     ctx.translate(this.pos.x, this.pos.y);
 16     ctx.strokeStyle = "rgb(" + this.color + ")";
 17     ctx.beginPath();
 18     ctx.moveTo(0, -10);
 19     ctx.lineTo(5, 10);
 20     ctx.lineTo(-5, 10);
 21     ctx.lineTo(0, -10);
 22     ctx.stroke();
 23 
 24     ctx.restore();
 25 }

Simulation
A simulation consists of the ship, knows how to accelerate the ship around in an orbit, and has the commands for actually starting, stopping, and running the simulation.
  1 var Simulation = function(size) {
  2     this.size = size;
  3     this.reset();
  4 }
  5 
  6 Simulation.prototype.drawStar = function(ctx) {
  7     ctx.fillStyle= "#FF0";
  8     ctx.beginPath();
  9     ctx.arc(0, 0, 20, 0, 2*Math.PI, false);
 10     ctx.fill();
 11 }
 12 
 13 Simulation.prototype.draw = function(ctx) {
 14     ctx.save();
 15     ctx.fillStyle = "rgba(0,0,0,1.0)";
 16     ctx.fillRect(0, 0, this.size, this.size);
 17     ctx.translate(this.size/2, this.size/2);
 18     this.drawStar(ctx);
 19     this.ship.draw(ctx);
 20     ctx.restore();
 21 }
 22 
 23 Simulation.prototype.step = function() {
 24     var ship = this.ship;
 25     var acc = ship.acc;
 26     acc.x = -ship.pos.x;
 27     acc.y = -ship.pos.y;
 28     ship.adjust(this.mult);
 29 }
 30 
 31 
 32 Simulation.prototype.reset = function() {
 33     this.stop();
 34     var ship = new Ship();
 35     ship.pos.x = this.size / 4;
 36     ship.pos.y = 0;
 37     ship.vel.x = 0;
 38     ship.vel.y = -this.size / 4;
 39     this.ship = ship;
 40 }
 41 
 42 Simulation.prototype.run = function(ctx, mult, refresh) {
 43     this.stop();
 44     this.mult = mult;
 45     var self = this;
 46     this.timer = setInterval(function() {
 47         self.step();
 48         self.draw(ctx);
 49     }, refresh);
 50 }
 51 
 52 Simulation.prototype.stop = function() {
 53     clearInterval(this.timer);
 54 }

On Load
Then there is the little bit of code to kick everything off, which leverages jQuery. This just sets the size of the canvas, and links the input controls from the HTML to the Simulation object.
  1 $(function() {
  2     var canvas = document.getElementById("canvas");
  3     var size = 500;
  4     canvas.width = size;
  5     canvas.height = size;
  6     var ctx = canvas.getContext('2d');
  7     var sim = new Simulation(size);
  8     sim.draw(ctx);
  9 
 10     $("#run").click(function() {sim.run(ctx, $("#mult").val(), $("#refresh").val())});
 11     $("#stop").click(function() {sim.stop()});
 12     $("#reset").click(function() {sim.reset(); sim.draw(ctx);});
 13 });

HTML
The HTML is just a canvas along with some inputs to control the simulation.
  1 <canvas id="canvas"></canvas>
  2 <br />
  3 Mult: <input id="mult" type="text" value="0.01" size="4" />
  4   
  5 Refresh: <input id="refresh" type="text" value="15" size="3" />ms
  6   
  7 <button id="run">Run</button>
  8 <button id="stop">Stop</button>
  9 <button id="reset">Reset</button>

Monday, May 7, 2012

Thoughts on Interviewing

I've been on both sides of the interviewing table a number of times. Currently I'm on the less stressful side, that of trying to find a good candidate. So how do you find a good candidate?

Joel on Software has two criteria: Smart, and Gets Things Done. His Guerrilla Guide to Interviewing does a good job of explaining what he means, so I won't repeat it. The question is, how do you determine if someone is smart and/or gets things done?

The Google/Facebook style of interviewing where you have to solve problems on a whiteboard answers the "smart", at least for a certain type of smart, and assuming that you don't freeze up under the pressure of interviews. But what about "gets things done"? The ability to solve problems doesn't mean that you will work diligently. So the best way I know to determine that is to investigate your track record. An internship or trial hire period would be better, but since that isn't typically an option, it instead means trying to figure out from someone's resume and their answers to questions about it. This is very much, an inexact science.

What about smart? Different positions require different degrees of intelligence. As my boss reminded my, the work that we currently do doesn't require super genius intelligence. However, I maintain that no matter how mundane the job is, it is better to have higher caliber employees doing them. Do you really want to be maintaining the software of someone who is just barely qualified to do the job? Are you really going to go to that person for help when an issue arises? How are you going to learn and improve while working with someone who just wants to get by?

Therefore, while I am not looking for super-geniuses, I do want someone who is more than just barely competent. So how do I personally test for that?

Based on Joel's article we now make candidates write some programs on the whiteboard. We are hiring a programming position. If you want the job you should be capable of turning thoughts and ideas into code. I realize that between modern IDEs and the internet, modern day programmers have access to unprecedented levels of help. However, you shouldn't be dependent on that help. If you don't know the difference between AND and OR without looking it up, or you don't know any collection types other than an ArrayList, how can I be confident that you will write quality maintainable code?

How about theoretical knowledge from a CS program? How important is that? I realize how much importance you put on that will depend on your own skills and experiences. While it may not be important to actually know that the time complexity of a bubble sort in O(n2), at some point you will run into code that is running unacceptably slow. If you don't show any knowledge of time complexity, what evidence do I have that you will actually pick out the bottlenecks of a slow program and know how to fix them? (or even better, how to avoid them in the first place?)

Unfortunately for me, every example above came from recent interviews I've done. Am I wrong to think that a Java developer should be familiar with more than just ArrayList from the java.util Collection classes? Is it random trivia to remember the time complexity of bubble sort? I think these are examples of things people who care about the craft of software development should know, but maybe I am biased by my own experiences?

What do you think?

Monday, April 16, 2012

Saved By The VM

One of the most exhilarating, but also frustrating, aspects of working in computers is how fast things move. Things that would've been considered disgracefully wasteful years ago, now provide us with solutions that I never would've imagined then. For example the editor that I am using to write this is running inside of my browser. In effect, the browser is acting as a virtual machine, and the editor is just one application running on it. How much CPU "wastage" is there by running in a VM rather than a native application? Who knows, but it doesn't matter, as my laptop isn't even breaking a sweat. And this is just one of dozens of tabs that I have open in the browser, and the browser is just one of over a dozen applications running currently (plus who knows what the OS is doing).

Not only is CPU time cheap, but so is storage. At work, our network storage takes automatic snapshots, which makes it trivial to retrieve from backups. This would've seemed incredibly wasteful to me not that long ago. This, combined with VMs, saved me a ton of work this past week.

Torquebox 2.0.0 was released recently, and I wanted to get it installed on our development server. While I was doing this, I decided to upgrade the version of Java running on the machine. I downloaded the latest version and installed it. Unfortunately, I wasn't paying attention and I let it install in the default location, rather than our group's standard location. In a moment when I was apparently flashing back to the days of yore, I thought I could just move the Java directory structure to the location where I wanted it. Since the registry settings did not get updated in the process, bad things happened. My first attempt to fix things was to just delete the Java directories, and reinstall it. Unfortunately, Java thought it was still installed, and refused to reinstall. So then I asked Windows to uninstall Java, but a DLL was missing (probably because I had already deleted it), so it couldn't uninstall either.

What was I to do? I spent some time fiddling with the Windows Registry, but that was getting me nowhere. Finally, I came to my senses and remembered what year it was. Our servers are running on VMs which means it's just an image on a network disk somewhere, which has regular snapshots taken. So I just wandered down the hall and asked one of our system administrators to restore the VM to an image from the day before. A few minutes later, my mess was cleaned up.

So yes, VMs are wasteful and inefficient, but they sure save time sometimes. And what's all this extra CPU power for, if not to make our lives easier?

Monday, April 2, 2012

Pair Programming - My Experiences

I've mentioned pair programming before in the context of the psychology of extreme programming, but I haven't said too much about it. This is because I've had very little first hand experience with it. Well, in the last couple of months I've spent a lot of my time pair programming, and here are my preliminary thoughts.

Distractions
I have argued that pair programming can cut down on distractions. I find this to be true. When working on my own if I execute a command that I know will take 5 or more seconds, it is very tempting to take this break to check my email or read a slashdot article. Unfortunately, while I justify this as being efficient, in reality it turns a 5-10 second pause into a couple minute pause. The change of context also flushes some registers, err.. short term memory, making it harder to be as focused when I first switch back to my development tasks.

When someone is looking over my shoulder, I am not going to make that context switch.

Motivation
I find that my enthusiasm for projects ebbs and flows. I'll be gung-ho for a while, and then my motivation will slip away. Its easier to keep working in a pair, both from the peer-pressure that you don't want to be slacking, and just the fact that its more fun.

Efficiency
I've always read that pair programming is more productive than one person working alone, but not twice as productive. (measured in terms of how much code gets written per unit time). My experience of the past couple months agrees with this. Of course this ignores other benefits from pair programming, like potentially higher quality code, and the implicit cross-training that happens.

Correctness
Pair programming definitely cuts down on mistakes. While the person on the keyboard is directly thinking about what they are doing, the backseat driver can focus on this big picture. These two different views helped us realize shortcomings that would not have been found until production had either of us been working alone. Also, when bugs were encountered, having two people (who think differently) looking at them, meant we were able to resolve them quicker.

Drawbacks
There are a few problems that I encountered with pair programming. The most obvious one is scheduling. The two of us paired up have different schedules in our personal lives, so we don't show up at the same time, or leave at the same time, or even take our lunch breaks at the same time. Plus we both have other professional responsibilities that sometimes require one or the other's attention at various times at the day. Thus an eight hour work day results in only four or five hours of useful pairing time.

The problem that I didn't expect was energy drain. After a couple of weeks of doing primarily pair programming I felt mentally exhausted. While we got a lot done, it wasn't a pace that I can maintain indefinitely. I think the little breaks that I normally build into my day, which were missing when pair programming, helped keep me fresh. I suspect that I can address this problem by intentionally scheduling breaks when pairing up.

it is most effective to work alone for a whileThe third, and most important, problem is problem solving. There are obviously times when two heads are better than one. But there are also times where the two heads need to work on their own. To solve difficult design problems, or to come up with innovative solutions to a problem, I truly believe it is most effective to work alone for a while. Then, after I've had a chance to think about it in my own way and come to my own conclusions, is the time to meet and discuss the ideas with others. i.e. if we work together on a solution, we will come up with one solution. If we work independently, we will come up with two solutions, from which we can then draw a third solution that is better than what either of us came up with independently, or if we had worked together all along.

Conclusion
Pair Programming has a place in your toolkit of software development skills. I think it can be really helpful when working on software that you want to be reliable, you want more than one person intimately familiar with the code base,  and which doesn't require too much innovative problem solving. However, like most things, moderation is the key. There are definitely times when pair programming will hinder you.

If you have the opportunity, give it a try. However, be open to the fact that it isn't best for all situations, so don't force it if it doesn't fit.

Monday, October 31, 2011

Chasing Technology

Maybe I'm just getting old, but keeping up with technology seems to be getting harder and harder. As I've mentioned before, I am a big fan of learning your libraries, languages, and tools. But how are you supposed to do that, when the libraries keep upgrading and there are constantly new tools to use? Just this past week there was a post on slashdot suggesting that tech skills have a 2 year half life. The comments on that thread seem to mostly disagree with the hypothesis, but there is definitely some truth to it.

The two languages that I use the most at work did not exist when I started college. However, languages are easy to keep up with. They tend to move slowly and are very well documented. Tools, libraries, and frameworks, on the other hand, are a nightmare to chase. They are constantly being upgraded, and often times the best documentation are the question/answers out there on the web at places like stackoverflow. The problem with these sites is that they are only useful after a tool has been out long enough for a critical mass of people to use.

So what's a person supposed to do?

Well, first, as many commenters from the slashdot article stated, the most valuable skills a software engineer has is knowing how to design, develop, and debug software. These skills don't go away just because you are using a new language or library. So play to your strengths. If you design and write clean code, it'll be easier to fix/update as you learn the language/library/tool better.

Second, choose your upgrades carefully and intentionally. Just because there is a newer version of something out there, doesn't mean you need to use it. Are the benefits worth it to upgrade now? Does it make more sense to wait until it has been popularly adopted? Or maybe it makes sense to skip a version or two.

Third, don't become an expert in everything. Most of us have finite amounts of energy and time. So, while I'm a big believer in being an expert in the tools you are using, that isn't always practical. If a particular tool/library/framework is bound to be upgraded/replaced in the near future, it's probably ok if you use the existing library in a less than optimal way. Focus your energies on the timeless (design and coding skills) or the long lasting (languages).

constantly learnFourth, and most importantly, constantly learn. If your employer doesn't provide opportunities for professional growth, take it anyway. Just as you don't ask for permission for every single test that you write, or every whiteboard design that you draw, you don't need permission to explore new technologies and tools. Whether they know it or not, your employer pays you to be a good and competent software developer. This requires you to be constantly learning new and better ways of doing things. If you are not taking ten to twenty percent of your time exploring and learning, you are shortchanging yourself and making yourself obsolete. I realize that it seems there is never time to do this, but like other aspects of good software engineering (appropriate design, testing, documentation), in the long run you will be worse off if you don't make the investment now.

Monday, October 10, 2011

Vexing Bugs

While bugs are a part of development, there are a few types of bugs that I find particularly vexing: intermittent bugs, library bugs, and bugs that only happen in production.

Intermittent Bugs
It's annoying to perform the exact same set of steps 4 times, have it work 3 of the times, and fail once. When Murphy has his way, it works when you, perform the steps or are watching, but fails when the user does it on their own. How do you diagnose a bug that you can not reliably reproduce?

Library Bugs
The majority of library bugs aren't actually bugs in the library, but rather a bug in how you are using the library. Either way, having cryptic error messages coming out of the bowels of a library, when there is no apparent connection between the error and your code, is not fun. I find the process of googling error messages or library usages to be much more frustrating than tracking down errors that are entirely in my own source code.

Production Bugs
While we strive to have our development environment similar to the production environment, there are certain discrepancies that always creep in. Things like debug information, optimization level, database source, etc. When in development, you don't want to be messing with production data, and your willing to give up some performance to better track the code. But since it isn't the same, code that works fine in development doesn't always work in production. Ugh.

This Week
So what prompted this post? Well, this week I had a bug that was at the intersection of these bugs. We had deployed a new version of our application, and suddenly I started getting server emails about errors. It was some cryptic error happening within the library we use for making Web Service calls. And, of course, the errors only happened sometimes. Even more frustrating, when trying to reproduce the error on my local box using WEBrick in development mode, the error never happened.

After setting up a development server on my local box that was configured just like the production box, I was able to intermittently reproduce the error. Using my standard debugging technique of adding printfs, I eventually noticed output that looked like:

Starting Web Service Call 1
Starting Web Service Call 2
Exception Caught from Web Service Call 2
Ending Web Service Call 1

Unfortunately, it didn't catch my eye right away, but I eventually noticed that every time there was an error, the web service calls were getting interleaved. i.e. Web Service Call 2 was starting before Web Service Call 1 started. And now it suddenly made sense. 

The two web service calls were being made as the result of two separate AJAX callbacks from a web page. Since the the two web service calls were being done in two different web requests, they were being handled in parallel resulting in a race condition. As it turns out, the web service library we were using is not thread safe. However, apparently WEBrick in development mode was serializing these requests (i.e. not processing 2 until 1 was completely handled), and so in development there were no threading issues. 

As with most bugs, once the problem had been diagnosed, it wasn't that hard to fix. In this case, we put the web service calls in a critical section, forcing them to be serialized. For our particular use case, the higher latency of serializing the web service calls was acceptable, allowing for a fairly simple solution.

Moral
This post wasn't really intended to have a moral. It was mostly just me talking about my week, but I suppose there are a couple good ideas.
  • If you think its a library bug, you are probably misusing the library. (i.e. Learn your libraries)
  • Intermittent errors are indicative of threading issues.
  • Know the differences between your development and production environments.
    oh, and maybe most importantly of all
  • When frustrated, take a break. I didn't actually track down the bug until I walked away from it for a while and then came back to it with fresh eyes.