Posts in Erlang (3 found)
Ludicity 5 months ago

Get Weird And Disappear

Can't leave rap alone, the game needs me 'Til we grow beards, get weird and disappear Into the mountains, nothin' but clowns down here The most treasured object in my home is the cheapest bookshelf I could find. It has been overflowing for quite some time, despite my efforts to only buy books of exceptional quality and relegating the rest to my kindle. Many of the books are unread, but that hasn't stopped me from adding to the pile 1 . My partner has gracefully accepted that I will stop at every bookstore that looks remotely interesting, and patiently reminds me that my past-self has issued strict orders to my current-self to stop acquiring tomes until I have space for a second bookshelf. Over time, I have dropped from buying a book a week to one every month, which represents a spectacular effort for me. Despite the gradual development of what I'd like to think of as iron will, I caved upon stumbling across this particular edition of A Wizard of Earthsea . This was a repudiation of all that hard-won bookshelf space saving. I had read A Wizard of Earthsea when I was thirteen, and I didn't really get it. It was a book about wizards. So what? It was slow and ponderous, and my teenage self knew that an interesting wizard should be firing lightning bolts at dragons. But the illustration on this copy of the book was so gorgeous that I bought it anyway. It was only when I slotted it into my bookshelf, and it was fully juxtaposed against the others, that I realized how hideous so many of my other books were. I treasure their contents , but consider the first two books I pulled at random from the shelf. The Robin Hobb book on the left is generally beautiful, but it is done a disservice by the George R.R Martin quote splayed across the front cover, its marketing payload expended the moment I purchased the book, but which I am nonetheless obligated to look at for the next thirty years. Almost all my books are thus marred. And this is, sadly, a relatively tasteful example compared to much of the competition. Consider instead the copy of American Gods on the right, sweet merciful Christ, it is a truly repulsive abomination 2 . Just look at it . The quote at the top is George R. R. Martin once again, which says something about what marketing departments think is impactful. In the top right, we see Ian McShane, which is incredibly jarring because I know him only for his role in John Wick. Along the bottom we have the tedious "No. 1 Bestselling Author". And most offensively, thanks to the screaming red bubble, my descendants will forever know that this precious artefact handed down from their great grandfather once had a no-doubt mediocre second season on Amazon Prime, whatever the fuck an "Amazon Prime" is. Did they turn the rainforest into a cinema when they were done destroying it? Upon closer inspection, my bookshelf is riddled with tasteless advertising smuggled into my home by boring marketing departments, and I am not open to arguments that this meaningfully boosts sales. Some people might have differing taste, but this is bland to the point of nothingness. At least erotica has the decency to slap a shirtless hunk on there, and we can envision the target demographic. Not a shred of this crassness is evident in this copy of A Wizard of Earthsea , and some part of me thought "This is Quality", and amidst the shrieking cacophony of the other titles ("New York Times Bestseller! Twilight Meets Game Of Thrones! Breathtaking!"), it is the one I walked away with. It is now one of my favourite books. A Wizard of Earthsea is a towering work of genius. Going back to it now that I'm older, I must simply accept that my teenage judgement was... well, a teenager's judgement. It is beautifully written, wise, and it does not feel the need to overstay its welcome with contemporary notions of how long a book should be. The writing speaks for itself: "You want to work spells,'"Ogion said presently, striding along. "You've drawn too much water from that well. Wait. Manhood is patience. Mastery is nine times patience." He spoke softly and his eyes were somber as he looked at Ged. "You thought, as a boy, that a mage is one who can do anything. So I thought, once. So did we all. And the truth is that as a man’s real power grows and his knowledge widens, ever the way he can follow grows narrower: until at last he chooses nothing, but does only and wholly what he must do..." While it was not a given, it is not surprising that the gentleness of the prose is matched perfectly with the elegance of the overall presentation. What was surprising is that cracking open the book reveals an introduction from Le Guin herself, specifically lamenting the immense difficulty she had over the years in simply getting artwork done which was not at terrible odds with the contents. ... until very recently, the books of Earthsea had no illustrations. This was partly my own decision. After Ruth's unique wraparound jacket for the first edition of A Wizard of Earthsea — with its splendidly stylized, copper-brown portrait face — cover art for the books mostly went out of my control. This is the beautiful cover to which Le Guin is referring. Le Guin continues: The results could be ghastly — the droopy, lily-white wizard of the first Puffin UK paperback;... ...the silly man with sparks shooting out of his fingers that replaced him... ... I was ashamed of the covers that gave the reader every wrong idea about the people and the place. I resented publishers' art departments that met any suggestion that the cover might resemble something or someone in the book by rejecting it, informing me loftily that they Knew what would Sell (a mystery that no honest cover designer would ever claim to know). Let us take a moment to appreciate how funny those covers are, and then take another moment to soak up some secondhand embarrassment — somewhere, alive or dead, there are people that told fucking Le Guin how to go about her business, to turn her characters from brown-skinned to white, who perhaps even rejected some early manuscripts. And at least some of them must be aware that Ursula K. Le Guin took a moment to personally light them the fuck up in the foreword of one of the most famous books of all time. This is not the first time that I've seen people in the publishing industry complain about the narrow-mindedness of their peers. Consider the afterword from my copy of Zen and the Art of Motorcycle Maintenance , which includes a letter from Pirsig's original editor, James Landis, who went to immense lengths to have the book published: The book is not, as I think you now realize from your correspondence with other publishers, a marketing man's dream, and if our particular variety of that species... tries to make trouble over the book, I'll just have to supply what pressure I can to overrule him: I'm determined to fight this thing through to the end you and I desire... No sense in trying to kid you by pretending that the book is 'commercial' in the way that term is understood by most people in publishing... However, I have ultimate faith in the book's being good, valuable, which gets us into standards beyond commercial and gets us also into what, to my mind, publishing is all about. That was from the 40th anniversary reprinting. We could speculate about the unknown unknowns — perhaps there are thousands of James Landis' out there, and we are witnessing the one who survived. It is surely possible to publish a phenomenal book and have it be ignored. But for my money, what happened is that Landis has real taste, and that while the modern economy sometimes appears to be filled entirely by bullshit, that only makes it easier for quality to win out if you're willing to stake something on it. But it doesn't come easily, because if you want to do anything interesting , and probably weird, you will immediately be besieged, from within and without, by tedious people and tired ideas. Getting permission from people without soul in the game is oppressive. Consider the final line from Landis above: However, I have ultimate faith in the book's being good, valuable, which gets us into standards beyond commercial and gets us also into what, to my mind, publishing is all about. If you run into Landis and his ilk, perhaps you can do something interesting. You have someone in your corner, who will perhaps take a risk on your behalf, because while they may preserve the skin they have in the game by refusing to be weird in front of their peers, they have to choose between that and their soul. But you will probably not run into Landis. You will probably meet the typical editor, who would be delighted if you offered to write Grit meets The Subtle Art of Not Giving A F*ck 3 . You will meet the real estate agent who will never be swayed by considerations other than the size of your bank account, or the government bureaucrat who will decide that you cannot immigrate because you are two days below the age of 23, or some other tasteless and impotent cog. Even consider startups, a community replete with people who jerk themselves off to the label of entrepreneur so hard that they're at risk of permanent groinal damage. And because we do work with some startups, I will make apologies to the twelve sane startup founders out there. 4 It's distressing how many young people are under the impression that startups are where you go to innovate and assert yourself. You're young, full of optimism, and have minimal obligations. Your only real weakness is your lack of experience, and it is with that inexperience that you... you sign a deal with people who are possibly dozens of years your senior in cunning, law, and finance? To play games on their terms, where you're a total loser if the business earns just enough money to live comfortably on your own terms? Where you have to justify your decisions, where they can pressure you to sell more of your equity, and ultimately appoint a new CEO if you make a misstep? But I digress. To continue the theme of publishing, last year I was approached by an editor at a mid-tier publisher. I made sure to read some of the editor's short stories before our first meeting, and it turned out they were themselves a talented writer with a real passion for the craft. In fact, while looking up the link to the article above, I discovered they published a book as recently as 2024. And they wanted to help me get published! My name, on a book! I knew that it was unlikely to do any significant sales, as blog-writing and book-writing are two very different skills, but still! A book! Things progress well over the next few days, and it turns out the editor shared many of my frustrations with how companies run. Just as it looked like I was going to sign on, the sales team comes with their Opinions, and I must sadly say that they were not sophisticated Opinions. To begin with, they wanted to stipulate that swearing was absolutely not allowed before knowing anything else about me or what we wanted to write. I wasn't actually intending to swear much, if at all, but I also saw no need to limit myself up front. Why agree to play left-handed before we've even tried out the game? More conditions are added. They will not even guarantee that they'll try to get it on bookshelves. I reach out to some other people who have published with them, they reveal that they were forced to write their entire book in Microsoft Word templates. Communications were confused and unclear. Even the payments were described as "opaque". Basically everything you would expect out of the typical tech project. A picture begins to emerge, of a serious editor trying to do their best, surrounded by colleagues who are about as unserious as anything I've described in the tech world. Nothing surprising, but still, why not self-publish? An editor and an artist will only run a few thousand dollars, a tiny investment compared to the time it takes to write a book, and whatever I lack in experience can be compensated for with giving a shit. To quote one of my co-founders, Jordan Andersen, it's only arrogant if you're wrong 5 . In the meantime though, I frequently find myself reflecting on how bizarre the knee-jerk "no swearing" rule was. Sure, there are always going to be some concessions to be made to marketing. I don't just label all my posts "Unnamed Post #7", because I would like to be read at least a little bit. But swearing? Who gives a shit? Is that really going to be the difference between a good book and a bad book? Why on earth would you hear that you've got someone interested in writing a book whose writing is doing millions of hits that very week and then immediately tell them that you know what will sell better than they will? In fact, the only other book they've got that's well-known enough for me to recognize it has swearing in it , so I know it isn't even a principled brand stance. A midwit just went "I am slightly self-conscious about how I appear to my boss" and that was enough to tank the whole thing. I will never stop citing Sturgeon's Law . Ninety percent of everything is crud. That is to say, ninety percent of everything is crud to a practitioner who has taken the time to develop judgement. That is to say there is some distribution of judgement and bravery, and a whole lot of people are clumped in one not-very-good batch. These days, when people become concerned about the seeming arrogance in that statement, I point them at real estate agents and say: "That's how bad many professionals are, but you can only tell when the issue is as blatant as a broken window in your living room." I still have not met a professional whose competence I've been able to verify that will not endorse something close to Sturgeon's Law. The best I've been able to manage is that, if you ignore all secondary attributes required for a job such as empathy, communication skills, maturity, and restrict yourself purely to the mechanical task at hand, some medical subspecialties are consistently okay... but with all those caveats, you'd still never want them to be your physician. In all fields, very weak practitioners seem to cling to a series of practices or principles without a nuanced understanding of why they're doing those things. Consider, for example, a junior engineer. The trajectory of the typical junior engineer is that they will hear a principle like Don't Repeat Yourself, and immediately begin writing functions to generalize two pieces of code that even look similar. This is normal and even admirable — it is a single-objective optimization problem, and they're optimizing! Junior engineers are supposed to be weak practitioners, but this person is trying . They will then become slightly more sophisticated, and learn about premature abstraction, and suddenly we have two principles that are in conflict. Collapsing duplicated code means you are Not Repeating Yourself, but you are probably introducing an abstraction, and now you have a tradeoff between two principles 6 . And if you keep going, you will pick up dozens to hundreds of these, implicit and explicit, and must become comfortable with the fact that you're going to have to balance them all simultaneously via the application of judgement, and you will be wrong sometimes. With all that nuance comes the boon and burden of being able to disregard principles. For example, we use Test Driven Development , but I was recently working on something that required spinning up a headless Chrome browser to convert a HTML document to a PDF. Unfortunately, this is very slow in a test suite and annoying in some CI/CD products for various reasons . Because I have an idea about why I test, and what the value of it is, and how likely this is to break, I made the decision to just not test that bit of the application when running tests in GitHub Actions. Will I regret that? Maybe, probably, but the point is that my rules are there for reasons and sometimes those reasons don't feel like they apply. 7 Truly weak practitioners will come to you with totally degenerate rules or principles. This is the "no swearing" publisher, but it is also the "no dogs" landlord, the "no risk" security guy, the "must have ten years of Git experience" recruiter and I've no doubt that everyone reading this can think of at least one system where they've thought "I can't believe I'm at the mercy of a person that isn't even thinking ". Frequently their rules are not even rules, they're just phrases that competent people used to say, and eventually they became well-known enough to become fake-able signal. Data-driven. Garbage in, garbage out. Agile. All of these may have previously signalled novel thought, and now anyone that's really savvy does their best to not use the phrases because they know how tacky it makes them look, even if they actually use them in meaningful ways . This can even happen when you've bypassed the large, visible, external gatekeepers, such as recruiters. All it takes is one person within an organization that loves talking and again lacks that baseline competency. One of my co-founders, Ash Lally, the infamous Business Jaguar 8 , was on a contract outside the context of our consultancy recently. They are tasked with pulling data from one system into another system, which is about the most boring and typical thing that a data engineer can do. The employer is not technologically advanced and this task is not their core competency, so as is the case for almost all work in this category, the solution is to schedule some code to run once every ten minutes to pull it in. They are working with someone that, to steal the words of a reader, has had a very impressive career in numeric terms, i.e, they're terrible at their job, but boy oh boy have they been doing it for a long time. Ash's counterpart considers pulling the data in every ten minutes, then comes back with: "Event-driven is good for internal system integration." Event-driven means that instead of writing something very simple to grab all new data every ten minutes, you instead write a very bespoke system that detects new events in real-time and copies it over to the target system. This is way more complicated and totally unsuitable for a company that hasn't figured out version control yet. And also totally unproductive, because the data can't be used without another piece of data which has a hard limit of being calculated... once every ten minutes. So the company still has a ten minute delay before anything can be used, plus all the insane overhead. But still, we should hear them out, why is event-driven good for system integration? I can think of some reasons, but I'll never know if they're the reasons this person had in mind, because that information is not forthcoming! They heard those words somewhere from someone authoritative-sounding and they now feel comfortable regurgitating them at other people. But we're going event-driven now! Bonus points, this infrastructure supports emergency services, so you can commit stochastic murder this way! It's like serial killing but you've tricked a whole department into being your co-conspirators! Even when you've passed all the normal gatekeepers, you will sometimes need permission to do the engineering equivalent of tying your shoelaces correctly. 9 Above, I talk about people who have even gotten as far as misapplying principles. As frustrating as that is, that isn't even the worst you can do . Some people never reflect on their craft at all, or do not view it as a craft. The person that says "event-driven is good for internal systems integration" has at least taken a moment to read something, even if it's a terrible LinkedIn post or a Medium blog. Things can get so, so much worse. Remember all your peers at university that would say "I dream of working in HR"? No, probably not, because that sentence has possibly never been uttered in all of human existence. The field is laden to the point of breaking with people that drifted into it because it was the first job they could get that paid white-collar wages for a qualification no more sophisticated than knowing where some of the buttons are in Workday. Some of them, by dint of personality and ethics, are good at their jobs, but they are few and far between, and perhaps most importantly are not systematically produced. Is it actually a surprise, under those conditions, that HR seems to be useless whenever you interact with them? Could we expect any other outcome? It's a testament to the power that so many of them have relinquished to the economy, by dint of being unemployable on the grounds of technical skill or competence , that they bother to get out of bed at all. They don't want to be there any more than you want them there. Jordan, the same co-founder responsible for "it's only arrogant if you're wrong", wrote a single blog post on our company website. During a meeting where Jordan asked for some feedback, we spent some time caught up on this little snippet. I just want to pause and note how fucked this was. While I was an accredited allied health professional at the time, it's fucking ridiculous that a bunch of recreationists were put in charge of dictating how anyone should respond to a medical emergency... And here's what the team was split on — do we swear on the company blog? You can probably figure out where I set on the issue. Go for it! What are you, some sort of coward? But the team wasn't sure, and the truth is that I wasn't entirely sure either. Maybe I can get away with that on my personal blog, but is that too crass? I mean, some people feel it's already too crass here. Will people be scared to take us to their managers? And most importantly, other consultancies aren't doing this , should we be more like them? Eventually, Ricky Ling chimes in (I'm sorry there are so many of us), and his take for Jordan is the Quality-focused take. "If you think it makes the writing better, do it". We still aren't sure, but we know that we didn't quit our jobs and give up all that sweet, sweet salary to be cowards, so we do it. That single post has generated us a huge amount of outreach from cool people despite not going viral or being widely circulated as far as I know, and we almost started prematurely neutering it because a group of people who already deviate wildly were still worried about doing something even a little bit different. Being seen to deviate is extremely hard, in large part because to deviate is to be seen , and the gaze of others is deeply uncomfortable. There's an exercise that actors do, where they sit in two chairs opposite each other, make eye contact, and then one of them just starts saying things that they're feeling. "I am aware that my hands are warm." "I am aware that I am uncomfortable with you staring at me." "I am aware that I want to burst out laughing." This is very, very uncomfortable to do. I've done it three times, for about ten minutes each time, and I cannot emphasize how much we all hated it. From this we can infer that actors are total fucking weirdos, but also that acting as a field has identified that there is something deep to unpack in reflecting on what it is like to be perceived without the luxury of flinching or breaking eye contact. This aversion to deviation and subsequent perception is enough to make some people totally impotent. In the earlier days of the consultancy, I envisioned that our sales pipeline would be something like this: This sometimes does happen, but it has never happened at a company without a really spectacular culture. What happens at the average company or government agency is something to the effect of: "I am working on a project, and we're being scammed by some other consultants. The whole thing is months late, and it isn't going to finish any time soon. Is there any chance you can help out?" I reply, "Yeah, of course, we'd love to. But we'd need an introduction to someone inside the company who might be willing to admit that something is wrong." And this is where, every single time, the person that initially reached out has decided that they don't want to take the risk of being visible. I understand — a lowly engineer suggesting an external consultancy with hot takes is really, really unusual, especially so if they present hard-to-ignore and inconvenient evidence that a project is failing. It has possibly never happened to the average CTO across their entire career. The engineer would be as visible as it is possible to be, perhaps moreso than if they hauled off and punched someone in the face, and during the next round of layoffs they will either be promoted for being weird or fired for being weird. In either case, redundancy is no longer dependent on who is at the top of the list when the CFO sorts the salary column on a spreadsheet by descending. In the past year, I've seen people have huge impacts at companies by exerting some bravery. This sometimes means getting a bully fired, sometimes it means getting the first tech project to work smoothly in a decade. In some of these cases, the person involved was made redundant shortly afterwards for interfering with people's selfish political aims, and other times they were promoted for actually giving a damn (and yes, sometimes for unknowingly helping someone else's selfish political aims). But all of them went in willing to put something on the line. A huge number of employees will venture nothing for their beliefs, and while that is fine or whatever, bla bla bla, they have kids, they're also going to be largely ineffective because they won't change anything big, because big change is novel and weird, and novel and weird might get you noticed, and getting noticed means something is going to happen to you. Our company is really into weird stuff. Our favourite TTRPG is Burning Wheel, an extremely niche product, hundreds of pages long, whose creator refused to release a PDF for years because he felt that it watered down the experience. Our favourite traditional board game is Twilight Imperium , a sci-fi masterpiece that takes thirteen hours to play. For internal projects, we program Elixir, a language with near-zero name recognition amongst engineering genpop that compiles to Erlang, a language developed in the 80s by Ericsson of all places. We're an Extreme Programming shop. Most of my spend this year has been learning material and one-on-one coaching for engineers in the company. We started with six co-founders, something that caused several banks a great deal of consternation when we tried to open our account, and I am now realizing makes it very hard to write blog posts without introducing what must feel to a reader like an endless stream of new names. It gets stranger. We pair program on all work 10 . We have no network drive, just Git repositories where all documentation is written in Markdown, and the proposals that must go to clients are converted to HTML so we can style them with CSS. AI? Not only do we not turn on AI-assistance during programming, we'll crucify each other for copying a StackOverflow example if we can't explain the behaviour with reference to code or core documentation. We contracted Mira Welner this year, internet famous for frontpaging Hackernews a few times as a fresh grad, who described our work as "the opposite of vibe programming", which will make different people have wildly different opinions about whether we're competent. We invite our clients to sip from the Chalice of Madness, wherein we pray that they will find that the Kool-aid is delicious and refreshing, amen. If there is a conventional script for something, we have probably thrown it out the window or seriously considered it. I'm obviously convinced that these practices are good or I wouldn't be doing them, but they have a secondary characteristic that may be more valuable than their originally envisioned purpose. They filter out shoddy, default thinking, and otherwise shake people into vivid awareness. Everyone is constantly immersed in weirdness, and that makes the next piece of weirdness less scary. I mean, we may still fail as a business for many reasons, but it won't be because we weren't thinking , it'll be because we had stupid thoughts , which at least has the virtue of meaning we actually tried. If you had a company policy of "we only hire people that can pass an interview about Burning Wheel rules", I suspect you would hire a stronger team than what the average company manages. At least they'll have something in common and they've demonstrated refined taste in one area. I don't even care if they can program, they'll figure it out. Iroh: What do you plan to do now that you've found the Avatar's bison? Keep it locked in our new apartment? Should I go put on a pot of tea for him? Zuko: First, I have to get it out of here. Iroh: And then what? You never think these things through! Some years ago, I knew a man that was laid up in hospital for a chronic illness. He was not having a good time, but it must be admitted that some of this bad time was the product of a long-running pattern of poor life decisions. C’est la vie. In any case, one day he is having a particularly bad day, and he messages me from the hospital. He's going to leave and pick up a pack of cigarettes. This perplexes me to no end. "But you don't smoke and are almost out of money, right?" And yes, it turns out I had not misremembered. He wanted to start smoking at that moment in time. Now, this is actually a fairly extraordinary amount of effort. Imagine, you're comfortable in a hospital bed, in a terrible mood, and all the normal pressures that lead to smoking are absent, such as peers to pressure you. But ex nihilo , you now grudgingly swing to your feet, fish out your last bit of money (cigarettes are supremely expensive in Australia, approximately a whopping USD $20 per pack), and march off to try and form a financially crippling addiction. Surely you have enough problems, and don't need to go through the trouble of leveraging your executive function to make more of them? After mulling this over for a while, I come to the realization that this fellow felt the need to inhabit the role of the hard-done-by man on the street. And what does the hard-done-by man do? Well, on the television or a play, he would light up a cigarette of course! Probably take a big, long drag off it, then close his eyes and exhale a stream of smoke into the sky as he sighs. It's real cool , yeah, he's a real cool dude. It's all symbolic, y'see? He's destroying his body as if to say "the world is wearing me down so quickly, the cigarettes won't have time to get me, heh". This is practically understandable, in a strange, catharsis-y way. We all know social scripts exist. There are rough guidelines on how much to tip a waiter in the U.S. In Australia, you should stand on the left side of an escalator if you're not intending to walk up it. What I hadn't really thought about was that some of them are so strong and latent that they can spontaneously cause a person to self-inflict a nicotine addiction. I hadn't even really noticed that I had an archetype of the put-upon smoker in my mind, but there it was, and you likely knew exactly what I was talking about. These scripts are adaptive in some situations — for example, well-adjusted men should be aware that the comradely arm on the shoulder is a great deal more appropriate with a male colleague than a female one, and an even better-adjusted person will just not touch their colleagues. But other scripts, especially the ones that are too small to think about or too large to see, drive insane life decisions. When I was studying psychology, almost everyone, including me , picked the course because we weren't sure what we wanted to do with our lives, but the script says finish high school and then take on ten of thousands of dollars in debt. That script is so large that it basically encompasses your whole upbringing. When you try to look at it, you see grey, and think "there is no elephant here, just a cement wall". Or when someone looks for a job they just start sending CVs out, even though that basically doesn't work at all. The assumption that this is how you get a job is so quiet that people don't even realize they're making a decision. They think the decision is whether you should have a one-page CV or a three-page CV, not whether they should have a CV at all. And again, when you interface with a sufficiently large system, they will have their own scripts, and you will be expected to abide by them. Your counterparty will usually unthinkingly apply them, and if you find someone that is willing to actually look at the situation at hand, treasure them. The other issue with going off-script, or otherwise deviating, is that you have to accept that you're going to look extremely silly if things don't work out. Someone, usually someone that isn't taking any risks themselves, will be a dick about it. Let's say that my company does well enough for me to draw a full tech-tier salary in 2026. I'll be praised for whatever I did differently. Six co-founders! My God, he's a genius! You can keep most of them working contract roles, which means your revenue requirements are low, but it only takes them about an hour a week to mobilize their networks for sales! His mind is a thousandfold blade, so keen is his thinking! Sure, now let's say that it collapses in June because a co-founder wants to pivot to a SaaS offering and I don't. Six co-founders! My God, what a fool! Everyone knows there are reasons that VCs prefer two to three founders and no more! A huge risk for a startup are the founders having a falling-out, and the risk increases exponentially with each node in the fully connected network! His mind is being passed around by stoned college grads, so blunt is his thinking! I can skip the embarrassment by doing what everyone else does. If I failed the normal and boring way, by running a non-Extreme Programming consultancy, with one co-founder, that writes Python because everyone else does, selling GenAI bullshit 11 , I would be beyond critique. I'd just say "Gosh golly, sales are hard", and everyone would nod sympathetically. Guess what though, whether or not people point and laugh, they certainly aren't going to pay your rent for you. Who gives a fuck about embarrassment? LaRusso: Do you think I stand a chance at the tournament? Miyagi: Not matter what Miyagi think. Miyagi not fighting. What most of this comes down to, fundamentally, is whether you trust your own judgement, what you're willing to stake on it, and whether that conviction is strong enough to throw away the guarantees that you'd get from conforming. Because you could take the guaranteed money for writing the book, and if you don't really believe that your judgement is superior, perhaps the money is worth it. Readers call me with some frequency to ask me if I think their startup idea is good. Could it sell? Would it work? Should I do it? How the hell would I know, I'm just some guy with a blog and a business that may explode in the next year. But if I were the owner of a $100M company, would I really know any better? If anyone knew, then when you asked them they would steal your idea. But no one knows, so the idea is safe and sound, and deep down the asker must be aware of this or they wouldn't be asking . Or take last week, when a student visited me from a local university to ask if they should drop out of university to run a startup. They really didn't like the idea of a corporate job, found university extremely tedious and their peers uninspired, so on, so forth. They were clearly very intelligent, but also clearly very young. What do you say there? Because the knee-jerk impulse, for fear of being irresponsible, is to say the boring thing without thinking about it. Finish your degree first. Get a few years of corporate experience. Or even, I know you're depressed, but don't quit your job without something else lined up. None of that is necessarily bad advice, but we should view ourselves with suspicion when we think about saying them, because they also absolve ourselves of guilt if things go awry. Who could blame us for giving the conservative line, even if you can easily play the tape forward and see it results in damnation? The advice that people are too scared to give, but which they sometimes really believe, with the usual caveats for a mental health event that has crippled the recipient's ability to see clearly: "What does it matter what I think? Do what you think is best for yourself, and yes, you might lose your life savings. What's the alternative, doing what other people say is best for the rest of your life?" Thank you for reading all the way through. For this kindness, I leave you with a parting gift. Penguin, what the fuck is going on over there? PS: Oh yeah, I put this in to justify writing, hire my nerds or whatever. PPS: Reader and now close friend Phil Giammattei could use some help with a horrible brush with cancer in the family. You can support him here . PPPS: You all crushed Phil's goal, thank you so much for your generosity. Things are obviously Extremely Bad in many parts of the world right now, and it's wonderfully refreshing to see people pull together, even if it is for a degenerate like Phil. I'd also like to take a moment to curse the person that dethroned me from my spot of Top Donation, and to double-curse them for doing it anonymously, embarrassing me further. Nassim Taleb calls this the "antilibrary" , the collection of books that one owns that one has not yet read. Taleb argues that an antilibrary is there to educate and humble, while a library of already-read books has much of its usefulness shifted to signalling erudition. If you were to point out that the optimal antilibrary strategy is to constantly buy books and never read any, Taleb (and I) would call you a nerd.  ↩ It was also a gift. Sorry Ricky, the Red Rising copy you got me alongside this was much better!  ↩ It is endlessly entertaining to me that the cover of The Subtle Art of Not Giving A F*ck , a book so desperately trying to be edgy, censors the the word fuck, achieving a flaccidity that goes beyond simply deciding not to swear at all.  ↩ 100% of startup founders nodding at this.  ↩ It is a custom that whenever I or Jordan call our shot and mess up, we call the other person and loudly declare "I was arrogant and wrong", then accept ruthless mockery.  ↩ It is remarkable how many companies seem to forget that the ultimate value is arguably Working Software, and while all the subsidiary principles may fall out of Working Software when you shake it very hard, you can't do away with it. Why calculate velocity if you know you aren't shipping, scrumlords?  ↩ The scary thing about messing with long-running, almost-mystical practices like testing is that their second-order effects run so deep that I get many benefits that I haven't even noticed, so making these decisions also means I may have thrown away some things I don't understand. It's like becoming convinced that I can leave a candle out of the summoning ritual.  ↩ I am slowly realizing that my company is comprised entirely of fucking lunatics, and I am the cracked porcelain mask of sanity that attends sales calls.  ↩ Our scathing disdain for this has not prevented us from chanting "event-driven is good for internal system integration" whenever we need to annoy Ash, which is probably not bullying.  ↩ We incidentally allow anyone to pair program with us over a four hour session, where you can choose to be amazed at our great team energy, or if you'd prefer laugh at how bad we are at programming, so long as you'd consider writing a nice review if you have fun and see strong evidence of competence. Just email me!  ↩ I am bored just describing this.  ↩

0 views
Julia Evans 10 months ago

"Rules" that terminal programs follow

Recently I’ve been thinking about how everything that happens in the terminal is some combination of: The first three (your operating system, shell, and terminal emulator) are all kind of known quantities – if you’re using bash in GNOME Terminal on Linux, you can more or less reason about how how all of those things interact, and some of their behaviour is standardized by POSIX. But the fourth one (“whatever program you happen to be running”) feels like it could do ANYTHING. How are you supposed to know how a program is going to behave? This post is kind of long so here’s a quick table of contents: As far as I know, there are no real standards for how programs in the terminal should behave – the closest things I know of are: But even though there are no standards, in my experience programs in the terminal behave in a pretty consistent way. So I wanted to write down a list of “rules” that in my experience programs mostly follow. My goal here isn’t to convince authors of terminal programs that they should follow any of these rules. There are lots of exceptions to these and often there’s a good reason for those exceptions. But it’s very useful for me to know what behaviour to expect from a random new terminal program that I’m using. Instead of “uh, programs could do literally anything”, it’s “ok, here are the basic rules I expect, and then I can keep a short mental list of exceptions”. So I’m just writing down what I’ve observed about how programs behave in my 20 years of using the terminal, why I think they behave that way, and some examples of cases where that rule is “broken”. There are a bunch of common conventions that I think are pretty clearly the program’s responsibility to implement, like: But in this post I’m going to focus on things that it’s not 100% obvious are the program’s responsibility. For example it feels to me like a “law of nature” that pressing should quit a REPL, but programs often need to explicitly implement support for it – even though doesn’t need to implement support, does . (more about that in “rule 3” below) Understanding which things are the program’s responsibility makes it much less surprising when different programs’ implementations are slightly different. The main reason for this rule is that noninteractive programs will quit by default on if they don’t set up a signal handler, so this is kind of a “you should act like the default” rule. Something that trips a lot of people up is that this doesn’t apply to interactive programs like or or . This is because in an interactive program, has a different job – if the program is running an operation (like for example a search in or some Python code in ), then will interrupt that operation but not stop the program. As an example of how this works in an interactive program: here’s the code in prompt-toolkit (the library that iPython uses for handling input) that aborts a search when you press . TUI programs (like or ) will usually quit when you press . This rule doesn’t apply to any program where pressing to quit wouldn’t make sense, like or text editors. REPLs (like or ) will usually quit when you press on an empty line. This rule is similar to the rule – the reason for this is that by default if you’re running a program (like ) in “cooked mode”, then the operating system will return an when you press on an empty line. Most of the REPLs I use (sqlite3, python3, fish, bash, etc) don’t actually use cooked mode, but they all implement this keyboard shortcut anyway to mimic the default behaviour. For example, here’s the code in prompt-toolkit that quits when you press Ctrl-D, and here’s the same code in readline . I actually thought that this one was a “Law of Terminal Physics” until very recently because I’ve basically never seen it broken, but you can see that it’s just something that each individual input library has to implement in the links above. Someone pointed out that the Erlang REPL does not quit when you press , so I guess not every REPL follows this “rule”. Terminal programs rarely use colours other than the base 16 ANSI colours. This is because if you specify colours with a hex code, it’s very likely to clash with some users’ background colour. For example if I print out some text as , it would be almost invisible on a white background, though it would look fine on a dark background. But if you stick to the default 16 base colours, you have a much better chance that the user has configured those colours in their terminal emulator so that they work reasonably well with their background color. Another reason to stick to the default base 16 colours is that it makes less assumptions about what colours the terminal emulator supports. The only programs I usually see breaking this “rule” are text editors, for example Helix by default will use a purple background which is not a default ANSI colour. It seems fine for Helix to break this rule since Helix isn’t a “core” program and I assume any Helix user who doesn’t like that colorscheme will just change the theme. Almost every program I use supports keybindings if it would make sense to do so. For example, here are a bunch of different programs and a link to where they define to go to the end of the line: None of those programs actually uses directly, they just sort of mimic emacs/readline keybindings. They don’t always mimic them exactly : for example atuin seems to use as a prefix, so doesn’t go to the beginning of the line. Also all of these programs seem to implement their own internal cut and paste buffers so you can delete a line with and then paste it with . The exceptions to this are: I wrote more about this “what keybindings does a program support?” question in entering text in the terminal is complicated . I’ve never seen a program (other than a text editor) where doesn’t delete the last word. This is similar to the rule – by default if a program is in “cooked mode”, the OS will delete the last word if you press , and delete the whole line if you press . So usually programs will imitate that behaviour. I can’t think of any exceptions to this other than text editors but if there are I’d love to hear about them! Most programs will disable colours when writing to a pipe. For example: Both of those programs will also format their output differently when writing to the terminal: will organize files into columns, and ripgrep will group matches with headings. If you want to force the program to use colour (for example because you want to look at the colour), you can use to force the program’s output to be a tty like this: I’m sure that there are some programs that “break” this rule but I can’t think of any examples right now. Some programs have an flag that you can use to force colour to be on, in the example above you could also do . Usually if you pass to a program instead of a filename, it’ll read from stdin or write to stdout (whichever is appropriate). For example, if you want to format the Python code that’s on your clipboard with and then copy it, you could run: ( is a Mac program, you can do something similar on Linux with ) My impression is that most programs implement this if it would make sense and I can’t think of any exceptions right now, but I’m sure there are many exceptions. These rules took me a long time for me to learn because I had to: A lot of my understanding of the terminal is honestly still in the “subconscious pattern recognition” stage. The only reason I’ve been taking the time to make things explicit at all is because I’ve been trying to explain how it works to others. Hopefully writing down these “rules” explicitly will make learning some of this stuff a little bit faster for others.

0 views
Hillel Wayne 1 years ago

The Hunt for the Missing Data Type

A (directed) graph is a set of nodes, connected by arrows ( edges ). The nodes and edges may contain data. Here are some graphs: Graphs are ubiquitous in software engineering: Graphs are also widespread in business logic. Whitepapers with references form graphs of citations. Transportation networks are graphs of routes. Social networks are graphs of connections. If you work in software development long enough, you will end up encountering graphs somewhere . I see graphs everywhere and use them to analyze all sorts of systems. At the same time, I dread actually using graphs in my code. There is almost no graph support in any mainstream language. None have it as a built-in type, very few have them in the standard library, and many don’t have a robust third-party library in the ecosystem. Most of the time, I have to roll graphs from scratch. There’s a gap between how often software engineers could use graphs and how little our programming ecosystems support them. Where are all the graph types? As I ran into more and more graphs in my work, this question became more and more intriguing to me. So late last year I finally looked for an answer. I put a call out on my newsletter asking for people with relevant expertise— graph algorithm inventors, language committee members, graph library maintainers— to reach out. I expected to interview a dozen people, but in the end I only needed to talk to four: After these four people all gave similar answers, I stopped interviewing and start writing. So far I’ve been describing directed graphs. There are also undirected graphs, where edges don’t have a direction. Both directed and undirected graphs can either be simple graphs , where there is a maximum of one edge between two nodes, or multigraphs , where there can be many edges. And then for each of those types we have hypergraphs, where an edge can connect three or more nodes, and ubergraphs, where edges can point to other edges. For each possible variation you have more choices to make: do you assign ids to edges or just to nodes? What data can be stored in a node, and what can be stored in an edge? That’s a lot of decisions for a library to make! But wait, do these distinctions matter at all? A simple graph is just a degenerate multigraph, and and undirected edge can be losslessly transformed into two directed edges. A language could just provide directed hyperubermultigraphs and let users restrict it however they want. There are two problems with this. First of all, it changes the interface, like whether various operations return single values or lists. Second, as I’ll discuss later, graph algorithm performance is a serious consideration and the special cases really matter . Kelly raised the example of maximum weight matching . If you know that your graph is “bipartite”, you can use a particular fast algorithm to find a matching, while for other graphs you need to use a slow, more general algorithm. [It] ties back to the “algorithm dispatch problem.” Given a Problem P, a Graph G, and Algorithms A, B, C to solve P on G… which one do you run? If we don’t know that G is bipartite, and Algorithm C only works on bipartite graphs, how much time can we afford to determine whether or not G is bipartite? — Kelly The perfect graph library would support a lot of different kinds of graphs. But that takes time away from supporting what people want to do with graphs. Graph algorithms are notoriously hard to get right. In this essay , the inventor of Python implemented his own algorithm. It had to be updated with corrections five times! Every single implementation of pagerank that I compared to was wrong. — Nicole So which algorithms should come with the library? “The amount of things people want to do with graphs is absurd,” Kelly told me. That matches my experience, and the experiences of all my interviewees. It sometimes seems like graphs are too powerful , that all their possibilities are beyond my understanding. “The question is,” Kelly said, “where do you draw the line?” For NetworkX, “the line” is approximately 500 distinct graph algorithms, by themselves making up almost 60,000 lines of code. By comparison, the entire Python standard library, composed of 300 packages, is just under 600,000 lines. 2 With all that, it’s unsurprising that you don’t see graphs in standard libraries. The language maintainers would have to decide which types of graphs to support, what topologies to special-case, and what algorithms to include. It makes sense to push this maintenance work onto third parties. This is already the mainstream trend in language development; even Python, famous for being “batteries included”, is removing 20 batteries . Third parties can make opinionated decisions on how to design graphs and what algorithms to include. But then they’re faced with the next problem: once you have a graph interface, how do you represent it? Let’s imagine we’re supporting only barebones simple directed graphs: nodes have identities, edges do not, neither has any associated data. How do we encode this graph? Here are four possible ways a programming language could internally store it: Different graph operations have different performance characteristics on different representations. Take a directed graph with 100 nodes and 200 edges. If we use an adjacency matrix representation, we need a 100×100 matrix containing 200 ones and 9,800 zeros. If we instead use an edge list we need only 200 pairs of nodes. Depending on your PL and level of optimizations that could be a memory difference of 20x or more. Now instead take a graph with 100 nodes and 8,000 edges and try to find whether an edge exists between node 0 and node 93. In the matrix representation, that’s an O(1) lookup on . In the edge list representation, that’s an O(|edge|) iteration through all 8,000 edges. 3 Graphs with only a few edges are sparse and graphs with almost all edges are dense . The same program may need to do both operations on both kinds of graph topologies: if you’re constructing a graph from external data, you could start out with a sparse graph and later have a dense one. There’s no “good option” for the internal graph representation. And all this trouble is just for the most barebones directed graph! What about implementing node data? Edge data? Different types of nodes and edges? Most third party libraries roughly fall in one of two categories: Offer a single rich datatype that covers all use-cases at the cost of efficiency. NetworkX stores graph as a dict of dicts of dicts, so that both nodes and edges can have arbitrary data. 4 Offer separate graph types for each representation, and rely on the user to store node and edge data separately from the graph type. An example of the second case would be Petgraph , the most popular graph library for Rust. Petgraph has , , and for different use-cases. Bradford used Petgraph for Nosey Parker , a security tool that scans for secrets across an entire history of a git repo. His benchmarking graph is CPython, which has 250k commits and 1.3M objects but only a few edges per commit node. He went with an adjacency list. Supporting many representations has a serious downside: you have to do a lot more work to add algorithms. If you write a separate version of the algorithm for each graph representation, you’re tripling or quadrupling the maintenance burden. If you instead write a generic abstraction over polymorphic types, then your library is less performant. One programmer I talked to estimated that a hand-rolled graph algorithm can be 20x faster or more than a generic algorithm. And this gets into every interviewee’s major complaint. A “generic” graph implementation often doesn’t cut it. — Bradford This is the big one. Many, many graph algorithms are NP-complete or harder. 5 While NP-complete is often tractable for large problems , graphs can be enormous problems. The choice of representation plays a big role in how fast you can complete it, as do the specifics of your algorithm implementation. Everyone I talked to had stories about this. In Nosey Parker, Bradford needed to reconstruct a snapshot of the filesystem for each commit, which meant traversing the object graph. None of the four provided graph walkers scaled to his use case. Instead he had to design a “semi-novel” graph traversal algorithm on the fly, which reduced the memory footprint by a factor of a thousand. I was able to get working a proof of concept pretty quickly with [petgraph], but then… this is one of those cases where the performance constraints end up meeting reality. — Bradford Zayenz raised a different problem: what if the graph is simply too big to work with? He gave the example of finding a solution to the 15 puzzle . This is done by running a A* search on the state space. A state space with over 20 trillion states . If you generate all the nodes, you’ve lost already. — Zayenz Zayenz oversaw one research project to add graphs to the Gecode constraint solver. They eventually found that a generic graph type simply couldn’t compete with handpicking the representation for the problem. Even graph databases, designed entirely around running complex graph algorithms, struggle with this problem. Nicole, the graph database engineer, told me about some of the challenges with optimizing even basic graph operations. If you’re doing a traversal, you either have to limit your depth or accept you’re going to visit the entire graph. When you do a depth search, like “go out three steps from this and find the path if it exists”, then you’re just committing to visiting quite a bit of data. — Nicole After leaving that job, she worked as a graph query performance consultant. This usually meant migrating off the graph database. She told me about one such project: to speed the graph queries up, she left one computation as-is and rewrote the rest as MapReduce procedures. “Which was a lot harder to understand,” she said, “But would actually finish overnight.” All of this means that if you have graph problems you want to solve, you need a lot of control over the specifics of your data representation and algorithm. You simply cannot afford to leave performance on the table. So, the reasons we don’t have widespread graph support: This explains why languages don’t support graphs in their standard libraries: too many design decisions, too many tradeoffs, and too much maintenance burden. It explains why programmers might avoid third party graph libraries, because they’re either too limited or too slow. And it explains why programmers might not want to think about things in terms of graphs except in extreme circumstances: it’s just too hard to work with them. Since starting this research, I’ve run into several new graph problems in my job. I still appreciate analyzing systems as graphs and dread implementing them. But now I know why everybody else dreads them, too. Thank you for reading! Thanks to Predrag Gruevski for research help, Lars Hupel , Predrag Gruevski , Dan Luu , and Marianne Bellotti for feedback, and to all of the people who agreed to do interviews. If you liked this post, come join my newsletter ! I write new essays there every week. I train companies in formal methods, making software development faster, cheaper, and safer. Learn more here . Graph querying languages (GQLs) 6 are to graph databases what SQL is to relational databases. There is no widely-used standard, but two of the most popular are SPARQL for querying RDF triples and Neo4j’s cypher . Ironically, GraphQL is not a graph querying language, instead being named for its connection to the Facebook Graph Search . I considered graph databases themselves mostly distinct from graphs in programming languages, but their query languages show how graphs could work in a PL. The main difference between all GQLs and SQL is that the “joins” (relationships) are first-class entities. Imagine a dataset of movies and people, where people act in, direct, or produce movies. In SQL you’d implement each relationship as a many-to-many tables, which makes it easy to query “who acted in movie X” but hard to query “who had any role in movie Y, and what was that role”. In SPARQL relationships are just edges, making the same query easy. Cypher has a similar construct. GQLs can also manipulate edges: reverse them, compose them together, take the transitive closure, etc. If we wanted to find all actors with some degree of separation from Kevin Bacon, we could write SPARQL cannot give the length of the path nor do computation along the path, like collecting the chain of movies linking two actors. GQLs that support this are significantly more complicated. My main takeaway from looking at GQLs is that there’s a set of useful traversal primitives that a PL with graph support would need to provide. Interestingly, the formal specification language Alloy has all of these primitives for its “relation” datatype. For this reason I find working with a graph representation in Alloy much easier than in a proper programming language. That said, these all work with labeled edges and may not work for other graph representations. Python added a graphlib in 2020. Based on the discussion here , it was because topological sorting is a “fundamental algorithm” and it would be useful for “pure Python implementations of MRO [Method Resolution Order] logic”. Graphlib has no other methods besides , which only takes graphs represented as node dicts. Unusually, the direction of the node dict is reversed : the graph is represented as . As of 2023, nothing in CPython uses graphlib and there are fewer than 900 files referencing it on Github . By comparison, another package added in 2020, zoneinfo, appears in over 6,000 files, and the term appears in 4,000. I’d guess a lot of these are from before 2020, though. Some skimming suggests that all of these custom topological sorts take different graph representations than graphlib, so they wouldn’t be convertable regardless. Graph representation matters. There are two other languages I found with graph types: Erlang and SWI-Prolog . I don’t know either language and cannot tell when they were added; with Erlang, at least, it was before 2008. I reached out to a person on the Erlang core language committee but did not hear back. Programming languages where “everything is a graph” in the same way that everything in bash a string and everything in lisp is a list. Some examples include GP2 and Grape . Based on some correspondence with people in the field, right now this is still highly academic. Mathematica, MATLAB, Maple, etc all have graph libraries of some form or another. I am not paying the thousands of dollars in licensing needed to learn more. I’ve collected some of the comments I received on this post here . Package dependencies form directed graphs, as do module imports. The internet is a graph of links between webpages. Model checkers analyze software by exploring the “state space” of all possible configurations. Nodes are states, edges are valid transitions between states. Relational databases are graphs where the nodes are records and the edges are foreign keys. Graphs are a generalization of linked lists, binary trees, and hash tables. 1 Zayenz : Former core developer of the Gecode constraint solver , and who has “implemented every graph algorithm there is” Bradford : Author of the Nosey Parker security library and inventor of several new graph algorithms Nicole : Former graph database engineer Kelly : Maintainer on the NetworkX python graph library and compiler developer . Adjacency list: Adjacency matrix: A set of three structs with references to each other Offer a single rich datatype that covers all use-cases at the cost of efficiency. NetworkX stores graph as a dict of dicts of dicts, so that both nodes and edges can have arbitrary data. 4 Offer separate graph types for each representation, and rely on the user to store node and edge data separately from the graph type. There are many different kinds of graphs There are many different representations of each kind of graph There are many different graph algorithms Graph algorithm performance is very sensitive to graph representation and implementation details People run very expensive algorithms on very big graphs. No, really. Hash tables are bipartite graphs . This was used to prove performance of cuckoo hashing operations . [return] I derived both computations with cloc 1.96. I ran cloc in (56989) and in (588167). The whole networkX library is ~90,000 lines of code. [return] You can make this more efficient by keeping the edge list sorted and doing an binary search, at the cost of making edge insertions more expensive. [return] NetworkX has functions to convert graphs into other representations but not for working with those representations directly. [return] 14 of the 21 canonical NP-complete problems are graph problems. [return] Not to be confused with the GQL language, a proposed GQL standard that’s still under development. [return]

0 views