Second Class Developers

Was talking with a friend today about how some developers look down on others for the tools they use. So like the rest of my posts I figured why not write about it!

Before going any further though, if you prefer watching/listening to someone talk then before anything else I’d recommend this talk by Felienne Hermans. I don’t think I’ll ever reach her level of explaining this concept. Plus it’s just a really great talk.


This topic of developers looking is close to my heart. I’ve seen it happen with things as fun as Minecraft where for years there were developers talking about how it’s a lesser game because it’s written in Java instead of C or C++. I saw it happen with Celeste when the developers released their code so that others could learn from it. Lots of other devs decided to instead criticize their code quality and style. Most frequently though I see it happen professionally with web developers, those who write web sites and web apps and more generally use Javascript to do so get looked down upon by those writing servers or native apps. Why though? Why treat the developer who uses tools you don’t like as lesser than you? Many, many times, the thing they’re building would never get built if instead they were always trying to us the “best” tool. Even then, what’s best for the job may vary depending on who you ask.

Regardless of whether it’s the best or the worst tool, we shouldn’t be shaming or ostracizing those who use tools we disagree with or dislike. Instead we should be welcoming them and conversing with them. Maybe they use the tool because it’s the only one they know. Maybe it’s because your favorite tool, or tool of choice, is missing something they need that you aren’t aware of. Maybe they don’t have a choice and are using it because they were told to by their boss. By excluding these people not only are we hurting them, but we’re also hurting ourselves. We are losing out on the perspectives and ideas of someone different from us.

Scallops!

For the first time in over a month my wife was feeling well enough to cook dinner, so tonight she made me scallops with a celery root puree.

Celery root and rice cooking

This is also the same meal as the very first meal she cooked me! So extra awesomeness!

Roses are Red

But are they? Looking at the picture above I see red and green. Someone might argue that the green part is the stem and if you remove the stem… well then you’re left with only petals not a rose. But for arguments sake, what if we were just talking about the petals? Well, to a child, yes those are red. If you’re at the florist you’d also ask for red roses. But what about the person who has to paint a rose? Would they say “Hand me the red paint.”? Would Bob Ross tell you to grab the red paint? No. The person who’s working in the domain of colors would ask for a Positive Red and maybe a Heartthrob (both taken from Sherwin Williams). In other words, the person working in the domain needs to be more expressive. Using simply “red” isn’t adequate because it’s too general.

How does this apply to software you might ask. If I’m talking about colors in programming we already have expressiveness with hex colors (red in hex #FF0000), rgb colors (255, 0, 0), named colors, hsl colors, and more. That’s really amazing! Well what about other things, how about an email address? Well most languages have strings, so we just represent our emails like so:

const person = {
  email: "wolfadex@gmail.com"
};

So that works, but what about:

const person = {
  email: "wolfadexgmailcom"
};

That’s not a real email address, but it is a string still. So now we’ve reached a point where our code thinks everything is valid but we know it’ll fail when we go to send an email. This, to me, isn’t a failing of the programmer but of our languages. The most popular languages are also the ones that are the least expressive in their vocabulary. Instead, I prefer to work with languages that allow me the option, and I really want to stress here that it’s an option, to use more expressive vocabulary, aka more expressive types. For me, this isn’t about static vs dynamic, or functional programming vs object oriented programming. What it is about is being able to better communicate my intention and better understand the intention of those who came before me. What does this look like? A simple example

type Email     = Email         { username : String         , secondLevelDomain : String         , topLevelDomain : String         } type alias Person =     { email : Email     }

This is a little Elm code declaring a new type called Email, which works at the same level as Int, String, Object, etc. It then has a constructor called Email which works at the same level as 0, “hello”, { key: value }, etc. Then within that a record, which for this discussion is basically like a JavaScript object. Lastly there’s a record that’s aliased as Person and has an Email. With this setup I now have to write functions for creating an Email and making sure it’s valid. Not really all that different from what you’d do in most languages. What makes this different, and I’d argue better, is that this type system tells the incoming user what they’re working with and before you go “well the variable name also tells them that!” I’d say that this is a very simple example. When I’m working in large code bases, like millions of lines of code, there are many values that you’re unsure of when your first see them. If I come across

if (state.loading) { ... }
if (state.error) { ... }
return state.data.map(...)

what are the types of loading, error, and data? Is data ever null? loading and error look like they’re Booleans but are they really? What if I want loading to have 3 states: currently loading, finished loading, never loaded before? Now it will always be true! Depending on the language I may also have to change the if statements to:

if (state.loading == "loading") { ... }
if (state.loading == "notYetLoaded") { ... }
if (state.loading == "fished") { ... }

This is all well and good, but did you see my typo above? Languages don’t validate that your String is spelled correctly. With a more expressive type system I’d instead write this as

type Request
    = NotYetLoaded
    | Loading
    | Failure Error
    | Success SomeData
case request of
    NotYetLoaded -> handleNotYetLoaded
    Loading -> handleLoading
    Failure err -> handleError err
    Success data -> handleSuccess data

Not only are the values more precise, just like in our initial discussion about red vs Heartthrob, but we are also guaranteed to not end up in weird states like checking for state.loading == "fished" which doesn’t make any sense.

Many love to point out that you still need tests, and that this doesn’t prevent the artist from painting their rose Hyper Blue, but that’s not the point. It’s not about preventing valid values it’s about communication. When I ask an artist for a red rose, I don’t want literal red I want shades of red. I want them to be expressive.

Finding a Focus

When I speak with coworkers or strangers about tools I find a lot of time is spent focusing on the wrong things. Things like “is it popular” or “what about this edge case I’ll never encounter” or “this 1 person doesn’t like the tool”. Focusing on these and related topics ends up costing you a lot of time and a lot of energy.

Instead, I prefer to focus on:

  • is this tool reliable
  • if I come back to this tool in a year, can I easily pick up where I left off
  • will this tool last me 2-3 years or will it break

This isn’t programming specific either. About 6 months ago I picked up knitting because I’d always wanted to try another fiber art and I’d already tried stitching, crocheting, and some light sewing and quilting. I chose knitting because the tooling was simple, even after putting it down for a month I was able to pick it back up really easily, and the tools are sturdy and simple enough that they should last me for many years. The cost is also low.

Because I do software development for a living I also apply these rules to the programming tools I choose, and why I choose Elm for most of my side projects. Elm is incredibly reliable. I’ve made many-thousand line refactors and it just works when I’m done, without ever needing a single test. If I rely on a 3rd party package and a new version is released, there’s minimal if any effort to upgrade. When I go back to old Elm projects, it takes me only a minute or two to get rolling again. When I read anyone else’s Elm code, I feel comfortable diving in immediately. Finally, in the past 3 years the core language hasn’t changed and the community has only made things easier.

I can’t say the same for the tools I’ve used at work over the past 3 years. React has introduced hooks which had a huge impact on the ecosystem. Ember has a new release every couple months. Vue has had enormous changes too. When I go and look at a random React, Vue, Ember, Svelte, Angular, etc repo it takes me a couple days to begin feeling comfortable. Feeling comfortable making production changes, probably another week or 2.

However, I’m not saying to use Elm for everything. When I do cli work I play a lot more with Deno because it’s really easy to build something quick and none of my cli work is serious. If I want to spin up a simple static website, just some html + css and surge.sh or GitHub Pages for hosting. If I want a toy server I’ll reach for Haskell or Deno. Basically, if the thing I’m building is just a toy then I reach for something quick. If the thing I’m building needs to last more than a month, then I reach for Elm.