kai_mactane: (Default)

When a company says “we can’t afford a QA department”, what they’re really saying is, “we accept that our software will be infested with bugs, and quality is not important to us.” When they compound this basic error by saying, “the developers will just have to do their own QA”, they prove that they have no respect for developers or QA people, and you shouldn’t work for such a company in either capacity.

(Of course, a company like that isn’t about to hire any QA testers, so you folks haven’t got the option of working for them. And I’m not a QA tester, I’m a developer. So the rest of my advice is pretty much aimed at fellow devs — but that doesn’t mean I don’t respect you QA folks. Seriously, y’all deserve a lot more respect than you get, and I love it when you make my life easier by finding my bugs for me.)

The skills, talents, and basic mindset that make a good developer are entirely different from the ones that make a good QA person. Asking one to do the other’s job is a mistake as fundamental as expecting graphic designers and accountants to swap places. Let me explain:

Developers hate repetition. We hate having to repeat anything more than once or twice; that’s why some of us become developers in the first place: because we can write programs that automate repetitive drudgery, and hence banish it from our lives.

Read the rest of this entry »

Originally published at Coyote Tracks. You can comment here or there.

kai_mactane: (Default)

First things first: Never actually do this. This is just a fun curiosity, for amusement value only.

Because of the way JavaScript’s search() method works, you can do:

var my_url = 'http://kai.mactane.org';
if (! my_url.search(/http:\/\/kai.mactane.org/)) {
    alert("Your URL is http://kai.mactane.org");
} else {
    alert("Nope, your URL isn't http://kai.mactane.org");

Try running this, and it will correctly claim that “Your URL is http://kai.mactane.org” — even though there’s a ! at the beginning of the test. What gives?

That exclamation point looks like it’s saying: “If the search for http://kai.mactane.org within the given string fails…” But what that test is really saying is: “If the search for http://kai.mactane.org returns Boolean false — or anything that evaluates as Boolean false…”

What that search() call actually returns is the character index at which the needle is found, or -1 if it isn’t found. Since the needle is found at the very beginning of the haystack — at character index 0 — search() returns zero. Which evaluates to false in a Boolean context.

If the needle isn’t found, the search will return -1 — which evaluates as true in a Boolean context!

Effectively, the ! operator is reconciling the disagreement between search()’s idea of falsehood and if()’s idea of falsehood: search() returns -1 for a false result (a failed match), but if() considers -1 to be true, not false.

This trick only works with needles that you are sure will only occur at the beginning of the haystack.

Once again, you should never, ever actually write code like this for any serious purpose or in anything you intend to deploy in the real world. The maintainability problems are not worth the amusement of confusing all your co-workers with a test that looks reversed. Instead, use a positional anchor in your regex, and explicitly test against -1…

if (my_url.search(/^http:\/\/kai.mactane.org) != -1)

…like any sensible JavaScript coder. (Yes, that last bit is intended to be ironic. I wrote something once about the silliness of having to add that extra test; I’ll have to see if I can find it and republish it here. )

Originally published at Coyote Tracks. You can comment here or there.

kai_mactane: (Default)

Let’s say one day you decide to add a feature to your software or service. For example, you need a new flag on user accounts, so that different types of users get different features. (These don’t even have to be tiered account levels; maybe accounts of type “music lover” get a widget in the sidebar with suggestions for bands they might like while “sports fan” accounts get a sports scores widget instead.)

So, following good software development processes, you first write a couple of tests:

Read the rest of this entry »

Originally published at Coyote Tracks. You can comment here or there.

kai_mactane: (Default)

A while back, when I was writing Hummingbird, I needed to look for Twitter usernames in various strings. More recently, I’m doing some work that involves Twitter at my new job. Once again, I need to find and match on Twitter usernames.

Luckily, this time, Twitter seems to have updated its signup page with some nice AJAX that constrains the user’s options, and provides helpful feedback. So, for anyone else who needs this information in the future, here’s the scoop:

  1. Letters, numbers, and underscores only. It’s case-blind, so you can enter hi_there, Hi_There, or HI_THERE and they’ll all work the same (and be treated as a single account).
  2. There is apparently no minimum-length requirement; the user a exists on Twitter. Maximum length is 15 characters.
  3. There is also no requirement that the name contain letters at all; the user 69 exists, as does a user whose name I can’t pronounce.

If you want a regex to match on this, /[a-zA-Z0-9_]{1,15}/ would be nice and safe for use in both POSIX and Perl-style regex syntax. (If you’ve got Perl-compatible regexes, /\w{1,15}/ is quick and easy.)

Originally published at Coyote Tracks. You can comment here or there.

kai_mactane: (Default)

My latest project is something I call “LJ Content Sieve”: a Greasemonkey script to filter out content on one’s Livejournal views based on nearly any attribute of a post or comment.

However, Livejournal is very customizable. It has 31 different “layouts”, each of which can then be further “themed” by application of CSS. This means that a user viewing a given journal, community, or single post, at a given time, may receive an HTML document containing any of 31 different DOM structures.

This means that finding a post’s author, or title, or even just a single post or comment, is not a straightforward process. I’ve set myself up a Ruby script that downloaded my “friends” view, a representative entry with lots of comments, and my own journal view, thus giving me a set of 93 fixtures that I can test against. The Ruby script also tweaked each fixture in the process of spooling it to my hard drive, by adding the proper calls to JSUnit files.

At the end of each document’s <head> element, there’s a call to jsUnitCore.js. Then, at the end of each <body>, I add a call to the lj-content-sieve.user.js script itself, as well as a set of test files that depends on which fixture this is. Every fixture gets an ljcs-global-tests.js call added to it — that file contains tests that should work anywhere, regardless of what sort of page you’re on.

Then all the “friends” page fixtures get an ljcs-friends-tests.js file, which tests operations that should happen on every friends page. For example, determining which entries need to be deleted. (In contrast, single-entry pages get ljcs-entry-tests.js, and the page from my own journal — which stands in for a view of a community — gets ljcs-self-tests.js.)

Finally, each fixture page gets a test file based on its layout: the “3 Column” layout gets ljcs-3 Column-tests.js, while “Cuteness Attack” gets ljcs-Cuteness Attack-tests.js. (Hey, I didn’t write or name the layouts; I just have to make sure LJCS works with all of ‘em.) These files will test that the actual DOM manipulations work properly.

Without test-driven development and automated testing to ensure that each layout and page-type is being handled properly, I don’t think this project would be manageable at all.

Originally published at Coyote Tracks. You can comment here or there.

kai_mactane: (Default)

I don’t want to optimize this code prematurely. And “while you’re still writing it” is probably premature. On the other hand, totally ignoring algorithmic complexity is a sure route to a Shlemiel the Painter’s algorithm.

Do I really want to just write the whole thing, and then start profiling it to see where the hot spots are, and then possibly have to re-design the whole thing? That seems like the complete opposite of “work smarter, not harder”. Then again, it doesn’t matter if you write an O(n2) or even O(n!) algorithm if n is always going to be small… and in this application, I expect low-to-middling n values.

Of course, even if n will always be small, and increasing CPU power is my friend… even if it performs fast enough to make users happy, I’ll still know there’s a problem down there in the details. That may be the deciding factor.

Originally published at Coyote Tracks. You can comment here or there.


kai_mactane: (Default)

July 2011

101112 13141516


RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 20th, 2017 09:51 pm
Powered by Dreamwidth Studios