A break from programming languages

This is a blog post I have been considering writing for a long time.

People who have closely followed my work for the past few years have probably noticed that my output has gradually slowed. My last post on this blog was published over four years ago. The last talk I presented was almost two years ago, on work that I had recently finished but had started several years prior.

My enthusiasm for my hobbies has always ebbed and flowed. After spending much of early last year managing a frustrating mixture of mental and physical health problems, it was certainly at an exceptional low. All the same, so often I have found I need only wait for my motivations to return, and so I decided to give myself some time. But although I’ve been grateful to have plenty of that this past year to rest, reflect, and recuperate (and if anything my mental health is now the best it’s been in years), the conclusion I find myself forced to confront is that many of the passions I once felt so strongly do not seem to be coming back.

This post is a personal exploration of my feelings. It is a little self-indulgent: it is intended primarily for me, a means by which I may collect and process my thoughts. It provides me a certain closure, and it’s helped me make sense of where I ought to go next. Nevertheless, I hope it will also serve a secondary purpose: to explain why—and perhaps more importantly, why not—I have decided to close this particular chapter of my life, and what lessons I’ve learned along the way.

Whence programming languages

I have had a personal fascination with programming languages for as long as I have been using them. I made my first serious forays into programming in the fifth grade, writing (very simple and mostly very bad) Flash games in ActionScript 3. I wrote my first programming language interpreter in my sophomore year of high school, a dynamically-typed, object-oriented Lisp with prototypal inheritance. The interpreter was written in C, and despite it being my first serious endeavor with the language, I used preprocessor macros to implement a form of exceptions in terms of setjmp.h. It is an amusing project in retrospect, given what my design sensibilities would eventually turn out to be, but it at least provides a little insight into how much the subject was already on my mind in my teenage years.

I have always deeply enjoyed programming. That is no less true now than it was fifteen years ago. As someone with (then untreated) ADHD, the automation of repetitive tasks has always held immediate appeal, but it did not take long to discover I enjoy programming for its own sake. It is inherently delightful to me to direct an infinitely reconfigurable machine towards any end I desire, given only a little thought and some time at a keyboard. Program design, even in the large, was something that immediately appealed to me. It is often as much a challenge of organizing one’s thoughts as it is a matter of translating them to a form the computer can understand, and the former is a challenge I have always found rewarding.

Even so, as every programmer inevitably discovers, the gap between one’s thoughts and executable code is never so narrow as we would like. I quickly discovered that a distressingly large amount of my time was being spent on the exactly the sort of repetitive task I had hoped to avoid, mechanically typing out reams of boilerplate in order to carry out what seemed to be incredibly simple tasks.1 It felt strange that we, as programmers, could be one of the lucky disciplines equipped with the means to produce our own tools, yet the tools we work with are so frequently unsatisfactory.

Programming is an astonishingly young discipline. FORTRAN, arguably the first recognizable programming language, is less than seventy years old, and the first stored-program computers are only a decade older. Programmers have been trying to bridge the gap between our conceptualizations of programs and the (often laborious) act of programming for as long as computing has existed. As John Backus said in 1979,

Much of my work has come from being lazy. I didn’t like writing programs, and so, when I was working on the IBM 701, writing programs for computing missile trajectories, I started work on a programming system to make it easier to write programs.

In my experience, this sentiment perfectly captures the strange relationship many programming language enthusiasts have with our craft. We enjoy programming so much that we are willing to spend enormous time, thought, and effort working on programming systems precisely to free ourselves from the tortuous burden of writing programs.

One possible means of reconciling this apparent contradiction would be to hypothesize that programmers like me or like Backus enjoy the results of our programs but not the process of writing them. We want to get things done, and we view the computer as a useful but necessary evil that should get out of the way as much and as expediently as possible. However, although I am sure there are many programmers who do match that description, I do not count myself among them, and I would likewise find it extremely difficult to believe that Backus—a man who dedicated his life to designing ever more sophisticated means of expressing computer programs—was someone fundamentally uninterested in programming.

On the contrary, I see a great deal of work on programming languages as a struggle—often in vain—by those of us who love programming so much that we wish to free it of its unfortunate imperfections. We strive to remove the impediments and obstacles we face when translating the beautiful, platonic programs we hold in our heads into the comparatively cold, alien language of silicon calculating machines. There is a widespread mythology that programming languages are primarily abstractions over machine code, but this perspective has been misguided for almost as long as programming languages have existed. Programming languages are instruments of thought, frameworks for precisely specifying an executable idea, and they are designed almost entirely for humans, with computers often providing little more than a loose set of inconvenient restrictions.

To compute is human, to program divine

The earliest computers were developed with a singular purpose in mind: to compute. A program was, essentially, a sequence of instructions containing the computations to be performed. This conceptualization of a computer program as essentially analogous to a cooking recipe or assembly manual has remained curiously persistent, even to the present day.

Almost no modern programs of any complexity look anything like a cooking recipe. Even programs written in the most imperative programming languages under the sun are complex webs of logic specifying dataflow, access policy, and interaction patterns between semi-autonomous, reactive subsystems, many of which come equipped with their own living, beating hearts. At the micro scale, it is true that programs specify behavior as a series of steps to be performed, but even this is a fiction maintained by modern compilers for humans’ convenience. Through a compiler’s eyes, the real programs are whatever is left after the comforting fiction is boiled away to obtain a homogenous pile of SSA and dataflow graphs to be haphazardly reassembled into a patchwork of basic blocks in a language most programmers would not even begin to understand.

Indeed, in stark contrast to the mental model of the programmer as a sort of silicon whisperer, I believe most practicing software engineers are primarily maintaining vast behavioral specifications whose defining sense of rigor comes not from computers per se but from the consistency we demand from their results. In other words, we are trained to be fluent speakers of languages that allow us to articulate a solution to a problem with a level of precision that ensures every legitimate interpretation is and will always be to our satisfaction. Crucially, these specifications do not fully specify how the task is to be carried out. Optimizing compilers are free to make their own choices with whatever leeway we permit them. HTML/CSS user agents may interpret our instructions in whatever way preserves whatever web standards happen to require. Even RDBMS query planners, a foundational technology largely unchanged for the past several decades, are essentially expert systems designed to decide on the fly how best to execute searches and retrievals under ever-changing conditions.

This is not to say that the task of programming is fully removed from the machine that ultimately executes our instructions, nor is it even really a suggestion it ought to be. Performance and debugging mandate a certain familiarity with the underlying system, even if the full complexities of its true inner workings remain carefully hidden from even its expert users. My point is simply that programs are not rote algorithms, and the act of programming is not primarily characterized by algorithmic thinking. Rather, programming is fundamentally a game of domain modeling and system design, with bits of algorithmic logic inserted here and there to glue the whole thing together.

My interest in pushing the frontier of programming language design has always been and continues to be an interest in making the task of writing programs feel closer to the task of designing them. In an ideal world, I would have a language expressive enough to more or less directly translate the computer programs I have in my head (which, for me, more often than not take visual form) into a digitized structure a computer may faithfully execute. It is that task I found myself fixated on at the tender age of fifteen, and it is one I would remain fixated on for the better part of the following decade.

Ten years of programming languages

I turned twenty eight this year. Almost exactly ten years ago, I started my first professional software engineering job. It was a fairly mundane position writing Ruby on Rails and JavaScript, but even then, I spent a great deal of free time pursuing the programming language hobby projects that truly caught my fancy. My first professional experience working with Haskell would come less than a year later, experience that would soon inspire my hobby research project to implement a Haskell-style type system within the Racket macro system. The majority of my career to date has followed more or less directly from that formative time.

After a decade, it seems fair to reflect a little on what I have learned, what I managed to achieve, and maybe more significantly, what I did not. Something one learns very quickly upon beginning any serious work on programming languages is that they are startlingly, unforgivably hard. A vast array of dizzyingly smart people have been working on the problem of program specification for seventy years; there are not many pieces of low hanging fruit left on the tree, and any new gains tend to be very hard won.

Still, even if programming language design is challenging, it would be some consolation if we were able to slowly yet steadily advance the state of the art, gradually picking away at the gap between the tools we have now and the ultimate programming language of the future. Sadly, even that pragmatic vision does not survive contact with reality. In practice, the challenge of programming language design is not one of expanding a well-defined frontier, it is grappling with a neverending list of fundamental tradeoffs between mutually incompatible features.

Subtyping is tantalizingly useful but makes complete type inference incredibly difficult (and in general, provably impossible). Structural typing drastically reduces the burden of assigning a name to every uninteresting intermediate form but more or less precludes taking advantage of Haskell-style typeclasses or Rust-style traits. Dynamic dispatch substantially assists decoupling of software components but can come with a significant performance cost without a JIT. Just-in-time compilation can use runtime information to optimize code in ways that permit more flexible coding patterns, but JIT performance can be unpredictable, and the overhead of an optimizing JIT is substantial. Sophisticated metaprogramming systems can radically cut down on boilerplate and improve program concision and even readability, but they can have substantial runtime or compile-time overhead and tend to thwart automated tooling. The list goes on and on.

The essential, most stubborn problems in programming languages come from unavoidable tensions between conflicting desires and requirements. We want loosely coupled software components that can be easily reused, but we also want the performance benefits of tight coupling and specialization. We want flexible programming languages that do not impose upon our freedom of expression, but we also want the benefits of static program analysis and powerful safety guarantees. We want sophisticated type systems that allow specifying ever more complex invariants, but we also want readable type signatures that won’t regularly end up longer than the code itself.

We cannot build the One True Programming Language because we cannot have everything at once, and we cannot hope to universally decide which tradeoffs are the right ones to make. This naturally makes the thought of a system constructed from a tapestry of many different programming languages attractive, affording the programmer the opportunity to select the tool best suited to the task at hand. Unfortunately, that, too, comes with (often brutal) tradeoffs of its own: the impedance mismatch at language boundaries, the vastly more complex tooling required for a polyglot system, and the increased knowledge burden of maintaining a system built in so many different ways.

Ten years of working on and thinking about programming languages has forced me to come to terms with a humbling truth: I do not know how to build a better programming language. I am personally extremely sympathetic to the idea that the future of programming probably involves more domain-specific languages, and I think the industry as a whole has been (very slowly) trending in that direction for quite some time. But even I acknowledge that the question of how precisely that ought to be done is extraordinarily complicated, and there are no easy answers here.

Even so, it would be far too dismal of me to suggest that the problem is hopeless, nor do I believe the work does not matter. Even if the problem has proven more difficult than teenage me may have hoped, the work is satisfying when it bears fruit. Unfortunately, even after toiling for years overcoming daunting problems, every working programming language enthusiast is forced to confront a much more frustrating enemy: programmers.

The reactionary conservatism of the median programmer

It should come as no surprise that programming language design is largely a social problem. Choice of programming language tends to be driven by strong network effects, and programmers tend to prefer languages that resemble what they already know. Programmers’ general lack of curiosity and outright hostility to learning new things has always been a personal frustration of mine, but I ultimately do understand much of where it comes from: as engineers, an overwhelming part of our job description is managing risk. Exotic technology choices are risky, and it is a responsible impulse to be wary of them.

Still, the history of mainstream programming languages is essentially a story of programmers vocally and emphatically rejecting what eventually proved to be some of the most incredibly successful innovations in the history of the field. Assembly programmers largely laughed at FORTRAN, but just a few decades later, there were nevertheless very few remaining assembly programmers. First-class functions were widely derided as needlessly complicated and confusing until programmers were forced to finally take the time to learn to use them once JavaScript became a load-bearing language by historical accident, and within a decade, they became a required feature for every major programming system. Sophisticated type systems largely retain a perception of overengineered, ivory-tower elitism, but many of the programmers who hold those very opinions have enthusiastically adopted Rust, a language that features a type system so complex that idiomatic Rust code can easily put Haskell programs to shame.

Discussions of programming languages are, by and large, emotionally driven shouting matches based on anecdotes and gut feelings. Surprisingly (or perhaps not), although most working programming language theorists and compiler engineers have a far more informed perspective on this subject (and do at least tend to refrain from petty debate), disparaging remarks directed towards languages not to the speaker’s taste are hardly unheard of even at academic conferences dedicated to the subject. I want to be very clear that I do not think that is somehow indicative of some toxicity within the community—they are by and large a group of truly amazing, wonderful people, and such comments are usually delivered with tongue planted firmly in cheek. All the same, my point is simply that programming languages are an emotional, opinionated subject in a way that seems perhaps inherent to the craft, a topic I explored at some length all the way back in 2019.

I do earnestly believe that the field of software engineering would benefit from more openness to new ideas and willingness to experiment with new technologies. I also think it would be enormously refreshing if programmers did not nearly universally speak with an expert’s confidence on subjects they have only passingly encountered.2 Nevertheless, I do not expect programmers’ tribalism to diminish anytime soon, so the pragmatist in me understands their nature imposes real limitations on what we as a field can meaningfully accomplish.

In my experience, most working programming language researchers have essentially resigned themselves to this fact, and the prevailing wisdom is to almost entirely decouple the value of the work from its impact. Even if an idea is broadly ignored by programmers today, if it’s a good enough idea, it will still make its way into some programming language in some distant tomorrow, as many ideas eventually have. Lexical closures were first applied to programming languages in 1975 but took a full thirty years to be broadly accepted. Algebraic datatypes were first introduced around the same time and have only recently found mainstream acceptance through Rust. Innovations take a long, long time to make the jump from research to practice in this field, and placing one’s sense of professional accomplishment in the fickle hands of mainstream programmers’ whims and preferences is a recipe for personal misery.

I have nothing but respect for this attitude, genuinely. This research community is astonishingly friendly, warm, creative, fun, and accepting, especially given the vitriol these subjects tend to elicit from programmers at large. I feel genuinely honored to have had the opportunity to personally collaborate with many of them, and the collective output of endlessly fascinating ideas and exciting projects one can find each and every year at every major PL conference is consistently inspiring. All the same, as much respect as I have for the people who work tirelessly on these problems for their own sake, I am not sure I can continue to count myself among them. I do find the subject exciting, and I do consider it rewarding in its own way, but these past few years, I have slowly been coming to terms with the fact that I don’t think I find it quite rewarding enough.

Why I write computer programs

I like writing software. It is strange how radical a statement that sometimes feels. So many programmers seem to practically despise what they do for a living, at least as you’d hear them describe it. I have never really been able to empathize with that mindset. I find programming fun, and I derive a unique joy from writing code that decisively solves the problem at hand. It doesn’t have to be a particularly interesting problem, and the solution doesn’t even have to require much more than snapping blocks together, but as long as I can take some pride and satisfaction in the craftsmanship and end result, I am usually pretty happy.

My attraction to libraries, tooling, and compilers has always stemmed from a mixture of personal motivation and a certain satisfaction from improving things for my peers. One of my favorite things about software engineering is taking a problem and solving it in such a way that it largely stays solved. Sure, it may need to change as requirements evolve, but the solution continues to work even after the labor is done. Other tasks in my life do not provide nearly the same sense of accomplishment. When I do a load of laundry, it provides me with clean clothes for a week or two, but ultimately, I know it won’t be long before I’m going to have to do it again. Software engineering is not like that. Working on software—even extremely mundane software—provides a pleasant variety of tasks that can be well and truly completed. I like that sense of progress, and I appreciate the relaxing, almost meditative process of growing and maintaining the metaphorical garden that is a collection of code.

Given all of the above, it is not altogether clear why I would struggle to take satisfaction in my work on programming languages. If anything, working on a compiler seems like the ultimate realization of my aforementioned desires applied to the very thing I, myself, spend my day doing. If there is some annoying or repetitive task, and I can extend my programming system to provide a better way of doing it, that task is something I will never again need to do. What’s more, working on a compiler that thousands of people actually use means this is not just benefiting me, it’s benefiting everyone else as well. It feels good to have that kind of impact, and to know that my effort is essentially multiplied by everyone who happens to use it.

On paper, this ought to make working on a compiler like GHC enormously satisfying. Even if I feel frustrated by mainstream attitudes towards programming languages, Haskell programmers feel differently. Surely, working on something used and appreciated by Haskellers ought to feel very rewarding. But it wasn’t really. There were parts that were nice, yes, and the problems were often interesting. But I didn’t find it rewarding in the way I had hoped, and I’m not sure it even compared favorably to working on bog-standard software. Why?

On the Haskell community

This was the hardest section of this blog post to write. It is easy to write about the things I love and the people I admire. It is perhaps even easier to write about the things I despise and the people I disdain. The Haskell community is neither. I do not dislike it. Several of its members are people I consider very good friends. Nonetheless, I have never managed to fall in any particular love with it, and even if that is no sin on its part, it is a somewhat sad thing to have to confess.

I want to be excruciatingly clear that I do not wish to mount any indictment of the Haskell community or any of the people in it. Many people seem to have a preconception of Haskellers as mean and elitist, and while I do get the sense there have been some historically bad actors that contributed to that perception, my general impression is that those people have been thoroughly expunged. I have never been the target of any memorably rude conduct, and I’ve definitely never felt targeted by any prejudice or discrimination, and if anything I have always felt universally warmly welcomed at every meetup or conference I have attended. I cannot speak for anyone but myself, and my experiences are necessarily limited. I cannot hope to claim with any certainty that no abuse has ever occurred or that it does not continue to occur within any Haskell’s myriad social spaces, most of which I have never participated in. Still, I am happy to be able to say that I have never personally experienced any real unfriendliness, and that is certainly not a factor in my dispassion for the language’s community. If anything, I feel I must extend a very genuine thank you for all the lovely support I have received from Haskellers over the years, and it is that support and enthusiasm that so often kept me motivated for as long as I was.

This is all simply to say that I do not think it is the fault of anyone in particular for my lack of affinity for the Haskell community. Rather, I think perhaps it is just not a culture that I have ever especially related to. That probably does not even say very much, as I’m not sure there are many communities I could say that about. That says much more about me than it does about Haskell or Haskellers.

It is admittedly tempting to say that perhaps I find these communities alienating in part because they lack people I identify with and relate to. After all, it is simply true that the Haskell community is overwhelmingly male, which really has felt lonely at times. It’s also true that the Haskell community tends to attract a lot of people who are mainly interested in Haskell because they find it intellectually interesting, or because they like category theory and enjoy libraries like lens that have explored those ideas, while I am really only interested in Haskell insofar as it is a practical vehicle for writing useful software. Nevertheless, there are other women who write Haskell and there are other people who care very much about writing useful software in Haskell, and that doesn’t seem to have radically altered my relationship to the community, so I think it would be disingenuous of me to claim that either of those flaws are substantially to blame.

If there is one substantive frustration I can express with Haskell, it is where the money comes from. For as long as I have been involved with it, Haskell has predominantly been used and funded by a combination of fintech and cryptocurrency. I don’t really have anything against fintech, though I certainly don’t find it especially exciting, but I do have something against crypto, and those who followed me on Twitter before its untimely demise know I have always been pretty open about that fact. My thoughts on the matter are really not something I want to elaborate on here, but suffice to say it is not especially motivating to work on a language if all of its users are applying it in ways I feel essentially indifferent about at best and actively hostile to at worst. This is obviously not something I have any easy answers to, but it is probably the most significant, concrete factor in me losing my interest in working on GHC, so if you mourn me leaving, at least I can give you one semi-actionable reason.

Make no mistake: GHC is a truly incredible project that often still feels like a compiler from the future, and having the opportunity to work on it as a part of my job was about as technologically stimulating as I could possibly ask for. Even so, during my time at Tweag, I often found myself reflecting on the fact that the users I was working for were, ultimately, Haskell programmers, a class I’m not sure even really contains me. I have often reflected on the fact that, although I have many personal projects, I have never chosen Haskell for any of them. Not once. Whenever I need to write a little code to accomplish some task, it’s always Racket. This blog is in Racket. My personal shell utilities are in Racket. When I want to scrape a website or wrap some library, I do it with Racket. Haskell is a language I have always exclusively written professionally, and although I do very earnestly love many things about it, it is not so precious to me that I feel motivated to contribute to it out of passion alone. If there were more users of Haskell doing inspiring, exciting things with the tools I was working on, I might feel substantially more driven to indirectly contribute to those causes. But Haskell is a niche language used by a select few, and it is hard for me to spend so much of my life working on a technological marvel that practically nobody will ever benefit from.

As a final note on this subject: I do believe very earnestly that the functional programming and programming languages communities would benefit enormously from more demographic diversity. Even compared to software engineering as a whole, the gender ratio is, frankly, almost unbelievably grim. I have always been drawn to interests and hobbies that tend to skew male, and that has never really bothered me, so if I have found myself feeling alienated by the conspicuous absence of other women—to the point that, in the past, I have sometimes considered giving up on Haskell primarily for that reason—I don’t think it is outrageous to say things are pretty dire. A wider set of perspectives could, in theory, inject some refreshing creativity into the dreary ecosystem that is industrial Haskell. Of course, I will admit that I have absolutely no idea how that end could possibly be achieved, and it is a subject far broader and more complicated than I think belongs in this blog post. For now, I will leave things at that, but I hope my voice is sufficiently well regarded that some readers may take my comments to heart.

Reflections on a decade’s work

Before writing this blog post, I essentially pitched it to a group of friends as “a sort of apology”. At times I certainly feel burdened by the weight of all the endeavors I’ve left unfinished, all the work I never carried long enough to bear fruit. Even so, as I write these words, I find myself reflecting on the things I feel I did manage to contribute these past ten years, and it strikes me that the trail I’ve left behind is perhaps not so dismal, after all.

It is comforting to look back on a decade’s accumulations and realize there is enough to take some real pride in. I am proud of my contributions to Racket and Haskell, and of my numerous libraries in each of them. I am proud of my experiments, among them Hackett and eff, and the excellent work from others they have inspired. I am proud of this very blog, from the most impactful things I’ve written to the far more niche. I am proud of my contributions to Programming Languages Stack Exchange, a site I most certainly intend to remain a moderator of and will undoubtedly continue to contribute to. And I am proud of the numerous talks I have presented over the years, all of them labors of love.

I have not always accomplished all the things I set out to achieve. Some have, for some reason or another, gotten the better of me. Many of them, from my math typesetting system to my improvements to GHC’s arrow notation, are things I hope to one day push over the finish line. But for now it is clear my heart is no longer really in them, so I think it is time for me to let them go. Perhaps others will find inspiration in them. Perhaps you will succeed where I did not.

It is a little sad to think about moving on from such a substantial chapter of my life. To date, I have spent almost my entire career in this professional niche, and I suspect I will never fully leave it. It has been a pleasure to work with so many bright, lovely, inspiring people, and perhaps one day I will find myself eager to return once more. But for now, my interests are elsewhere, and despite the bittersweet feelings, there is also a very real excitement in the tantalizing opportunity to do something new.

What next?

It is a little amusing to think that what I find myself most drawn to after a decade of pursuing ever more exotic projects is something entirely mundane: I want to write utterly ordinary software. I want to work on a piece of software used by people to accomplish a task, and I want to take pride and satisfaction in doing it well.

I do not yet really have any idea what that might look like. It has been over six years since I last worked on anything that really feels like it could possibly fit that description, and even then, it was only one part of my job. Is it so strange that after spending fifteen years of my life trying everything I could to get away from spending all day wrangling a big ball of mud in a Java IDE, that experience sounds pretty cozy to return to?

In late 2022, I decided on a whim to reverse engineer and resurrect a 2008 Java browser game called Shattered Plans. While doing so, I had the opportunity to spend an awful lot of time in IntelliJ, and after years of acclimatizing to writing code in fanciful languages with nothing more than a plain text editor, a terminal emulator, and a dream, the experience was almost viscerally thrilling. They say the grass is always greener, but even if that is true, I think I’d like to find it out for myself.

More to the point, my life is just very different now from how it was for most of my twenties. I was single, and it was easy to justify spending almost all of my time thinking about code, whether on the clock or not. It was hardly unheard of for me to spend twelve or even sixteen hours at my desk, just tinkering on something that had captured my attention. It was fun, and I’m glad I did it, but I am also very ready to work a simple, regular job I don’t feel the need to permanently devote a large portion of my soul to. It isn’t very romantic, but then, I have other things for that.

If you think you have a position that meets those (admittedly extremely broad) criteria, and you think you might like to hire me, by all means: send me an email. The worst I can do is not reply. And who knows? With the burden of my own expectations behind me, perhaps I’ll even blow the dust off this old blog of mine and start writing things again. As with my job, whatever I might choose to write next I cannot say. Either way, it’s a little exciting to be able to treat myself to a blank slate.

I could probably spend twenty thousand words writing in circles about all my thoughts and feelings on this subject. However, to be honest, I don’t especially want to. As this blog post has hopefully communicated, I would like to be done, and so this will have to be enough. Allow me to personally thank all of you who have indulged me by reading my disorganized ramblings to the end.

It’s been a long time. Here’s to another ten years.

  1. Readers may find it clarifying to note that a great deal of my early programming experience was writing (then era-appropriate) Java 6.

  2. I have often wondered if other engineering disciplines have anything to rival the collective overconfidence of the average Hacker News commenter. This is an earnest curiosity, not merely a rhetorical flourish; I do sometimes wonder what it is about my field of choice that engenders such disregard for the value of expertise.