We Do This Every Day

So it's been a while. In my defense, I have a good excuse (of which more later). I am returning from blog hiatus to grouse about something: I subscribe to Hacker News in Twitter and I'm happy to do so as I regularly find new packages and good advice in the stream. The price one pays for these tidbits is having to suffer through the worst examples of tech nerdism alive in the world today. Allow me, if you will, two examples:

Life on the Command Line

I'm forever trying to make myself more efficient through keyboard shortcuts, so I clicked right on this trap. After three or so sentences I recoiled in horror. Instead of being advice on how to use the command line, it's all about how the author hates graphical email clients, so he uses old-school Linux ones because they are far superior. I see two problems here.

  1. I do not claim Gmail is perfect, but it works damned well. Before it, I lived my professional life in Outlook. And that was fine too. I've used Thunderbird and had no major complaints. I've also used pine and mutt and written email by hand. Those are not superior ways of doing things. The specific mistake the author makes is in claiming terminal-based apps are superior because you get your email "faster" according to whatever observation-based metric he's made up. Email is a wonderful means of communication because it is asymmetric: you write to me when it's convenient for you and I read it when it's convenient for me. If you're sitting around hitting "Check for messages", you're doing it wrong.
  2. The more general mistake this type of nerd makes is that computer programs are an end to themselves. They are not. Carve it into your forehead backwards if need be, but unless you are currently taking Computer Science classes or writing a programming language, it is unlikely you are writing a program that doesn't have a purpose outside the confines of the machine it runs on. An email client isn't just for you, it's for everyone who needs to communicate with you. So I need you to be able to respond in nicely-formatted language that clearly indicates what you meant, not some plain text crud wrapped at 80 columns. And I need you to have an email client that can handle calendar events so I know if you're going to show up or not.
  3. My all-time, can't-be-beat favorite example of this kind of crawling up one's own ass comes from my all-time, can't-be-beat favorite co-worker. When we moved to .NET, everyone got a copy of Visual Studio. Now you can make a lot of complaints about a lot of Microsoft programs (and I can help if you want to set up regular meetings), but I am hard-pressed to complain about Visual Studio as a work environment for creating Microsoft-based code1. Not good enough for The Professor though. Too complicated. His idea was to write his code in Notepad and then run it through the raw compiler on the command line (sense a theme here?) and then hand it over to us. Technical types reading this will need no further info before they begin laughing; for anyone else in the audience, this is the equivalent of your new employer handing over a set of keys to a Rolls Royce by way of apology for the commute and you refusing them, saying you prefer to walk 5 hours each way and then to prove it, cutting off your own legs at the knee with a rusty hacksaw. One could write the code in Notepad if that made them happy. It does have the side effect of pissing off all your coworkers who have to clean up the mess though.

    The Big Re-Write

    I've lost the second link, but it was a story from some wet-behind-the-ears kid about "Why I rewrote my company's code base and you should too." I won't claim it couldn't be true; from the link I think he said he did it in three days, so it sounds a bit like someone saying they rebuilt their entire house from the studs and then finding out their house was a refrigerator box and is now pieces of the same box taped up in a slightly different configuration. It's perfectly possible it was a good idea. But if you're the sort of person who thinks they can discerns a trend line based on a single data point, maybe you shouldn't be handing out free advice. Especially when it's rather dangerous advice. It's such a bad idea, a mistake so many people have made, it has its own name ("Second system effect") and an entry on Wikipedia.

    I am regularly stunned by the number of people who think they have everything covered. As a kid, I always noticed the guys my Dad chose to hang around seemed impossibly competent2. Good with their hands, good with numbers, all-around friendly, you get the drift. The best description I can provide is one stolen from Neal Stephenson's Wired article about the laying of a trans-Pacific Intenret cable:

    "They tend to come from the US or the British Commonwealth countries but spend very little time living there. They are cheerful and outgoing, rudely humorous, and frequently have long-term marriages to adaptable wives. They tend to be absolutely straight shooters even when they are talking to a hacker tourist about whom they know nothing. Their openness would probably be career suicide in the atmosphere of Byzantine court-eunuch intrigue that is public life in the United States today. On the other hand, if I had an unlimited amount of money and woke up tomorrow morning with a burning desire to see a 2,000-hole golf course erected on the surface of Mars, I would probably call men like Daily and Wall, do a handshake deal with them, send them a blank check, and not worry about it."

    I've worked as a programmer for over a decade and I've worked with perhaps two people like that. Which feels about right to me— I've worked with a lot of programmers and a lot of good programmers, but people who you'd bet your life on— those should be rare. If they're not, you're awfully careless with your life. My frustration with this comes from our new venture3, Rivermill at Dover Landing. Just about every single vendor in the wedding industry thinks they are one of these people; some old ballplayer in Ken Burns' Baseball was quoted as saying "We do this every day" and I can't think of a better label for the condition. Some of them clearly are. But they're easily-identifiable behind the scenes, if not via their common competentness then through the higher price on their invoices. The trick is, if you're not behind the scenes, they'd be hard to spot, because you can't be casual in this business. This is someone's goddamn wedding day. I know you and I do this every weekend, but you still need to stand at attention and look like you're about to break into a sweat.

    We had a pair of wedding "planners" who apparently worked together so there was always someone to explain why the other wasn't doing anything. We spent the better part of a week making these mopes look good because we don't have a choice: if any vendor screws up, it reflects badly on us. And even if the client understands, random guests can't tell things were off-schedule or messed up because of a vendor. So in the midst of us hurrying around to paint over their mistakes, in walks the mother-of-the-bride and she's freaking out. Which is entirely expected and entirely understandable: you're throwing probably the most important party of your life except you aren't exactly in charge: if it were your party, you'd know implicitly where you want the tables to be, what color linens should be where or what the first dance song is. Since it's not your party, you need to have that all written down beforehand, assuming you think to ask. Alternatively, you could hire a wedding planner. So she's freaking out and trying to get some answers out of the planners. Their answer? "Relax, have a drink. It will all be fine." These vendors "do this every day". The problem is, they all have their own internal definition of what "this" entails and you only find out after the fact.

    [1] I'm not claiming it works well for anything else. I don't write anything but C#/ VB.NET (God help me) in it. But before you complain, go try Eclipse.
    [2] Compare and contrast with the men who we knew by happenstance: my Dad once spent 5 minutes trying to help our neighbor get his lawn mower started because it never even occurred to my Dad someone would begin yanking on the pull start of an engine before checking to see if there was a single drop of oil in it.
    [3] Which has basically sucked up all my nights and weekends and thus all of my blog-writing free time. Or at least that's my excuse.

Catharsis: To a Young Designer

"To be young (is to be sad)." Ryan Adams

Dear Designer,

You don't know me and I don't know you, which is why I'm posting this here where you won't see it instead of replying to your email with an eye-peeling rant. You are the second young designer in two months to tell me you work in Illustrator, not Photoshop. And you compounded the sin by informing us you do know Photoshop is the industry standard. It's one thing to be ignorant, but to happily announce your intentions to be uncooperative is not a recipe for success. Please warn me next time you're going to write something like that; I got angry enough I was light-headed[1], which is why I had to write this.

There's no gentle way to explain the problem here, so let me just say it: you are stupid. You don't know anything. Whether a designer or a coder, the classes you took in college didn't prepare you for much. That senior project you slaved over, even if it weren't laughably wrong-headed, represents about 1% of the work involved in a real project. If you ran into a dark corner on your senior project, something you couldn't figure out how to do, you just changed the project. Can't happen in the real world. Instead you rely on the advice of people around you who have gone through the process before.

I am a firm believer in Thoreau's maxim, "Grey hair does not confer wisdom." However, there is no implied corollary that youth does. It would be one thing if you were using GIMP instead of Photoshop; not only could I understand doing so to save money, but it would be evidence you've done some investigating to see what options are out there besides the ones you know. It would suggest an open mind instead of someone who assumes they already know what they need to know. And the solution to your anti-Photoshop bias is not to write the HTML yourself. I've seen your HTML. It sucks even worse. Learn how to do one job properly before you decide to add another bs title to your email signature. Accept it takes time to learn a craft. We are all standing on the shoulders of those who did our job before us.

Stop looking at every step in the process as a problem that needs solving. The steps in the process are in the process because they are solutions. Twice since I've gone out on my own I've run into problems with a young developer who had "a different approach" to the version control system we were using. Thing is, there's an industry standard for how to use Subversion. And I know what it is. Know how? Because the people who made Subversion wrote a book about it and made the book available to anyone who can use Google. And I played around with different setups until I realized they were right. When you work on anything, with anyone, use the industry standards. Whether perfect or not, standards make sure everyone is speaking the same language. They reduce friction. If you're not sure what the standard is, just ask me and I'll tell you. It's like it said in my wedding vows, "From now on, I'll do the thinking for both of us."[2]

I don't care if you work in Illustrator. And I don't care why, though I must say if you find it hard to place a 1 pixel line in Photoshop, the problem might not be Photoshop. Work in whatever the hell you want and then Google "convert from [my stupid choice] to PSD". Another reason I'd be ok with you using GIMP: it exports directly to Photoshop. It has to. Because, in the realm of image editors, it is no one. So it has to be cooperative or no one will work with it. That should be your role model. Be T.S. Eliot's "infinitely gentle/ Infinitely suffering thing". Don't talk, listen. When you get to the point where people are knocking on your door to give you work, then you can be e.e. cummings Olaf, saying, "There is some shit I will not eat".

But you won't. Because in five years, you'll realize how stupid you were now. And in ten you'll realize you're still learning. In fact, set a reminder for ten years and if you don't feel this way, you have a Very Serious Problem. You've become one of those old people who isn't worth listening to.

A couple of other free pieces of advice:

  • Tattoo this on your arm: "The perfect is the enemy of the good." Fail fast. There's no shame in not succeeding the first time. Writing is easy, re-writing is hard. No work is ever perfect, so if you keep tweaking until it's perfect, you'll never finish and no one will ever see your work.
  • This isn't a goddamn competition to see who's smarter, so please don't refer to your boyfriend the HTML whiz while telling the client how I should be doing my job. You aren't even bright enough to do your own job, so why not assume there's a reason I did things the way I did? Also, don't bad-mouth the people I work with as a way of trying to get me to send you work instead. That makes it clear we're not in this foxhole together and you'll do the same to me as soon as it looks profitable.

1. Given you don't know me, I feel the need to point out this isn't hyperbole. I almost blacked out in my car thinking about your email.
2. Clancy, Thomas, "Weddings Vows" (first draft only), 2005, as yet unpublished


Week 162

"[T]he advantage to being a wicked bastard is that everyone pesters the Lord on your behalf; if the volume of prayers from my saintly enemies means anything, I'll be saved when the Archbishop of Canterbury is damned. It's a comforting thought."
Flashman, Flashman at the Charge

And the advantage in taking 20 weeks off is I still have a Flashman quotation left laying around to use. What have I been up to? Not much:

  • 3 new Django content management sites
  • A Django social network for an episode of PBS' Frontline, God in America
  • An ecommerce site powered by Satchmo
  • My first Microsoft MVC2 Project (another big social network, done under NDA)

August was a rough month. After a slow July, the Satchmo site and the .NET site were competing for all of my attention, made worse by the fact each project was a learning experience for me. Forced to work in a Windows environment, I would happily work with MVC2 again. I'm spoiled by Django and I have reservations about the amount of ecosphere .NET projects drag around with them, but it's a huge improvement over a WebForms site. I'll never get over my objections to magic happening in compiled files somewhere on a machine (I want to be able to open a text file and see what's going wrong if there's a problem), so .NET will never be my first choice solution. My mind is also bent by Django since it's the first MVC framework I really worked with and because it is the one I know best (I'm just starting to learn CakePHP while working with Croogo, which seems like a nice lightweight PHP CMS solution), so some of the issues I have with MVC2 are just a case of expecting things to work a different way. But there are some design decisions I disagree with:

  • I'll start with the big one: I'm not a huge believer in Controllers for web apps. There's a new Python framework whose name I've forgotten two days later that describes itself as an MV framework, which basically describes Django as well. I can see putting security logic in controllers (that's what I did when I rolled my own for .NET way back when), but given the amount of security and sanity-checking a routing engine gives you to begin with, I don't think it's a lot of overhead to put into the views. Actually, that's not true. If you need to write the same security logic into multiple views, that's not good. But Django's use of decorators works for me. MVC2's controller attributes serve pretty much the same function, just in the controllers. Which brings me to the next issue . . .
  • Django, Rails and most other MVC frameworks intentionally make it difficult to put logic into the presentation layer. Because MVC2 just uses .aspx pages as the View layer, it allows people to re-invent WebForms.
  • My personal opinion is that everything about a model belongs in the model. This was my one fundamental disagreement with Django's design up until the last release. Until 1.2, some validation had to be done in forms. Forms are just a way of interacting with a model, but there's no contract to use a particular form. You could build a dozen different forms for a model or not use a form at all, which means there was no single location for business logic. Where Django made it hard to centralize rules for a model, it's just about impossible in MVC2. Logic goes in the Controller, not the Model. There's no way (that I could fine, I could be totally wrong) to hook into a Save event or similar. And things get further confused with the Repository Model and View Model concepts, where you build "models" as a data access layer and as a convenience object for strongly binding a view to an object. It feels wrong-headed to me.
  • The build process still feels horribly complex for .NET projects. It typically consists of a batch file tied to one or more large XML files describing the different deployment locations. It runs a build, moves stuff around and then you manually drag and drop the files and diff the folders because of course no Windows server admin dares to have FTP open anymore and you're not going to get SFTP access either. And then maybe you need to restart IIS, maybe you don't. In comparison to the Nant build scripts I'm used to, my Fabric deployment files for Django projects look like the slow kid in class: a dozen lines top, another 5 or so if I have a second deployment location.
  • I've finally wrapped my thick head around using South for migrations in Django. If there's something similar for MVC2 projects, please let me know.

As for Satchmo, I don't know if I'd use it again. I had heard it, for better and for worse, included everything plus two kitchen sinks. I went with it because I figured if I got over my head, the amount of options and sizable user community could save me. They did, but it still felt like an elephant gun solution and it was harder than I expected to customize it. Actually, that's not fair: once I learned my way around, it was pretty easy to customize, but all that work happened in uncharted territory. While it has decent documentation, the documentation is written for people who just want to set a site up, tweak some settings in the admin and be ready to go. While you can add/ customize all sorts of things, you're on your own for much of it. All of which suggests I ought to donate some time back to the project in the form of documentation. I guess I would use it again given it can do most anything, provides a lot straight out of the box and gave me a feeling of security you don't get from hand-rolling your own credit card processing logic. I'll just keep an eye open for other Django ecommerce solutions like LFS. And I've heard good things from people using Shopify.

While those two projects dragged on into September, the Frontline site launched. It's a testament to Django (with some help from django-db-log— now replaced by the more attractive but also more confusing Sentry) that the launch went so smoothly. It's a different experience, knowing that after 10pm on a given night, thousands of people are going to hit your newly-launched site. A small number of edge cases issues cropped up, but it's reassuring to have fixed and deployed a patch before I get an email from the client about the issue. The only real issue I ran into was a performance problem on the directory listing pages: because one of the sorting options is by views (and the default option at that), the query was running incredibly slowly and forced me to denormalize the view data from a separate table (the views are in a separate table so I could track who viewed a profile and when) into the profiles table itself. Once that was done (and once I added a bit of template caching to the page), the problem disappeared.

Totally (almost) unrelated to work, one music note from my missing months: we caught the Paste Tour at The Middle East in Boston. This came up in a discussion last night when someone told us they'd recentl seen Sufjan Stevens in concert. If you know me at all, you should be proud: I didn't get up and walk away, I didn't spit out my drink (not that I'd ever spit beer in general or Boddington's in specific). Instead I was just a jerk and asked if Sufjan played his 25 minute new album closer that features costume changes during the song (don't look at me like that, I heard it on an episode of the otherwise-fantastic Musicheads podcast)? The answer: yes he did and it was awesome. There was confetti and white people going as crazy as people who attend Sufjan Stevens shows are capable of going. Which, one imagines, isn't very far at all but still requires an expensive therapist to sort out the ennui afterwards.

No thanks. We walked into The Middle East late due to traffic and a restaurant who thought the slow food movement should be extended to the table service and walked directly into a screaming match between Jesse Sykes' guitarist Phil Wandscher (late of Whiskeytown) and one or more patrons who were standing in directly in front of the stage and texting. That segued into a typically raucous set from Langhorne Slim; if he gets near your town, go see him— it might have been the 'Gansett tallboys talking, but Michelle asked me how likely it was she could land him for next year's Cochecho Arts Festival, so he might be closer than you think.

So that was all dark and boozy and ceilings so low Langhorne Slim nearly decapitated himself jumping off drums and amps. And then Jason Isbell showed up and here comes my point along with him: he was a complete mess. I saw his eyes as he walked out from backstage and got a little nervous: while Michelle tolerates the Drive-By Truckers for me, she loves Jason Isbell. And here he came looking like he was going to fall off the stage. And then he ripped off an hour plus set that might be the best show I've ever seen. My eyes have looked like his any number of times. None of those times have I had the hand-eye coordination to unlock a door on the first try. Somehow he played the best guitar I've ever witnessed close up. I suppose it's like getting to Carnegie Hall, "Practice man, practice". I can't see Sufjan Stevens, Animal Collective or Soul Collective ever letting themselves free like that. For me, music, art in general, should be about Dionysus, not Apollo: let yourself go. Free your ass, etc., etc. It pains me to be at a show and see someone doing that White Guy Dance where he's kinda shaking his ass, but his elbows are welded to his hips for fear of annoying other patrons or (God forbid! Heaven forfend!) ever looking a little goofy. You see those "Dance Like No One is Looking" bumper stickers on plenty of Volvos, but I never see the drivers doing it.

Week 142

"That tension— between beauty and cynicism, between what the Brazilians call futebol d'arte and futebol de resultades— is a constant, perhaps because it is so fundamental, not merely to sport, but also to life: to win, or to play the game well? It is hard to think of any significant actions that are not in some way a negotiation between the two extremes of pragmatism and idealism."
Jonathan Wilson, Inverting the Pyramid

This was supposed to be "Week 138", but I never got off my duff. It's just as well as I read Flashman and the Dragon in the interim and it colored my thoughts on this post. I want to clarify and expand upon what I said in the last post about the danger of falling too much in love with one language, one web technology. Some of that is just my personal bias: I spent my formative development years working at a consultancy that took on work in all manner of languages and on any number of platforms, so I think that's How Things Should Be. I've always prided myself on being "language agnostic" in terms of programming. A few times on a job interview or when trying to land a client I think this has cost me— you see a wrinkled nose or the torrent of questions turns into a trickle— but I've never really minded because I think insistence on working in one way is the path of the small-minded. It's something I rail against in general, the tendency for everyone to think where they live, how they live and what they think is based on some cosmic template of How Things Are Done and anyone who's opinions, skin color, language differ from that template is doing it wrong.

That kind of thing infects your thought. If I were designing a curriculum for a school, it would include a week discussing Kipling's "[W]hat should they know of England who only England know?" A week at the inside. Make it the basis of a year's worth of forming thought. Too many developers focus on one thing, get comfortable in it and then don't know what to do when that technology turns into a dead end. Or, worst of all, don't ever find out that technology has turned into a dead end. There's nothing more frightening than meeting a new client's old developer via his work. "He has his own way of doing things." "He was very specific about that." Etc. If you don't think there are people making a good living writing dead-end solutions for clients who don't know better, find out how many copies of Microsoft Access were sold last year. Ask why people are still looking for VB6 compilers ("I don't like to upgrade [to] 2008. More than 10.000 lines of code")?

So what the hell am I doing trying to work in Django all the time? First we should discuss the lie I told above. I'm not language agnostic. Not exactly. I try not to be a fan of anything, but that's not in my nature anyway: I expect to be let down by anything I rely on. But I don't stop myself from hating. This week, a partner asked me if I knew any ColdFusion consultants. My thought process:

  1. Why would I hang around with a sorry bastard like that?
  2. Hey, I've written thousands of lines of ColdFusion!
  3. Yeah, and you hated every second of it.
  4. Oh, right.

No thanks. It's one of the few languages I've worked in that I feel sets you back (note: all opinions circa 2002 and CF4/5). Like ASP, its limitations make you think programming has to be hard and that there are things that cannot be done. It never fails to amaze me when a developer says something "cannot be done". It's almost never accurate. 99% of the time it either means it can't be done in budget or the developer does not know how to. And that second case is when you should drop a developer post-haste. I've rarely done anything interesting as a programmer when I knew how to do it at the outset. You only learn and grow when you get challenged.

So, again, why work so much in Django where you can develop a comfortable rut and never be challenged by ideas and paradigms from other languages that might show a better way to do things? So much of life comes back to biology, and working in one language is incestuous. Healthy populations have lots of differences, providing more opportunities for mutations and evolution. I could hang out with the world's smartest Python programmers and all I would ever learn is the best way to solve problems in Python. Which is not necessarily the best way to solve a problem. Going back to Kipling, it's hard to appreciate what you have if you don't know what the alternatives look like. It's human nature to assume what you have is the best option. My favorite Americans, the people who I think are our best citizens, were citizens of the world. Franklin, Jefferson, etc. were Americans intimately familiar with England, who spent much of their diplomatic lives in France. The synthesis of different ideas results in totally new avenues. Even just the ability to synthesize different ideas is important.

The answer turns out to be a surprising one: I, and by extension, this company, am not a programmer. It's what I do to accomplish client goals, but it's not what clients want. They want a solution to a problem. Ideally a secure, high-performance, user-friendly solution, but in no case do they care about the language it's written in or the format of the code. They just want something that leaves them happier than they were before. All that stuff developers argue about, languages, platforms, editors, it's all fanboyism. I'm too old for that and I'm more interested in accomplishing something than being right. Or I'm trying to be.


Week 137

Not a whole lot to report. There is, I suppose, but it's too damn nice of a day to spend it reading (or writing) this stuff. I'm dangerously close to finishing a site for PBS' Frontline after a week-long crunch. It's been yet another experience that's re-affirmed my love for Django. It's to the point where I can take on (literally) twice as much work as I could before Django and the scary thing is that I'm just getting comfortable with it and each project exposes me to at least one new package that makes things easier. For instance, I really wish I'd known about PyFacebook a couple of projects ago. It would have made things a lot easier (especially if I'd coupled it with django-socialregistration).

The downside to my love affair with Django is it gets really easy to become picky, to insist on only taking projects that can be done in Django. The next step is to try to force each project into the shape of previous projects; the whole reason I gave up on CMSes in favor of a framework like Django was to avoid cramming a client's square peg into a round hole (dirty!). Always working in the same language and framework is a ghetto: you only know what you know and you don't get exposed to new ideas.

So I've ripped through another Django project and have picked up a new one this week as well. And yet, given my chronic case of Irish Alzheimer's, I'm down in the mouth because this week also saw the death of a project. Not death exactly, but it's being shipped off to India to apply the final touches. Whether that's death or CPR depends entirely on who gets a hold of it, but I'm guessing the project would have a hell of a time getting term life insurance right now. It's only the second project I've had go south in the 2-and-a-half years I've been out on my own, but it still sucks. In each case I came in after the contract had been agreed on and after (what would have been) the requirements gathering period had ended. I'd call it a clear lesson learned except it's one I learned a long time ago and keep screwing up because I assume I can punch my way out of anything. I need to spend less time improving my code and more time improving my ability to communicate the value of up-front requirements gathering and a process "agile" enough (whatever that means) to get regular feedback from the client on how things currently look.

Totally unrelated to any of this, but I did run into an interesting usability issue while we were on vacation in Maine. Though it may be silly to generalize about a state's drivers, I will still assert Maine's drivers are far more law-abiding than their New Hampshire counterparts. So I was surprised to see how they lay out passing lanes in Maine: like a challenge to your manhood. The first couple I shrugged off as mistakes, but after a day or two I could not get over how many passing lanes didn't end until you were just about up to a curve or hill that obstructed your view. I finally figured it out at the end of our trip: Maine assumes the best in its residents and visitors. Passing lanes end at the last possible second it's safe to pull back in. New Hampshire knows their residents are crazy. Passing lanes end at the last inch you could possibly pull out at and pass someone assuming you're on a motorcycle and passing a rickshaw. It'd be nice if Maine added one more sign to the Burma Shave-esque laundry list of warnings they have when passing from New Hampshire into Vacationland. Or just replace them all with "Welcome to Maine: Don't Do It, Brutha".


django-avatar and Pinax Configuration

Noting this here for the sanity of my future self. When using django-avatar (which is included in Pinax), you need to add at least one of the avatar settings, AVATAR_STORAGE_DIR, to your settings.py file. The important thing to note is this needs to be a relative path to a folder under your MEDIA_ROOT as the path will be used both to create a file system path and to build the urls when serving the avatar images.

For local development, I had trouble getting the avatars (or anything under /media) to appear. The patterns in Pinax's staticfiles.urls include one for everything under /media, but not only didn't I see files under that folder, the server didn't even attempt to serve them. I tried explicitly putting the pattern into my main urls.py at the top of the list, but nothing changed. As a fix, I changed my local MEDIA_URL to '/includes/' and added that pattern to my urls.py, which fixed things. The production server should not be affected since the files won't be served by Django.

Tags: , ,

Week 134

"It ain't always easy, if your knees knock as hard as mine, but you must remember the golden rule: when the game's going against you, stay calm— and cheat."
Flashman at the Charge

Heard from an old client and met with a (potential) new one this week. Though both New England-based service companies of comparable size, they're from two different eras. Due to dropping margins in their current business, the existing client is moving into a new, tangentially-related one. Before building a new site, they wanted me to do some search engine research. I've been working in SEO since around the time they coined the term and it's never been satisfying. Some of it's just my personality: I like coming back to clients with finished work, with correct answers. SEO resists that. No matter how the algorithms change, it's always going to be an art[1]. The client's new industry is a competitive one. Until they've established themselves, search engines are going to be an opponent, not a help. We've come up with a list of keywords and a strategy for using those words and getting linked to by their partners and other industry sites, but that's about all that can be done on my end. I could do a lot more busywork and generate a lot of documentation, but that's the dark art part of SEO. Without relevant content that interests people enough to link to it, you're chasing the keyword market (through bought AdWords) rather than creating it. My advice to the client is the same easy (for me) advice I always provide: from the terms you gave me, here are the words people actually search for. Put those in your content. And then keep creating new content on a regular basis (blog). Create it with a consistent voice and create it because the content is worth knowing.

The new client also feels their chosen industry is contracting. Rather than branching out, they've decided to reposition. The Internet made their business a lot easier; reduced costs led to higher margins. For a while. But like nature abhors a vacuum, the economy always destroys an arbitrage. The efficiencies introduced by the 'net brought much larger companies into the industry on a national level. The client cannot compete at their price point. They could, but it'd be a short competition given the negative margins they'd suffer.

So they have to change their model. In any service industry, you can be a boutique. There are some people out there so good at what they do they can make it on word of mouth, but it's a pretty risky bet to assume you're that good[2]. The client's idea is to become a resource. A lot of people pay lip-service to this idea, but it's nice to see a client come up with the idea on their own and be committed to it. I enjoyed it all the more because it was disconcerting: they're a small shop hidden in New Hampshire and the client's old enough (ageism alert!) it was unexpected. Survival's a powerful motivator.

I'm sure every region of the country (and every country in the world) has them, but I've only known New England and I think this region runs on people hidden in the woods who know what they're doing. I once went on a business trip with my Dad when I was still in high school. We wound up down a dirt road in Rhode Island in front of a couple of old Quonset huts representing the sum total of a metal fabrication shop. Out walks a heavyset guy in his 60s with a bushy beard full of tobacco spit off the unlit cigar that never left his mouth. But inside one of those huts was a CAD program driving a plasma cutter. This was 1992 at the latest: it'd be like walking into your neighborhood auto parts store and finding wings for flying cars. Little ahead of his time. It's nearly two decades later (God help me) and there are still people in his business not that technically advanced.

Guys (sexism alert!) like that always survive. They don't thrive: they refuse (or are uncomfortable) marketing themselves and to grow past a certain size they'd have to overcome the cultural barrier of dealing with bankers from a city. Maybe put on a suit. Which means there's room in the industry. Between giant (multi-)national companies and brilliant Yankees in the woods, there's room for people who, regardless of how good they are at what they do, are decent at marketing themselves. If you don't go with the giant in the industry and you don't know about the boutique, you wind up with whomever you can find. Which is why spam works and why you have to pay $100 to get a poster framed in your town. The Internet's flattening those things out. It's abstracting marketing out of industries: killing trade magazines, newspaper classifieds, anything that made money by holding onto information. I don't know what it will mean when it's easy to find the boutiquess and the ass-kickers for whatever job needs doing, but it can't hurt to be a resource in your industry. Give away the knowledge and show you can do the job.

1. "art" in either the loosest sense of the word or when the best people in the industry do it. Most of it's a lot worse than art and some of it is pure snake oil.
2. "Hello Kettle, this is Pot. Can you hear me?"


Any Interest in the 700-page Abridged Version?


Me: We've still got the frying pan to clean.
Michelle: I always forget that.
Me: I know, it's on my list of complaints about you.
Michelle (unimpressed): Really?
Me: See chapter 3, "Domestic Disappointments".


Week 133

"[T]here's something splendid waiting for you to go and find it, far out yonder. I wonder if I'd feel it now, or if it happens only when you're young, and have no thought for the ill things that may lie along the way."
Flashman, Flashman and the Redskins

This week's notes start last week, but Saturday was after my last post and it's appropriate this beings with an ending because that's where I want to begin. I was lucky to learn a Universal Truth in my first job. There was a woman who'd worked at Putnam for years when my class of newbies rolled in. As far as we could tell, she was one of the engines that made our department go: knew everything about her specialty, did a ton of work (at 34 instead of 22, I can tell you all she'd done is carve out a fiefdom by working on one thing and spending the rest of her time fighting to avoid the rest). She managed to miss a month of work with a back injury. Upon returning, someone had an uncomfortable conversation with her about how part timers didn't get sick time so they were going to have to take from her vacation time (leaving her with something like -97 hours to spend on beaches around the world). She walked out on the spot. Well, she made a scene and then walked out.

Shock. Desperation. Visions of insane workloads, late hours and less fun than we were already having danced in our heads. What we discovered instead: she talked a much better game than she played and her work was easy. In a couple of weeks, with no new hires, it was like she never existed. Since then I've always reminded myself no one is irreplaceable and no one is the keystone. When I left Putnam, I slunk out a couple of hours before quitting time just as the part-time ladies brought my cake in. Maybe a little cold, but they wanted the cake, not a goodbye and I've always been addicted to that feeling of freedom that only comes from leaving. Anything.

But all of that is a bit of a lie and I'm a lot of a hypocrite. Make no mistake, I am not a team leader. I'm too prickly and I can't modulate my expectations for people. Expecting less of others than I expect of myself feels like an insult. Completely unfair and maybe a little pathological, but there it is. I fancy myself more like a point man: you might not see much of me, we might not be best friends, but you're never going to get blown up on my watch. While I tell myself nobody makes a lasting impression unless they jump from a great heightr[1], I've always had it in the back of my head I lead by example, I leave places better off than I found them. Which is a damn fool illusion to walk around with. Because on Saturday I ran into some code from a place I used to work. And it took me a half hour to calm down enough to fix the worst of the mistakes in the code. You can see why I'm not a team leader. Calming down involved emailing a couple of former coworkers to grouse. We decided the secret ingredient when we were there were the small smattering of complete incompetents who made everyone work double-time because they knew they had to carry the load. In the hope of reducing the sum total of complete incompetents in the world (at least for the next 10 minutes), I'm going to talk about how not to write the code I came across. So if that sounds like nerdery, jump off now. It won't get any better in the next graf.

The first time you code something, it is the most rickety thing you'll ever come across. Various labels exist for this genus of code: "twine and baling wire", "duct tape", etc. You're basically speaking a foreign language and the fist time you get an acceptable response, you stop everything and call it done. The form submits and anything shows up in the database? Success! Don't anyone touch it. Assuming you're not completely put off by the process, at some point you realize your code can break. But even after cleaning up all the mistakes, there are still any number of ways a user can break the thing. Exceptions. So you write your first exception handler[2].

The first step to exception handling enlightenment (keeping in mind your narrator is an unreliable one) is to start using them. That's something. It shows a beginner's mind. It shows humbleness, a realization of the imperfection inherent in all works of man. But you've barely gotten anywhere, because all you do when you first start trapping exceptions is "Please catch anything that happens. Eat it, swallow it and pass it without ever making a sound. I don't want to know about what happens down in the guts of this program." Having a Beginner's Mind doesn't mean being ignorant. You need to know what's going on in there. Instead of saying, "This could blow up. I better set a trap here", you need to think of how it could blow up and trap that. Because if you don't know how it'll blow up, you don't know how you should be handling the exception. If the fire alarm in your house goes off, it could be that the batteries need changing. It could be dust got into the sensor. Or it could be your house is currently engulfed in flames. You don't want to handle all those cases the same way. Because there's only one way to handle those cases the same: run away screaming. It'll keep you alive, but it won't make for good code.

If all you're going to do is set up an anonymous try/ catch (i.e., one that traps every error), don't. You're better off without them. At least then when things go wrong your users find out and they can tell you. With anonymous try/ catches, no one knows what happened. Things just don't work. Ignorance is an enemy of good work in any field. Self-imposed ignorance . . . I don't even have a metaphor here. Don't do it. Here's another hint: the Warnings panel in your compiler? It contains warnings. Yes they are not errors. Yes you can ignore them. Yes there are a couple of things that it warns about that aren't necessarily so. But they're warnings for a reason and the compiler is smarter than you. So figure out what they mean. "I can always ignore 'Unreachable code detected' because someone told me to in this one specific case" isn't knowledge. It's faith. It's ignorance. Investigate everything, even when someone tells you to ignore it. Worst that happens is you learn something before you're done.

As pissed as that left me, it was nothing compared to dealing with one of my bigger clients this week. This big client has a big data team. The data team sends us big files full of chronological data. I got killed by QA this week for two major issues that revealed a troublesome problem: some of that chronological data ain't. When I pointed out their chronological data was sorted "alphabetically" by date (where dates run 3/2009, 3/2010, 6/2009) in one case (and apparently randomly in the other), this did not cause anyone to jump up and fix things. We're a small client for the data team. There are plenty of other clients they serve. The problem with that is no one could be relying on the current order of the data. It didn't exist. So, as is their wont, they paid me to work around it. Authorized a day's worth of work for me to deal with it instead of authorizing 15 minutes of work on the data team's side to fix the problem permanently across all existing and future projects that consume the data. Please don't sing me sad songs of how I don't understand big systems and all of the interactions and the need to QA and how many eyes have to look at the problem. Somewhere on some server there's a bit of code that pulls this data out without bothering to sort it like the rest of the data it pulls out. At the outside that's a 3 line fix. My 15 minute estimate gives you 10 to sit on the john.

1. Shamelessly stolen from The Old '97s

2. An aside here for the non-technical minded (though you were politely asked to leave): an exception handler is (wait for it) a way of handling an exception. But the important thing is what you consider an "exception". A good example of a handled exception is asking a user where to save a file and they provide a path that doesn't exist. The handler fires and gives you a chance to yell at the user rather than just crashing your program.


True Love: A Play in One Act


A nice April night, game is in the middle innings, Kevin Youkilis coming up to bat.

Michelle: After this at bat, I'm going to the bathroom, no matter what Youk does.
Me: What if he cries out your name?
Michelle (pensively): I'm still going to the bathroom