![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
This screenshot more or less perfectly illustrates what I consider wrong with the Udacity HTML5 game development class. We’re in the middle of a routine for drawing sprites to the screen, and so far this particular lesson, on asset atlasses and sprite packing and all the rest, has been fine, but there’s something in this particular code that makes me twitch hard. Take a look at the “hlf” object created in the middle of this function. What is it doing?
It’s doing nothing. It’s not a transformation. It’s not analysis. It’s not functional. It’s just a renaming of one variable (“center of x”) to another (“half of x”). It doesn’t even help the user understand what’s going on.
But it’s also doing something else. It’s creating a new object in the context of this function. That object goes onto the heap until the Javascript VM performs garbage collection, at which point the entire VM pauses to make sure no references are tampered with as it cleans up. Different VMs (V8, SpiderMonkey, Chakra, etc.) perform garbage collection on different criteria, but all monitor memory growth, watch for times when memory usage exceeds a certain point, and perform routine garbage collection on an interval. Every HTML5 game designer in her right mind should be doing absolutely everything she can to prevent the garbage collector from triggering, and if it must, giving it as little as possible to clean up. A long VM pause is going to make one hell of a mess of your jealously protected 30 frames per second, and depending upon the tightness of your code it may throw off timing routines as well. Remember: setTimeout(func, 60) doesn’t promise to run func exactly 60 milliseconds later; it promises to run func “as soon as possible” after 60 milliseconds has passed. Relying on that while throwing in possible ~100 millisecond garbage collection pauses is a sure recipe for failure.
I understand that this is a basic course, and it’s going to be missing a lot of details. Memoization and hyper-functional up-front calculations are fairly advanced subjects. But there’s a difference between not covering advanced topics and actively teaching students a bad habit.
no subject
Date: 2013-02-19 10:53 pm (UTC)no subject
Date: 2013-02-20 12:03 am (UTC)no subject
Date: 2013-02-20 04:42 am (UTC)no subject
Date: 2013-02-20 05:39 am (UTC)As for cryptic variable names, I have no problem with short names in a function small enough to live in an IDE window. I'm a Haskell hacker, I like names like 'x' and 'xs' to denote 'item' and 'list of items' in a function.
no subject
Date: 2013-02-20 08:57 am (UTC)no subject
Date: 2013-02-20 09:01 am (UTC)no subject
Date: 2013-02-20 09:25 am (UTC)no subject
Date: 2013-02-21 03:49 am (UTC)Sure, the abstraction leaks. All abstractions leak. The point isn't that you should ignore leaky abstractions. The point is that you should pay attention to them when they start leaking. There are all kinds of abstraction leaks that exist. Plugging leaks before the abstractions start to leak is a good example of premature optimization.
I'm going to guess that they aren't using unit tests or TDD either.
What's the target audience for the course? Beginners who don't even know what a memory model is yet? Experts who already know everything except html5 game coding? Or is it a sophomore level hybrid course where they should be getting an introduction to garbage collection as well as the html5 content?
Premature Optimization != !Deoptimization
Date: 2013-02-21 04:47 pm (UTC)Creating that additional variable can also introduce unneeded code later on that can be reduced if you see the obvious part, e.g. -
This is obviously a contrived example, but it illustrates my point. This function will always return 0, but if you don't see the declaration and return on the same screen, it's not immediately obvious.
I (and I believe Elf as well), have no problem with a declaration like so:
Because that actually has a transformation in it, but that is not the case in the example Elf posted.
-Michael
no subject
Date: 2013-02-21 05:21 pm (UTC)You're arguing for coding around abstraction leaks defensively. That's premature optimization. There is no reason a good compiler can't allocate the variable on the stack, and if it does, you may have made the code more difficult to maintain. If it allocates it on the heap, then maybe you'll have a problem, but chances are that you won't until you run into resource constraints, another case of abstraction leakage.
If code quality is an issue here, then your variable names "a" and "b" are likewise problematic. Maybe you'll excuse yourself and say "this is just a code example". It's not clear why that excuse works for a broken idiom, but doesn't work for a defensive idiom.
You have a choice to make, you can make the code as clear as possible, so that maintenance costs are minimized, or you can insert an arbitrary number of defensive practices to guard against leaky abstractions, or anything in between. Different contexts will lead to different decisions. The context of learning generally pushes the decision towards using the abstractions at face value to focus on the particular course content. If the content is the specific abstraction leak, then that's a different story. Remember, this is a course context. The focus is not "best practices" it's about learning about the technology. I assume no one is doing unit tests, no one is doing TDD, no one is doing code reviews, no one is using source code repositories, etc.
no subject
Date: 2013-02-21 05:34 pm (UTC)var a, b, c, d, e, g, h, i, j, k, l, m, n, o;
o = 1;
n = o;
m = n;
l = m;
k = l;
j = k;
i = j;
h = i;
g = h;
f = g;
e = f;
d = e;
c = d;
b = c;
a = b;
This is adding a layer of abstraction that is completely unnecessary to the code that was shown in the original post. You already have references to the two pertinent pieces of information. You're saying it's fully valid to add two more references to the *exact* piece of information? I will admit, I have, on occasion, created my own version of object, either so I can extend it with additional methods, or reformat the data so that it make more sense internal to the application I'm developing. That is not the case here. The code declares two new references to existing data without an apparent improvement in readability, accessibility or clarity.
I agree that an introductory course is not necessarily the place to teach complete "best practices", but neither should it teach inherently bad practices which must then be unlearned later.
-Michael
no subject
Date: 2013-02-21 06:00 pm (UTC)Using aliases for the purposes of documentation is a fairly standard practice.
In the code snippet provided, presumably hlf is an alias for the center of the sprite, indicating that we are using half it's width and height to position the sprite. I could certainly take issue with the use of variable names here. It might be that the person who wrote the code struggled to figure out what cx/cy where, and when they did, they chose to document that in the code. It's not the best job I've seen at doing that, but that is certainly a standard idiom that used commonly in programming. In fact, I'll be happy to admit that I used the hlf identifier as a hint when trying and figure out what the code was doing. As an identifier, hlf carries more semantic information than cx/cy.
I will admit, I have, on occasion, created my own version of object, either so I can extend it with additional methods, or reformat the data so that it make more sense internal to the application I'm developing.
In this case, the object was not extended, but rather narrowed, something which is a not unreasonable thing to do.