elfs: (Default)

I learned an important lesson today: never put on hold a book from the library that’s already listed on the shelves. Just go get it. If it’s on hold, they’ll take it off the shelves and put it “into the system,” which means you won’t actually be able to get it for 24 hours.

I also learned another important lesson. Always start a few load-creating automated tests, then go to the most hostile wi-fi enabled cafe you know and try to use your web application from there.

The King County Library System recently spent a lot of money upgrading their computerized system. It looks like there was a desperate attempt to make it “more 2.0″ by throwing a thin layer of AJAX into the mix: searches now update page partials rather than whole pages, and various divs for holds, fines, checkouts, and wishlists come and go as you click on the appropriate tabs. All fairly unimpressive, by my standards. The developers, whomever they were, used Adobe’s library as their basis as the Javascript is full of Dreamweaver-related (“MM_”) tags. Where they didn’t use Dreamweaver, they wrote the code themselves; there’s a strong Not Invented Here feel to much of the Javascript they used.

And I’m sure, when they first started out, it looked okay. They tried to search for a few books, the spinner spun for a second and then the page rendered. Only now, under load, the spinner spins for a several seconds, and then the page goes blank. A long pause later, the page begins drawing again. The clue that the spinner needs to stop and the signal that the data is ready to be drawn are two different signals.

There are several examples of this, but the book search is the most egregious. All in all, the upgrade has made a lot of people mad: renderers don’t work, often fail to deliver, time out without excuse. And this doesn’t have to be hard. KCLS has slightly under a million items, and had 21 million check-ins last year, or about 3 a second during business hours. Prodigious, but seriously middle-tier as far as businesses go. A modern implementation of the website should not be as difficult as they’ve made it.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

I love being able to combine one of my favorite design techniques with my latest infatuation.  It makes my hair tingle.

Gamification,” as any buzzword-compliant high-priced consultant will tell you, is the process of adding game mechanics to a website in the desperate hope that trivial reward mechanisms– badges, stickers, and made-up titles straight out of your D&D years– will encourage your customers to come back and visit your website again.  At least, that’s what gamification appears to be on the surface.  That is a shallow and useless description.  Badges, “experience points” and useless labels will not encourage anyone to use your website.

Story cards” are a specification tool used in Agile and eXtreme Programming development.  A story card (usually a hand-written 3×5 card) describes the “happy path” of a user doing something useful with your software: “The user logs in,” “the user searches for a movie,” “the user watches a movie,” “the user likes a movie,” (here, “likes” is emphasized to record that “liking” is an application-specific verb).  (I use the example of a movie-selling website because I work for a movie-selling company.)  Before a development sprint, the team sorts the cards by priority, makes estimates as to how long it would take to write code that would fulfill each story, and then begins bargaining to establish who has responsibilities for each story, along with the usual ensuring that one developer’s track will not confound another’s.   A sprint is made, and then the developers assess.  A “story” is a small, atomic action a user can take with your software.

Deep, rich websites typically have dozens, if not hundreds, of stories.   Often, many of those stories will go completely ignored by your users.   They may be obscure or difficult to find in your navigation.; alternatively, their value to your users may not be obvious.  As a website owner, you want users to try out every story you have; you never know which constellation of the many stories your website supports will be the one that hooks any individual user to engagement.   If you don’t encourage your user to try out everything, you’re wasting your website.

Gamification helps prevent this waste.  It’s is an incredibly easy concept to grasp; you could write a Django app or Rails plug-in to support it in a single afternoon.   The gamify application looks like this:  For any given story (usually, “gamification experts” will call this a “user action”), the customer accrues a certain amount of currency. (Do not be confused by this word.  It does not imply money, or “virtual currency”; it’s merely a tally of whatever it is your tracking the accrual of: experience points, votes, the number of times a user has reviewed a movie, the consistency with which a user has visited your website.)  At some point (maybe even immediately), your software awards something to the user.

This is where the whole “badges, levels, titles” thing gets confusing– and annoying.  Because rarely does the user want a badge, a level, or a title.  What the customer wants is enlightenment. What you want is engagement. What your software awards to the customer should not merely be a badge, a level, or a title– your software should award the customer the information and tools needed to engage more.

Gamification is not turning your website “into a game.”  That’s stupid.  If I want a game, I’ll fire up the Playstation.  Better yet, I’ll go find my kids and a deck of Uno cards.  Gamification is the mechanism by which your website’s user manual is turned into easily digestable and entertaining awards, leading users by the hand from one capability to the next.

So get out your story cards and arrange them, not in the order in which they could be accomplished by the developer, but an order in which you want a customer to encounter them.   Sometimes, this order will be linear, but more often not.  Lay the cards on the table, with “sign up” at the top, and then the “natural” things the user would do as a second line of cards underneath, then more complicated things.  Maybe down at the bottom you could put the “epic win” cards of your website: the most popular filmmaker, or most respected reviewer, or whatever.   Now, for each card, you have to come up with a parallel game card: write down what currency we track in this story, and when the user has completed the story, what award will lead the user to other cards.  The award is a fragment of your user manual: “Now that you’ve done X, you can also do Y!”  Now, as an added layer, write a tracker for each event, tally the user’s currency, and design the award.

Gamification is the process of enlightening your users about how they can grow as users of your website.  If you have mild engagement (that is, the customer didn’t flee at the first sight of your home page), you have an opportunity to educate the user about what to do next.  You can do that with a Big Page Of Instructions, or you can do it incrementally, gradually, and with a sense of achievement.   The mechanics are easy.  So damn trivially easy I don’t see why VCs are giving third-party “gamification tracking” companies like Big Door and Bunch Ball millions of dollars.  The real trick to gamification is at the other end, at your website: your active customers know what’s epic and important about your website.  Do some analytics, figure out what your active customers already know, and then figure out how to lead new users down those same pathways in a gentle and entertaining way.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Oh, what a surprise!  Firefox implements the HTML5 “article” tag as display: inline, and Chrome implements it as display:block.

How annoying.  Well, it’s a simple CSS setting to make it work as expected.

(Edit: I see, as always, A List Apart is way ahead of me on this.  By almost a year!)

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Inspired by Five Web Files That Will Improve Your Website, I decided this morning to implement OpenSearch on the Indieflix Website. (It’s not up yet, we’re still beta’ing it, and it’s along with a massive list of changes that still need testing, so don’t go looking for it.) OpenSearch is a way to turn your site’s search feature into an RSS feed: you define for (other) search engines how and what you search on your site, and it automagically creates relationships so that your site’s search can be included in remote results. Normally, the results would be returned in an XML container for RSS or Atom, but HTML’s fine for some applications.

As a trivial example, I’m going to add your website’s search engine to Firefox’s drop-down of search engines. I’m going to assume that you already have a search engine enabled on Django. Haystack, or Djapian, or Merquery, or something along those lines.

First, you need a file called opensearch.xml. I put this into my template base directory:

Code behind cuts )

Obviously, there are things to modify here: your real short name, description, image and search paths.   You know where those go.

This goes into your base urls.py (if you haven’t imported direct_to_template, now is the right time):

More code behind the cut )

Again, if you changed the names or locations of the template, you have no one but yourself to blame if stuff blows up.   The name opensearch.xml is not particularly important or required, in either the template (obviously) or in the deployed URL.   To make external spiders and browsers know about your website, this goes into your base.html or site_base.html, somewhere in the headers with your metainformation and style sheets and so forth.

Final cut )

And that’s it.

To test this, load up your home page in Firefox, then click on the search bar’s drop-down. You should see your “short name” offered as a search plug-in. Select it and type some search terms, and Firefox will know to use your search engine, and the results will be from your site.

Pretty cool.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

As I’ve been working on a project at Indieflix, I’ve been evaluating other people’s code, including drop-ins, and for the past couple of days a pattern has emerged that, at first, bugged the hell out of me. Django has these lovely things called context processors– they allow you to attach specific elements of code to the request context before the router and page managers are invoked; the idea is that there are global needs you can attach to the context in which your request will ultimately be processed, and this context can be grown, organically, from prior contexts.

Nifty.  I kept noticing, however, an odd trend: programmers attaching potentially large querysets to the context.  Take, for example, the bookmarks app: it has a context processor that connects a user’s bookmarks to the context, so when time comes to process the request if the programmer wants the list of the user’s bookmarks, there it is.

It took me three days to realize that this is not wasteful.  It says so right there in the goddamn manual: QuerySets are lazy — the act of creating a QuerySet doesn’t involve any database activity. So building up the queryset doesn’t trigger a query until you actually need the first item of the queryset.  It just sits there, a placeholder for the request, until you invoke it in, say, a template.  Which means that you can attach all manner of readers to your contexts, and they won’t do a database hit or other I/O until you drop a for loop into a template somewhere. I’ve been avoiding this technique for no good reason.

This also means that pure “display this list and provide links to controlling pages, but provide no controls of your own” pages are pure templates that can be wrapped in generic views.

Ah!  And this is why I didn’t get why generic views were such a big deal.  Information is often so context sensitive so how could a generic view possibly be useful?  The examples in the book are all tied to modifying the local context in urls.py, but that’s not really where the action is.  The action is in the context processors, which are building that context.

I feel like Yoda’s about to walk in and say, “Good, but much to learn you still have, padawan.”

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

I recently implemented a new subsite for IndieFlix using LessCss, the Leaner CSS metaframework. LessCss is a programming language that abstracts CSS out into a hierarchal language, where instead of writing:

#header { ... }
#header img { ... }

You write:

#header {
    ...
    img { ... }
}

Which, believe me, makes a whole lot more sense. Even better, if you’re fond of the clearfix technique, then you’ll see why I fell in love with LessCSS. I had a long sidebar object, and I realized that I needed to make it clearfix to deal with some float issues. I had .clearfix { ... } defined already in my CSS, and I had my “.social-networks” class that I wanted clearfixed. LessCSS let me write:

.social-networks {
    .clearfix;
    ...
}

And it all worked the way I expected it to, without my having to clutter up the HTML with layout hacks.

Yes, this means that there are duplicates in the CSS LessCSS actually spits out, but that shouldn’t matter, any more than you care about bitsequence duplication in a large C++ program’s object code. I tend to look down on metaframeworks; my experience with using Ruby to write Scriptaculous code, or GWT, is that unless I want to jump through strange hoops I’m limited to expressing in Javascript only what can be expressed by the writers of the Ruby or Java-based framework.  This problem is made worse by the promise of not having to learn Javascript to be expressive in it.  I call shenanigans.   The win for using any framework has to seriously overwhelm the loss of expressiveness. I don’t bemoan losing the expressiveness of assembly language when I write in Python (although if I did have a problem that needed assembly language, I’d write in ASM, build a C wrapper, and compile the thing into a Python module… because I know all three of those languages*), and the only thing I lose using LessCSS is browser hackery, which I shouldn’t be doing anyway.

The containerization of cascades is such a clear win for me that I can’t imagine going back to doing CSS by hand. Well, I can, I just wouldn’t want to.

LessCSS does not carry your CSS comments from its source file to the CSS output, so it’s inappropriate if you need browser hacks that rely on poor comment parsers (I’m looking at you, Opera) or have alternative uses for comments in CSS (such as Wordpress’s style.css file does).


[*] Okay, I studied Motorola 68K assembly, which is a far cry from x86 assembly. Back in the 80’s, everyone “knew” the x86 chipset was junk and Motorola’s native multitasking cores were the future. Then Apple had to screw up using the multitasking features, Amiga and Atari blew it, Microsoft, IMB and Intel continued to chug along, and we’re left with the x86 series. This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Sharper FX

They do nothing but churches. Black churches, too. Sharper FX is an 11 on the scale of Manliness. Watch some of the Flash splash pages. They’re amazing. I love this site.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

A friend of mine pointed me to the website of CB Richard Ellis, a real-estate investment and management house with a big footprint here in the Pacific Northwest.

Their hiring website is a horror. No, really, go look, unless you’re an epileptic. (Sadly, the effect only seems to be present for Firefox users. Opera, Chrome, and IE6 didn’t show the evil.) Then go read The Federal Electronic and Information Technology Accessibility Standards, better known as “Section 508″, and document how they’re out of compliance. (Hint: Section 1194.21k).

I fully believe it’s possible to design very attractive websites that don’t violate Sec508. CBRE has failed on a galactic scale with this abomination.

If you’re not a Firefox user, here’s the horror: Every input button has this added to its CSS: text-decoration:blink;.

Yes, that’s right. Every input button is set to “blink.” I don’t know what’s worse: that the people who wrote their site thought that was cute, or that Firefox honors it.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

I had a job interview today, and one of the “challenges” with which I was presented was this: “We own several sites. We would like our user to be able to log into the central site as a subscriber, and then all the other sites will know what permissions that user has.”

The sites are cooperative, so getting content onto each one to support this idea isn’t difficult. Also, all of the sites belong to the same user, so getting a regular framework that you can deploy to all of them isn’t difficult either.

The scenario we want to support is this. We have two websites, the remote authentication server framework. Let’s call it “rasf.com” (which, sadly, does not go to rec.arts.sf.written), and let’s call the site that wants authentication “brandx.com.” (Sadly, this is a parked site that leads to a stock photography reseller.) The idea is that you’re a subscriber to rasf.com. You visit brandx.com, and Brand-X initially has no idea who you are. We want Brand-X to be able to say, “Hey, Rasf, who is this guy?” and have Rasf come back “Oh, he’s John Smith, he’s a legit user, and here are some details.”

The trick involves public key cryptography.  Both Rasf and Brand-X have public and private keys.  To understand the scenario, you must appreciate that much of the heavy lifting is done away from both sites on the browser.  The problem is that, on the browser, any windows opened between Rasf and Brand-X cannot communicate with each other; this is known as the sandbox, and it keeps malicious sites from using iframes or Ajax to either inject malware Javascript into the victim page or allow the nefarious iframe from ripping data (like username and password keystrokes) from the victim page.  We want to violate the sandbox, but how?

Assumption: You’ve visited Rasf recently, and have a cookie from Rasf saying “Yes, I, Joe Smith, and a valid user of Rasf and affiliated sites!”

You access a page from Brand-X.    Secretly, Brand-X creates a one-pixel-wide iframe and set the iframe’s src attribute to the “authenticate this user” page on Rasf, including in the request its public key as an argument.   After the iframe loads, the loaded page from Rasf now has the session information on the browser, and it has Brand-X’s public key.  The session information includes the Rasf cookie.    So now, Rasf knows two things: it knows who you are, and it knows that Brand-X wants to know who you are.

How does that who you are information get back to Brand-X?  Here’s where the cooperation comes from.  The iframe from Rasf, using the onload() event, creates yet another iframe, this time calling back to a specified page (the cross-domain receiver page) on Brand-X’s site, and that URL is loaded with your user ID, a cross-domain session key, and other information, all signed with the Rasf private key (so the Brand-X site can unpack with Rasf’s known public key).

Now, because both the containing page and the iframe two layers in are in the same domain, they’re in the same sandbox, and can communicate with one another via javascript.  The innermost iframe communicates with the cookies of the outermost page, the calls reload: all this information has now been pushed back to the Brand-X server, which can now use the signed cross-domain session key to make back-end requests of Rasf’s web services API and say, “Okay, now that I know he’s user 12345, and I have a session key validating this conversation, what else can you tell me about him?”

There are lots of other details here.  What if he’s not logged in to Rasf at all?  Well, enlarge the 1-pixel iframe to a size big enough to show a log-in within the Rasf domain, get his username and password, authenticate and proceed as before.

This is a generic description of what Facebook Connect does, and it’s how you can do it as well.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

While visiting with friends and family this weekend, I ran into a long-missed flame who said she was frustrated because she’d gone back to school to renew her web design business, last heard from about a decade ago, but the school seemed insistent about teaching her programming instead. Her head was full of PHP and Javascript, when what she really wanted to do was “draw pretty pictures” and hand them off to the developers.

Curious, and because I’m always looking out for good designers, I asked her what her design aesthestic was.  Did she like grunge or cleanOrganic textures or vectorsDark or light?  What did she think of grids?  How about Minimalism? Typography?

I’m afraid in my high-speed way I hit her with all of those questions in one long stream and she stared back at me like a deer in the headlights.  She’d never heard of any of these terms being used in conjunction with her current studies or practices.  Now, admittedly, these were terms from poster and illustration work back in 1999 that had only just begun the leap into web design practices.  When she jumped out I was working with flat, vector advertisement people who thought the height of design sensibility was the Taco Salad typeface (Ugh, totally hate that one now, even though it’s immortalized in a design I did in 1997 that will live forever and that I can’t take back).

I’m still much more of a developer than a designer, but I keep a daily zeitgeist feed of what’s hot in the design world, and I collect and keep tickler files, so when I’m in need of a new design, I can collect a few and when I hire a designer I can say, “I want a feminine design, slightly three-d (drop shadows are adequate, some pseudo-perspective boxes would rock), with a wine-purple background to suggest sensuality and mystery.  The objective has some infographic weight, so a stable grid would be a good idea.  Let’s talk information architecture and session flow.  I want something that’s a mash-up, not a compromise, between a website that sells porn and one that sells high-end cosmetics.  The background has to be IUI compatible.” Or, “I need an info-rich magazine layout for the adult story set, something way sexier than what’s currently out there, but with enough whitespace that each article can successfully compete with its neighbors for eyeballs based on content about the length of a double-tweet. I need a bumper-sticker-sized banner, with a solid typographic cascade, for the story of the hour. And I need some Section-508 compliance in the site, so high contrast is a must.” Or, “I need a web 2.0 throwback site for a low-end web app. A simple thing. Let’s do green and white, subtle gradients and high-contrast borders, unless you’ve got something burning that I can buy into.”

Being able to talk this way with designers is a plus for me, but it also lets me experiment on my own.  I know what I want.  I know what other developers are doing with it, and I can whip out the Wacom (or, better yet, colored pencil and paper) and just let myself explore the possibilities.  I’ve been hanging out with a bunch of web “creatives” recently, and this is the language they use.  The posters of their office space run the gamut from photorealism to grunge to flat OEM (original English manga) style, with same 60’s psychedelic for a wine-and-Shakespeare festival on the far wall.

I’m sure you can run a good sized web business without this knowledge base.  But you’ll look like these guys.  I’ve sent these guys my resume’ because, you know, that’s what I’m required to do under the circumstances.   But let’s face it, these guys need help: four separate flash items on the home page, bad 2003 swirly headers, no alt tags on the title images, table based layout, and no grid sensibility at all.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

So, I got tired of the way Django-SocialAuth was borked and not working for me, so I forked the project and have put up my own copy at GitHub.

There are three things I noticed about the project right away: First, it forces you to use a broken templating scheme. I haven’t fixed that, but in the meantime I’ve ripped out all of the base.html calls to keep them from conflicting with those of other applications you may have installed. Really, the templates involved have very little meat on them, especially for the login.html page. These are components that would have been better written as templatetags. Second, the project is rife with spelling errors. (The most famous, of course, being that the original checkout was misspelled “Djano”). I am a fan of the notion that a project with spelling problems probably has other problems. I’ll make allowances for someone for whom English is a second language, but I was not filled with confidence. And third, the project violates Facebook’s TOS by storing the user’s first and last name. Along the way I discovered that the Facebook layer was completely non-functional if you, like three million other Facebook users, had clicked “Keep me logged in,” which zeros out the “login expires” field from Facebook. It would never accept you because your expiration date would then always be January 1, 1970, effectively before “now.”

I’ve barely begun hacking on the beast, but already I’ve made some progress. Facebook now works the first time around. I’ve cleaned up much of the spelling and grammar in the documentation, such as it is, and I’ve clipped many of the template naming problems that I saw in my original use of the system. I’ve also revised setup.py so that it runs out of the box, although I’m tempted to go with a different plan, one like django-registration where it is your responsibility to cook up the templates for the provided views. And I’ve ripped out most of the Facebook specific stuff to replace it with calls to PyFacebook, which is now a dependency.

One thing I do want to get to is a middleware layer that interposes the right social authentication layer on those users who come in from the outside world: i.e. if the AuthMeta indicates you’re a facebook user, then request.user will be a lightweight proxy between you and Facebook for those fields that are, by definition, Facebook-only (and a violation of the TOS if you copy them). It might make more sense to have a decorator class, but only if you don’t have a gazillion views.

I haven’t gotten much further than a Facebook layer that satisfies my immediate needs. I haven’t had a need to branch out and explore the Twitter or Oauth components yet. What I needed at the moment was a simple authentication layer that allowed either local users (for testing purposes) or FacebookConnect users, and one that didn’t need to contact Facebook for absolutely every view, whether you wanted it or not, just to check “is this guy still a facebook user?”, which is how the DjangoFacebookConnect toolkit does things. I suppose, if you’re a Facebook app, that’s what you want, but I’m not writing a Facebook app, I’m writing an app that uses FacebookConnect to associate and authenticate my application users’s accounts via their Facebook accounts.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Parsing HTML with regex summons tainted souls into the realm of the living.

If you hack HTML for a living, this will make you giggle.  And given that I’ve used regex in my tests to assert the presence of classes and objects in a page, I guess I’m guilty.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Sigh.

I’ve just spent the last few hours wandering around the various “open source” analytics programs trying to find the exact right fit for what I want.  I’m not finding it, which means that (headache ahead) I may have to write something myself.  There’s a django-analytics placeholder in GoogleCode, but it’s empty.  I at least have a model!

Basically, I have a distributed subscriber/producer package, and I want to be able to present individual producers with analysis specific to their work.  Because the work is long-form text, I want to be able to tell the viewer that the reader scrolled every paragraph into view (no, really!) and actually read the work, not just scanned it.  Both of these are more or less beyond the province of Piwik, Google Analytics, or OWA.

Time to put the research aside and concentrate on finishing the product.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Today’s little snippet: Filtering a loosely coupled many-to-many relationship.  As revealed earlier,  I don’t really “get” the difficulty with many-to-many relationships.  I don’t even get the difficulty with signals; if you define the many-to-many manually, handling signals on it is trivial compared to trying to do it manually in one of the referring classes.

Today, I was working on an issues tracker.  There are two classes at work here, the Profile and the Issue.  One profile may be interested in many Issues, and obviously one Issue may be of interest to many Profiles.

This calls for a ProfileIssue table that stands independent (in my development paradigm) of both Profiles and Issues.   As I was working on a dashboard, I realized that one of the things I wanted was not just a list of the issues the profile was following, but also a list of the issues that the profile was responsible for creating.  As it turned out, adding that query to the ProfileIssueManager is trivial, but requires a little knowledge:

class ProfileIssueManager(models.Manager):
    def from_me(self, *args, **kwargs):
        return self.filter(issue__creator__id = self.core_filters['profile__id'])

The secret here in knowing about the core_filters attribute in the RelatedManager.   It contains the remote relationship key that you can use;  calling from_me from profiles works, but calling it from anywhere else doesn’t.  The IssueRelatedManager won’t have a profile_id and this will blow up.  That’s okay; using it that way is an error, and this is a strong example of Crash Early, Crash Often.

I can here some of you cry, “Now why, why would you need such a thing?” Well, the answer is pretty simple: templates. Having one of these allows me to write:

<p>Issues tracked: {{ profile.issues.count }}</p>
<p>Issues created: {{ profile.issues.from_me.count }}</p>

And everything will work correctly.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Repeat after me:

  • Registration is not Authentication is not Authorization is not Utilization.
  • Registration is not Authentication is not Authorization is not Utilization.
  • Registration is not Authentication is not Authorization is not Utilization.

I’ll keep reminding myself of that until I figure out how to disentangle the four from this damned Facebook app.  Registering to use the app is not the same thing as authenticating to use the app, and it’s definitely not authorization to determine your level access.  Nor is any of this related to callbacks to the social application network to give you things like lists of friends and writing on your wall; that’s outside the responsibility of SocialAuth anyway.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

If you’ve created Django Application A, and then Django Application B, it is acceptable (and even sometimes necessary) for Application B to reference Application A.  The canonical example is Django contrib.auth; everyone references that beast.  It is not acceptable for you to go and edit Application A to reference Application B.  That is officially Doin’ It Wrong.

In a smarter world, you will never use a Django ManyToMany field.  You will create an individual class referencing both objects of the many-to-many relationship.  You will inevitably need more smarts than a mere two-column table, and a separate class, however small and insignificant, will provide both self-documentation and a chance to define the __unicode__() method for administration. Django is smart enough to hook up the relationships under the hood.

Unit testing is goddamned hard when your application is married to FacebookConnect.  A smarter relationship uses the SocialAuth layer, with additional proxies for information and posting handlers.  That way, not only can your application send updates to Facebook walls, but it can also update its activity on Twitter, and allow authentication via Google, and so on.  By using the SocialAuth layer, you can create a pseudo-layer that handles testing.  You’re still beholding to testing the SocialAuth stuff yourself.

If you’re using SocialAuth, push all of your user-related smarts into the UserProfile object, and always refer to it.  Build your UserProfile object to own the proxy to the user’s authenticated relationships with social media.  After login, leave the user alone!  Better yet, use middleware to attach the profile to the request object automagically if and when it’s present, and live with it.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com

CSS Sprites

Sep. 6th, 2009 03:08 pm
elfs: (Default)

It seems like such a stupid thing, but hey, now I know how to use CSS sprites.

Basically, it’s the same idea as a viewport slider: treat your rectangular space as a viewport onto a background image. By using the background-position attribute and the .css() control (in jQuery; there are others in other libraries), you can move the background image around. If you have two different icons of the same dimensions, you can make the DIV (or whatever rectangle you want) the same size as one of them, and concatenate all of the images together (either left/right or top/bottom). The first image will show up in the DIV. When you want the other image to show up, set the background position to the negative (left or top) of the width or height (respectively), and it’ll slide your first image out of view and show the second one.

I discovered this when I saw that Firefox was making a round-trip every time I hit the end of a paginator, because it was fetching the “enabled”/”disabled” buttons that the previous programmer had built there. A round trip for every action? My gods, you’d better save that for state control, not special effects. Anyway, it’s working now, and no more “fetches from the database” to get even a 302 (item cached) transaction.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

One of the nifty things that Django provides is the
{% url backreference %} syntax, which allows
you to name the targets in your list of URL objects and then refer to
them by an explicit name. You can sometimes use the function name
instead, and Django has a way of turning the function name back into
the URL. It works fine as long as the signature of the backreference
and the signature of the function match.

It’s very nice for RESTful interfaces. But what about AJAXy webpages?
AJAX is all about D(X)HTML and the rendering and animation of user
interfaces in a broser, and there’s a lot of Javascript that comes
along with all that HTML and CSS. And embedded AJAX often comes with
its own set of URL calls. I mean, seriously, what if you want to write
something like this:

<example.js>=
$.getJSON(
"{% url results %}", {},
   function(resp) {
   $("#resultswrapper").html(resp.results);
});

Here, I want to replace the string “url results” with the url
that returns the results and shoves their visuals into the
“resultswrapper” HTML object, whatever it is.

You could do this in Django, making this a templatized object
and spewing it out every time. But often enough this URL
never changes during the lifetime of the program. This is
effectively javascript with a macro embedded in it that you want
substituted once, preferably at start-up. Well, I haven’t done the
start-up for you. But here’s a nifty little chunk of code that’ll do
URL reverse lookups in any static files in
your STATIC_DOC_ROOT directory (by the way, that
STATIC_DOC_ROOT setting is pretty useful for development, if you’re
serving static media out of your Django server, as devs frequently
do):

<addition to settings.py>=
import os
DIRNAME = os.path.normpath(os.path.dirname(__file__))
STATIC_DOC_ROOT = os.path.normpath(os.path.join(DIRNAME, 'static')) + '/'

And here’s the routine. Note that I’ve made it a Django command:
put it wherever you want and use it wisely:

<rendertemplates.py>=
from django.core.management.base import NoArgsCommand
from django.core.management.base import CommandError

from settings import STATIC_DOC_ROOT
from django.template import Template
from django.core.urlresolvers import reverse

import os
import os.path
import re

re_walker = re.compile(r'\.tmpl$')

class Command(NoArgsCommand):
    help = ("Run a series of templates through the Template handler to produce "
            "(semi) static files.  This is mostly useful for javascript "
            "handlers with Ajax calls in them that only need the urls "
            "defined when the application is first built or starts running.  It "
            "allows developers to use the {% url somethingorother %} syntax inside "
            "Ajax handlers without burdening the application at runtime.")

    def handle_noargs(self, **options):
        paths = [os.path.join(STATIC_DOC_ROOT, path[0], filename)
                 for path in os.walk(STATIC_DOC_ROOT)
                 for filename in path[2]
                 if re_walker.search(filename)]

        for fn in paths:
            fn_out = re_walker.sub('', fn)
            open(fn_out, 'w+').write(Template(open(fn, 'r').read()).render({}))

It’s not perfect (hey, I wrote it in about 20 minutes, mostly to
fix this problem in a quick and dirty fashion. Given that I didn’t
know how the innards of the Template class worked, and have never used
the new os.walk() function, this was pretty good.

As always, I’ve provided the source code for this.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

One thing I see a lot of in professional Django is the importation of ugettext, Django’s internationalization library that leverages the GNU gettext project’s toolkit for generating translation catalogs. Laying the groundwork for translation is important to larger projects intended for universal appeal. Because the underscore is a valid leading character in a function name in both C and Python, it’s also a valid function name in its own right, and gettext recognizes that single function, _(), as the wrapper for a string to be recorded in the translation catalog, and for that string to be the “key” for translations into other languanges.

However, it gets a little old, after a while, typing in the same “import-as” string in module after module. So I decided, to heck with it, I’m just going to make the gettext function (or in Django’s case, ugettext) absolutely everywhere:

<__init.py__>=
from django.utils.translation import ugettext
import __builtin__
__builtin__.__dict__['_'] = ugettext

Put this into the __init.py__ file in the root of your project (the same directory level as urls.py and settings.py) and this installs _() as a global reference into the current running python VM, and now it’s as universally available as int(), map(), or str().

This is, of course, controversial.  Modifying the python global namespace to add a function can be considered maintenance-hostile.  But the gettext feature is so universal– at least to me– that __init__.py is where it belongs.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

So, remember my comment about unit testing yesterday?  This is what it looks like today. Here’s the features page:

Feature: Login
  In order to use the system
  As a customer
  I want to log in

  Scenario: Access page
    Given I am at the login page
    Then the page title should be "SecretProject"

  Scenario: Log in
    When I log in as "username" password "redacted"
    Then the page title should be "SecretProject - Project List"

And here’s the steps:

Given 'I am at the login page' do
  @browser.goto @options[:address]
end

Then /the page title should be "(.*)"/ do |title|
  @browser.title.should == title
end

When /^I log in as "([^\"]*)" password "([^\"]*)"$/ do |arg1, arg2|
  @browser.text_field(:name, 'username').set(arg1)
  @browser.text_field(:name, 'password').set(arg2)
  @browser.button(:xpath, "//input[@value='Login']").click
end

While I’m not entirely sold on the COBOL-esque nature of the unit tests, I respect the way cucumber makes you think about what you’re doing and generate scenarios and codify the steps to fulfilling those scenarios, all the while working well within the context of things like WATIR, Matchy, and so forth.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com

Profile

elfs: (Default)
Elf Sternberg

August 2025

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 17th, 2025 02:02 am
Powered by Dreamwidth Studios