Boots

2021-Nov-24, Wednesday 10:58

You may already be familiar with the Boots theory of socioeconomic unfairness. As an allegory about how much more expensive it is to be poor, it's fine, but I think there's another story of socioeconomic unfairness we can tell with boots as well.

Let's take a trio of characters: a cobbler, a tradesman, and an investor. The cobbler, looking to retire, has one last pair of boots for sale. Much like Pratchett's good boots, they're high-quality and marked at $50, the sort you could reasonably expect to last for a decade.

Our tradesman needs new boots and has one hundred dollars, and so goes in to the store to buy them. Seeing this, the investor offers to pay a little more, thus starting a bidding war with our tradesman.

Naturally, the investor wins the bidding war. He gets the boots for $101—just enough to price our tradesman out of the market. The cobbler is certainly happy—he got twice as much for the boots!

The investor, having no need for the boots himself and keen to spot an opportunity, offers to rent the boots to the tradesman, for a mere $5 per month.

The tradesman, still in need of boots, agrees.

One year in, our investor has netted $120 (a $19 profit!), and our tradesman is $70 poorer than he would have been had he been able to buy the boots himself.

Over the ten year lifetime of the boots, our investor has received $1,200 ($1,099 in profit!), and our tradesman is $1,150 poorer than he would have been had he been able to buy the boots.

Not bad for the investor, considering all they brought to the table was the ability to outbid our tradesman by a dollar. Our investor got richer not by being more clever or smarter than our tradesman, or even a better negotiator, but merely by being lucky enough to start with more money.

Pratchett's boots allegory is, in my mind, a comparison between poor and middle class, here we've made a comparison more between middle class and wealthy. I think it demonstrates that the rich don't get richer just because they can buy better boots, but because their starting advantages can be leveraged into vastly outsized results (the investor's $1 advantage netted over a 1000x return!). A small wealth gap can be expanded into a large wealth gap, and that process can be repeated ad nauseam until they own everything and the rest of us are merely tenants.

For the first time in my career, I recently got to sit in the hiring chair. My current employer let me look for a Software Engineering Intern. (With a little luck, I'm hoping to repeat the process for a senior level developer in the near future.)

I learned a lot, very quickly, doing that (a biggie: actually write down a list of questions to ask, don't just wing it—with my apologies to the very first person I interviewed, as I did not do a good job interviewing you), but this post is not about those lessons learned. This post is for all the people I had to send a rejection letter to. In my opinion, all of the people I interviewed were smart and capable of doing the job; actually picking one was a tough choice.

While our chosen field of computer programming offers amazing opportunities, finding work can be difficult¹, so don't despair. Here are some general tips to help you find work, and become a better developer.

Caveat: These are all filtered through my path as a developer, which absolutely does not match yours. The most obvious and major difference being I did not go to college. Props on going for the degree!

Finding Work

Give Talks

Local user groups—such as DSM Web Geeks, Pyowa, DSMJS, Iowa Ruby Brigade, CIALUG, and so forth in the Des Moines area—are always desperate for talks, as are larger conferences such as Iowa Code Camp. Too many people are terrified of speaking, thinking they need to be an expert, but that's just not true. The perspective you bring as a newbie, showing us all something you've learned, is both incredibly valuable, and woefully under-represented. It's also an effective way to catch the eye of a hiring manager or recruiter.

Giving talks will help you become a better communicator, which is a vitally important part of being on a team.

Contribute to Open Source

I learned a ton in my early days by contributing to open source projects. If you can find a project you care about, with a community of smart, patient people willing to help guide you, contributing to existing projects will help make you a better programmer, and give you things you can point at to say: I did that.

Contributing to open source will help you get better at revision control (e.g., git), reading code, and accepting feedback.

Develop Your Network

Getting your foot in the door of a place is a lot easier if you already know somebody on the inside. Be friendly, hobnob with other developers (e.g., at local dev groups), and stay in touch with people.

I've spent large chunks of my career as a lone developer and am a natural shut-in, so this is one area I regularly fail at.

Expand Your Mind

While learning the Framework Du Jour or a specific technology will help you be more employable in the short term, a solid foundation of knowledge will help you throughout your career, enabling you to pick up framework and language specifics more quickly, and to see the similarities with things which have come before.

While it'd be difficult to point you to the books that helped shape me as an early developer—in part because books like "QBasic For Dummies" and Laura Lemay's "Teach Yourself HTML 4 in 21 Days" would be a tad anachronistic at this point (though it appears there is a more modern version of the latter)—I can at least point you to some that have shaped me as a more intermediate developer.

How to Design Programs
This book is a gentle introduction to programming. It's a solid look at programming starting from zero. While you're almost certainly beyond it skill-wise already, I've been skimming through it lately and find the way it frames things can be helpfully clarifying.
Structure and Interpretation of Computer Programs
This was the textbook for an MIT course of the same name for a long time, and takes you from basic functions to meta-circular evaluators. Depending on what you've been exposed to already, it may well cover a gamut from "yeah, duh", to blowing your mind. Also freely available online as a textbook, and video lectures.
Practical Common Lisp
Common Lisp is a really fascinating language, and can open your mind to possibilities you likely haven't imagined. It certainly did for me! As just two examples: multiple dispatch and the condition system are among the things I sorely miss in other languages. Also available freely online.
Coders at Work
This book is a series of interviews with influential developers. It's an interesting foray into the minds and experiences of people who have ventured down the path of software development you are just now beginning to embark upon. This one isn't freely available, but it is a fascinating read, in my opinion.

Admittedly, that list reflects a heavy Lisp heritage. Lisp has had a heavy impact on me and the way I think about programs, but many languages can fall under the category of "mind-expanding". You're likely already familiar with Java, which covers the space of modern, standard object-oriented design. Some other design spaces you may want to explore, if you haven't already:

  • A purely functional language. Purely functional code is often easier to understand and test than OO code, and you'll see its influence across a broad spectrum of languages. A good way to explore this space is through Haskell, which is a very mathy language—you could easily get lost in monads and category theory—, if you're into that sort of thing.
  • Different concurrency models. Erlang's actor-based concurrency model is fascinating, and often much better suited to problem domains than thinking about lower-level things like threads and mutexes.

Sadly, none of these things are likely to make you more employable on paper—a sad reality of how we evaluate developers today—but they will make you better at the job itself.

Be Well-Rounded

It took me entirely too long to learn, but there is more to life than slinging code, so don't forget to do things that aren't programming. Take an improv class, learn some ballroom dancing, learn about user experience (UX). Whatever interests you.

  1. I am amazingly terrible at interviews, to the point where I've spent years in between jobs, and the jobs I've gotten are often in spite of my interview. I totally get how frustrating it is to be rejected.

One of my philosophies about exceptions is that they should be very specific. It's not enough to throw a generic Exception, or even a LibraryException, you should throw a specific exception for any event you want to handle separately. For instance, at a previous employer, our database layer would catch the generic exceptions (PDOException, in our case), inspect them, and re-throw as very specific exceptions (DuplicateEntry, CannotConnect, etc.).

Why

I've formed this opinion over the years, seeing things like the following code from a real application, which decides whether a nonced token has been seen before, and rejects the token if so:

try {
  // insert ...
  return false;
} catch (PDOException $e) {
  // 23000 is SQL error code for duplicate entry
  if (23000 == $e->errorInfo[0]) {
    return true;
  }
  throw $e;
}

That's ugly, and an annoying amount of boilerplate. It's much clearer if you can do something like:

try {
  // insert ...
  return false;
} catch (DuplicateEntry $e) {
  return true;
}

Particularly when you start getting into multiple scenarios, or start needing to support multiple database types. It can also be handy in the case of testing, since your mock can literally just throw the scenario you're trying to test.

If you're looking at that DuplicateEntry exception and wondering why it doesn't just check if the value exists first: race conditions, man.

Fun fact: that particular codebase has over half a dozen instances of catching DuplicateEntry for varying tables. Some of which are caught all the way in controllers to expose information to the user (hey, we already have an account with that e-mail address). The pain saved is very real.

Don't Wrap That Exception

This of course leads to another opinion about exception handling: libraries shouldn't wrap exceptions thrown by lower levels. At least, not in a generic, everything-is-now-a-LibraryException sense; clearly I'm okay with wrapping an exception to make it more specific.

There's a conflict of interest here: what exceptions get thrown is absolutely a part of your public API, and you want to be able to swap out the libraries you happen to be using underneath. Wrapping exceptions enables you to do that, whereas passing them through does not.

But here's the thing: in the age of Dependency Injection, your caller knows more about the exceptions thrown by the implementing object than you do. So if you're a Frobnicator, and your caller gives you a Fetcher implementation, you're actually hiding information the caller expects by catching exceptions thrown by the Fetcher and wrapping them in your FrobnicatorException. That's actively hostile to your calling code, because now to catch the exceptions they were expecting they must first catch your exception, unwrap it, then rethrow.

I guess another way of saying that is any layer in the middle should refine exceptions, not conglomerate them. Please, be mindful of which you're doing.

That's kind of a provocative title, so let me just get this out of the way: No, no they are not. And I am not crazy enough to attempt to convince you otherwise. That said, they aren't nearly as bad as they're given credit for.

Let's do this by way of example. Suppose you have a list, and users need to be able to sort it, alter the items in the list, and delete items. All your front-end developers are busy, and so are the UX people, so it's up to that backend developer to bang something out. What are they going to give you? Something, I suspect, an awful lot like this:

Sort Item Delete?

In other words, a <table> that closely mimics the underlying database structure. Yeah, I can hear the internal screams of the UX people from here. But let's consider this for a moment. Is this going to be fun to use? No. Definitely not. But in its straightforward simplicity, it gives us something that's kind of amazing: anybody can use this form. No matter how spotty your network connectivity, if you managed to load this form, you can submit it. If all you have is a text-only browser, you can use this form. No mouse? That's okay, this form is keyboard-accessible. Do you interact with your computer via voice command? This form will be serviceable.

For the vast majority of your users, this is not great UX. But it is Universal UX. Anybody―everybody―can use it! The web is universally accessible by default, and by staying away from the fancy stuff, by building something that would be at home in 1994, our backend developer managed to preserve that.

We definitely don't want to stop here, but it's a pretty great jumping-off point. So let's put our UX hat on and start making some improvements.

Sort Item Delete?

Some quick wins are simply to adjust the sort values to make rearranging easier, and adjusting the text of the button. Not terribly complicated, even the backend developer can manage it.

Sort Item Delete?

But of course, manually entering the sort weight is awful, so maybe we add some buttons to adjust the list sorting, so users can click a button, rather than type in sort values, and hide the numeric input with a little CSS. We'll leave it in the DOM both for text-only browsers, and to give a place for our buttons to store the sort order (assuming they function via JavaScript).

Sort Item Delete?

And as we get fancier, maybe we dim or strike-through the to-be-deleted rows, to make it obvious they're going to go away. We add a little JavaScript to enable drag-and-drop of the rows, for really simple sorting. Maybe we even add some keypress handlers so people can move things in the list by pressing C-x C-t or whatever seems appropriate. And if those scripts load successfully and work in the user's browser, maybe we even hide the explicit sort buttons from visual users, to avoid clutter. You do run the risk of excluding a small contingent of users that way―if you can only interact with a computer through eye-movements, visible buttons might be kind of handy―but for all I know they may have other ways of handling that, so if you've got the budget, maybe test that sort of thing and report back to the rest of us. I'd certainly love to know.

But in the end, what we end up with is a lot closer to what you might have designed as a visually-oriented UX person, but because we built it in stages, because we started with the basics and layered things on top, it's usable in far more scenarios than it might otherwise be had we started with a Photoshop mockup of the end result.

NB: As you may have noticed, there is no JS attached, and there isn't much in the way of styling. That's partly due to platform limitations, but mostly because this isn't really meant to be about how-to-build it, but more about what-to-consider in the design. It just so happens that if you build it in a certain order, those considerations naturally reveal themselves.

Last night, while attempting unsuccessfully to acquire sleepytimes, I heard a loud bang. This was quickly followed by the fomf of the power going out, and a short while later by the beeping of battery backups now without power.

Naturally, the first thing I did was go to shut down my computers. My first hint that this was more than a nearby transformer blowing is that my internet was out. My end is, naturally, well powered, but apparently my ISP does not provide battery power at their end, and their end was also without power.

Computers safely shut down, I wandered outside to see how widespread the problem was. The neighbors were without power. The streetlights, without power. I look up and down the street, and the neighboring blocks are, you guessed it, without power.

This can only mean one thing: something at the nearby substation blew.

So, naturally, I wander in the direction of the substation. On my way, I run into a police patrol. They don't stop me, but they pause briefly as they drive by to think about it. It's been maybe ten minutes, and they're already patrolling the neighborhood—a pretty impressive response time, though it seems weird that they'd respond to that at all.

A little bit later, I see some firetrucks. Nothing was on fire, so I have no idea what they were responding to, but okay. I guess they're out for the power outage as well? Well, that or they're breaking into the auto-parts store. I can't really tell.

The power company isn't at the substation yet, but that's not surprising: in all likelihood, some poor lineman has to wake up first.

So I wander around the neighborhood, to explore it in its unlit, silent glory. And it was awesome! No streetlights burning bright (the city has been slowly replacing the yellow lamps with bright blue LEDs, and if the yellow ones weren't bad enough the blue LEDs are awful). The usual ever-present hum of air conditioners was gone. And in spite of the streetlights being out, there was plenty of light to see by—though the moon being only a day or two off from full certainly helped with that.

Still no power company at the substation. But I do notice something: the nearby stoplight is blinking red. It was affected by the power loss, and has degraded itself to a four-way stop. Fascinating!

I turn around to head home, and am struck with an idea. So I wander several blocks over to the retail shops, and explore an unlit street, full of shops lit only by their emergency lights. Once in a while, I'll pass a building emitting the slow beep beep beep of a battery backup. Interestingly, the collision repair shop has plenty of lights on, and emits the unmistakable hum of a generator. I can only assume it kicked on automatically, since few people would be around so early to start it.

I head home, with a quick detour to the substation, where a pickup is just arriving. A few hours later, we finally got power again.

Losing power confirmed something I've long thought: getting rid of streetlights would be awesome! Particularly on the residential streets, where they're just not needed. Particularly that freshly installed bright blue LED two houses down that casts the glow of cheap office lighting across the entire gorram block.

It also confirms that several hours without A/C is several hours too many. Ugh.

And that my ISP needs to get on the ball, and make sure internet continues to function during a power outage. You're a phone company, making sure things continue to work should be second nature!

November 2021

S M T W T F S
 123456
78910111213
14151617181920
212223 24252627
282930    

Syndicate

RSS Atom

Most Popular Tags