Hacker News new | past | comments | ask | show | jobs | submit login
Three Tribes of Programming (2017) (josephg.com)
270 points by ivank on Sept 6, 2019 | hide | past | favorite | 119 comments

This is fantastic and surprisingly close to how I tended to explain computer science to students and graduates:

In Computer Science, there are 3 kinds of problems:

1. The problems that Math gives you: algorithms, data structures. These are the problems you think you're going to solve and sometimes you do, but often we just need a few really smart programmers to solve this and the rest of us can just use those solutions.

2. The problems that Physics gives you: hardware, device drivers, network latency. Sometimes you do systems programming and work close to the hardware. But once again, once one engineer has solved this, most of the time we can just use those solutions.

3. The problems that other engineers give you.

And that is where you're likely to spend most of your time: gluing APIs together, reading code and documentation, and arguing about code formatting.

This is why in so many ways computer science is a social science. Certainly "software engineering" is. Everything you do is going to be about communication. When you write code, you're not just communicating with the compiler and the machine, you're communicating with other engineers. You're going have to craft smart documents, emails and collaborate. Any nontrivial solution will require these skills, so you better start investing in them.

I'm continually surprised at how quickly non-technical problems come to dominate my time on a software project. E.g. my code doesn't work because two business stakeholders have slightly different, irreconcilable notions of what a "customer" is and it has to satisfy both.

Or things as mundane as discover that a third of your coworkers (even seniors) are so much emotion driven that may as well go back to high school in order to learn how to socialize and be professional avoiding jealousy, envy, unnecessary competence or just plainly learn how to work in team and how to follow some sort of structure in an organization.

unnecessary competence

What on earth do you mean by this? It sounds rather like advocating just doing the minimum you can, for the sake of harmony.

I think he/she meant unnecessary competition, rather than competence.

*unnecessary competition, (cannot edit anymore)

What I speak is about individuals trying to compete against its own team to defeat them in some unnecessary priority rather than collaborate and play all together.

We desperately need them to do X for our project to succeed. They have a brilliant and extremely compelling reason not to do X.

Makers who don’t understand 1 or 2 often create slow or insecure code that often results in clear user impact.

For example, I’ve seen diffing / recomputation code operating in O(n^3) or O(n^2) where O(n) or O(1) is possible and necessary for reasonable performance. I’ve also seen extremely poor use of network requests (multiple serial requests) that happen because the developer doesn’t understand network latency and networking performance (in this case with a single data center in the world).

In practice, a great engineer should be relatively well balanced in all 3 aspects and know when to favour one over another (such as the time sensitive case where performance in the code execution is more important than writing something that the next engineer can easily understand).

You can't make it better until you make it work.

But you can start off with an architecture that requires a full rewrite to make it better.

The number of times I’ve seen this sentiment end in a project being late or never ship is easily 10x more than the number of times a project became crippled later because of performance issues.

Improving performance isn't the only way you can make something "better". A system could be architected in a fragile or rigid way that makes extending it or adding new features extremely difficult without a rewrite.

I can't tell you how many times I've seen people "make it work" and create a mess that has to be rewritten later with much greater difficulty than if even the slightest amount of forethought had been given before hand.

Really? I think it's often group 2 that makes insecure code.

I like to remind largely junior engineers I work with that we're basically Dell. We're system integrators. We take the bits that other people have made and glue them together in a fancy box. If they start doing computer science they need to stop for a second and ask themselves if they're really sure they should be doing computer science in case someone else already has and they can just leverage what they've done.

The focus for me is really building appropriate abstractions over the work I do so that people can focus on improving only the vertical slice they need to.

I like this. It's in the same vein as the blog post, but it addresses the only aspect I was truly uncomfortable with: the word "tribe" implies exclusivity, whereas I tend to think of myself and other devs as points in the triangle whose vertices are these tribes.

Computer science and math is useful beyond just algorithms and data structures. Understanding the mathematics behind program construction would allow more programmers to write composable code and more general, re-usable, less ad-hoc APIs; and do a better job of gluing existing components together.

Joel Spolsky talks in an interview about how his bookshelf shifted from 80% theoretical books to 60% psychology books over the course of his career.

Surely his production coding went from 100% to 0% at the same time?

I agree with your three problems, but only if problems means hard roadblocks to achieving your goal.

Much of programming is encoding what you want to computer to achieve and is therefore a rather long process, but not necessarily hard. Precisely specifying how a GUI should look has a substantial amount of necessary complexity, and writing that out doesn't fall into 1, 2 or 3.

You could also argue that that is a separate thing from programming. I don't at all mean to be to be snobbish here, just that it's useful to draw the line somewhere between there. Modeling is not programming. Architecture is not really, either, even if the process can involve programming.

I'm totally stealing this for teaching to my grad students, it's a much better way of stating what I try to stumble through each semester talking about "programming as communication"!

I'm not sure where this fits into your three problems but I spend most of my time thinking about problems that business gives me. Of course, this still underscores your point about social science.

Physics gives us device drivers? ;P

> You are a maker. You build things for people to use

I am a maker. I build things for people to use and maintain.

This puts me at endless odds with the hackers. All three groups suffer from Novelty Seeking and Risk Taking (aka Adrenaline Junkies), but the hackers seem to get it the worst.

My hatred of tools that fall apart the third time you use them goes back to childhood. I don't want to put my name on any of that shit.

And yet...

I'm also quite comfortable and capable performing emergency field repairs on objects real or virtual. I think the difference is I know this is temporary. Single use. When we get back to where there are tools and supplies, we should take it apart and fix it for real. The hacker declares victory and moves on to the next problem.

Where I disagree with the breakdown here is that the makers are also poets. It's just that the medium is different, so it's hard to compare. I think it's safe to assume that the same is true of the hackers.

At the risk of just jumping on a single point:

> I build things for people to use and maintain.

Maintenance. Maintenance. Maintenance. That's the key. It is the lack of that mindset which is killing our home world. Ultimately, it's just expression of not having to pay for your externalities.

It also kills software dev. If software devs were actually held to account for their legacy (software, hah), then we'd have a lot less shitty (and shitty+, shitty++, etc) software.

In context of this, I've always been thinking that software engineers should be held way more liable -- like those of the physical engineering disciplines. In order to enforce good software engineering practice, there must be either incentives or disincentives (carrot or stick) that have clear consequences on the engineer himself/herself. Otherwise there is nothing stopping them from producing bad work. It may be unintentional and the code perhaps is simply sloppy (but still works).

This is just a thought (and may be unpopular): practices differ wildly from one company to another, and between enterprise software vs hacky side-projecty node apps, nonetheless, maybe it's time to standardize software good practices across the entire industry and enforce them, making them not just "good" practice, but mandatory practice.

If you create liability traps, the price of everything goes up and many things do not get made at all.

It's like saying that tents shouldn't exist and people shouldn't use bicycles even though they are great tools for certain jobs.

Nobody wants to pay for space shuttle levels of software engineering. It costs a lot in labor time to produce less results.

The cost of bugs varies wildly. I do not want my FADEC to have the bugs my word processor has but I do want the word processor to have more features.

What is the deal with maintenance engineers thinking every engineer ought to be one? Can't you agree it takes all types or is there something about maintenance that preempts such thoughts?

Edit: Maybe I should go around pretending hackers and poets have the moral high ground.

I think it's contempt for people who won't stand by their work. Maintenance engineer implies a very long term relationship with code but you can't get some self-aggrandizing butterflies to support something they wrote a month ago. The truth should be somewhere in between.

When you're young it's easy to derail your complaints by implying you are not smart enough to appreciate the magnificence of the code. I tend to take Feynman's position that if you're really so great, your solutions will be obvious.

There is certainly room for art in our world.

I'm just saying that what companies sell as products should not be made in the "art" mindset. Is that clearer?

hard agree.

I remember once coming across a 3rd party web API whose documentation stated you could configure something like 50+ settings with it. Only about half of them actually changed the configuration, the other half I had to actively go in and start doing things like shutting down the service, updating various files, and then restarting.

When I realized this I just thought to myself, how in the world does your pride as a developer even ALLOW you to ship something that bad.

Another example is PoSH (Powershell SSH). The author just randomly changed how he does things, and changed the defaults, so one day things that worked before just stopped. You now had to configure it to have the old behavior. WHY!?!

Then I realized that if you issue a shutdown command over SSH via PoSH it would hang until the timeout was hit. I then found myself maintaining a custom version of PoSH to work around the issue. I even went as far as to describe the issue, and my fix, for the author, but to this day I don't think they ever actually fixed it. The day when we can natively use SSH from powershell can't come fast enough.

The point being that things are always so damned brittle. And the worst part is that I don't think it gets better the lower down the stack you get. I've ran into plenty of these types of issues in C and C++, it's a mindset and it drives me nuts.

Openssh server and client are included in windows 10 as an optional feature for a while already.

If you don't watch your users struggling with your product then you can tell yourself all sorts of delicious lies about how awesome you are.

If you have no empathy then you can watch them and dismiss it as user stupidity. Which is never an attractive look.

>I am a maker. I build things for people to use and maintain.

So you're dev ops?

Jokes aside, do you really have a passion for maintaining projects? This is something I deeply struggle with and any advice on the subject I would be deeply grateful for.

I thought I could deal with it and enjoy a project in the long run if it had no bugs, so I worked on some of the code the internet runs on, where even putting in one bug would make parts of the internet go down world wide. (Which I did do btw. Sorry.) I both hated and loved that job, but in the end, even in a "bug free" code base, so maintaining it was only feature requests for the most part, I still lost passion over time.

I switched to Data Science, writing code I know will be scrapped. I write mockups to analyze data. It's a lot of fun! But to me it's just running away from the issue.

How did you gain passion for maintaining code bases? If you have a story, it would mean a lot to me. I'd love to hear it.

You don't need passion for maintaining projects to have compassion for the people who need to maintain your projects (whether or not that's also you).

As you point out, though, some code actually doesn't require maintenance. But at the same time, that's not always the code you think.

> do you really have a passion for maintaining projects?

I don't. I have a passion for clearing roadblocks and that means different things at different times. Sometimes that means automation.

I think you parsed that sentence in a different way than I intended. I think a legitimate handoff is part of building a tool for someone. We have people who run the gamut from rent-seeking to dropping the mic and walking away.

I did interpret incorrectly. Thanks for the clarification.

This post is nice, but...

Rich Hickey and Bret Victor here are squashed into overly simple (and/or wrong) categories whose descriptions go like "the best programs [...] formally prove correctness" and "beautiful code is more important than beautiful UI". Both have been very vocal against these points.

Jon Blow is definitely not (just) in category 2. "But one of the reasons his last game (The Witness) took so long to write was that he wrote his own engine instead of using something off the shelf [...]. I understand". He'll probably have a heart attack reading this deep, deep assumption that creating his own thing slowed down his unique game rather than enhanced it.

As someone who does OCaml (and who maintains ReasonReact), shoving it into the category of "poetry is more important than execution speed" and "code over UI" is exactly what we're going _against_. It sucks to emphasize pragmatism, compile & runtime and UI, only to be shoved back into the "poetry" category.

I get a weird feeling criticizing a blog post that mostly gets the right idea across but then goes e.g. "don't worry, we get that you're a poet and care more about that than real-world execution and we empathize with your different perspective" or "we get that you don't prioritize writing simple beautiful code". Like, I _do_ care and these folks _don't_ abide by what you're describing. There's gotta be a name for this.

Thanks. Author here. I mean, generally I agree - but, any generalization will always be a bit overly general and reductive. The point of this article wasn't to try and make a formal taxonomy; just express an intuition. If I were to revise this article now I think your point is what I'd change about it - I mean, all of us can embody all of these core motivations. (Although I'm not sure we can hold all of them at the same time easily, and I think they're in tension within us). I'm also sure Rich Hickey, Bret Victor and RMS are all more complicated in person than how they're perceived in public.

But extremes are useful to define a scale. In your work on ReasonReact, how much time do you spend thinking about the ergonomics of the users? It sounds like a fair bit of your time and mental cycles go into that. So it sounds like you sit somewhere between the extremes of those camps. I don't think I would have been able to say that sentence without defining overly steriotyped, extreme positions.

And there's lots of interesting thoughts that follow from that - like, what happens when those motivations come into conflict? Eg, users care about feature X, which is going to be really ugly to implement, but desired. What do you do?

Nice to see the author here. Note that I still do appreciate the post. You're also right that establishing simple, potentially extreme profiles isn't the goal but does help with understanding. The nuance I wanted to convey was lost while describing the folks above; I don't think I have much more to add about it, though here are some related thoughts.

My personal answer to your question for me is "It depends. Lemme check what feature we're talking about here". My mentality isn't "nice, an occasion to exercise my principles", and judging from the talks two of the three aforementioned people gave, I'm positive they adopt a similar attitude: happen to take a stance, but don't actively seek it.

When I go over some codebases, I often find flavors of code that smell like someone tried too hard taking a stance. E.g. code that overly future-proofs, code that definitely needs less ad-hoc-ness, code that prematurity optimizes in an obviously naive way, code that tries too hard to use a functional/OO concept, etc. Note that these all belong to different categories in your post, but one thing they share is that they all feel like p̶e̶o̶p̶l̶e̶ ̶w̶i̶t̶h̶ ̶d̶i̶f̶f̶e̶r̶e̶n̶t̶ ̶p̶r̶i̶n̶c̶i̶p̶l̶e̶s̶ ̶s̶l̶a̶p̶p̶i̶n̶g̶ ̶m̶e̶ ̶i̶n̶ ̶t̶h̶e̶ ̶f̶a̶c̶e̶ ̶w̶h̶i̶l̶e̶ ̶l̶e̶c̶t̶u̶r̶i̶n̶g̶ ̶m̶e̶ ̶a̶b̶o̶u̶t̶ ̶h̶o̶w̶ ̶t̶o̶ ̶c̶o̶d̶e̶ folks shoehorned principles back into the project rather than the other way around.

So an alternative way of categorizing things is whether you go from the principle to the project, or vice-versa (aka whether you go from abstract to concrete or vice-versa). A result of that is that Jon Blow and Rich Hickey end up in the same category while Bret Victor and Alan Kay ends up in another (without speaking too much for themselves, and thanks to the nice confluence that is HN, I’d say that this categorization has been empirically verified if you check these people’s discussions with each other).

Also, as computing domains grow, you'll probably need to create many more categories if we cross-cut the way you did in your blog post; on the other hand, this alternative way of cross-cutting, I believe, would stay constant. But hey, that doesn't mean your way of cutting it is wrong. The alternative one might be simpler but more abstract.

Maybe this explains why many people in this thread debate on whether the cross-cutting is fair. If you ask the alternative question "which direction do you work from/to", you might get some better partitioning.

Thanks for the article, I agree that these groups are useful to think with, while I also object to the association of specific people with a particular category. Maybe because I align myself with these people too much, but don't consider myself aligned to one category at the expense of the others?

Yes, I really like this article too but the inclusion of Bret Victor in the first group seemed a little off - from what I've read he seems deeply concerned with human-computer interaction.

+1, I came here to say what you said. Those three categories seem OK as a very rough sketch, but the details in the article feel all wrong.

I've come to almost the same conclusions as the author.

- The first tribe is mostly coming from Maths background, their favorite performance measure is the big O notation.

- The second tribe is coming from Physics/Engineering background, their favorite performance measure is expressed in SI units, most often a duration.

- The third tribe is coming from everywhere else, and their favorite performance measure is customer satisfaction, or in other words dollars.

I think a fourth particularly important tribe is missing ... the Modeler.

This a programmer that models systems (real or imagined) into working computer applications. I suggest that in many cases, the other tribes largely exist to support the creation of these systems.

This includes the systems that track and support your money, taxes, utilities, services, scheduling, reservations and insurances amongst others. The systems that enable you to purchase and consume things and have them delivered within the context of a whole supply chain.

It also includes the modeling of control systems, from the software that runs an elevator, to an airport baggage handling system, to an automated warehouse.

Typically in these, the challenge is in abstracting the problem domain under consideration - the determination of what to produce, rather than how to do so.

Examples: Kristen Nygaard, Peter Coad

Favorite Languages: Java, C++, C#, Smalltalk

Hangouts: Currently suspended due to the focus on problems in the computer and data sciences, and computing infrastructure.

I think this is a good article, but ironically I think all three tribes would actually describe themselves the same way many times (whereas this article implies they'd describe themselves, or what matters to them, differently).

To use an example from the article, I think Jonathan Blow would absolutely argue that he wrote his own game engine because it was best for his user. Whether you agree with him or not, he is whole-heartedly convinced by his assertion that it could not be done in Unity trivially. Having listened to him a fair deal, and his feelings on games (vs. programming of games), I very much believe that he cares a tremendous amount about the experience of the game above quite possibly all else. So, while you can certainly argue that the way he chooses to implement that goal is misguided (I don't believe this, but an argument exists), I don't think its fair to give "The UI is more important than anything else" to the third camp and not his. I think he agrees with this statement, and feels that what gets you the best UI in a game happens to be low level work (to avoid frustrating lag, etc.).

Similarly, I think Bret Victor might take issue with this as well. Much of his work is centered on creating innovative UIs to help people think, and often against the (current) abstract ways of representing knowledge. In particular, from the maker perspective, he cares deeply about empowering people to make things -- less so I would say than some sort of mathematical purity.

All this to say, I think there may be less difference in goals than we think, and more difference in what we believe influences those shared goals.

Re: Jonathan Blow, I don't think it's a stretch to say different/better tools can have a profound effect on the industry and resulting games as a whole. As someone in games, quite a lot of software has had far-reaching impact that influenced games on a noteworthy level. Speedtree, Zbrush, and the substance package have basically defined modern AAA art assets. And while the major public engines have had a profound impact, even things like Source mods, RPG Maker, and Game Maker have had a profound impact in terms of enabling development of breakout indie hits or introducing people to game development as a whole who are now in the industry.

So I don't think it's a stretch to say a performant alternative to C++ with a game engine out of the box could have an impact which has broader reach than speedier development of his next game.

One of the most played games of all time, Counterstrike, started off as a mod.

The logical extreme of camp 1 would be researchers who are more interested in creating Haskell language extensions/conducting research than doing work for which UI/UX is very important.

I think it's dangerous to say, "I don't know much about X, but X clearly wouldn't have worked in this case."

I think most people don't fit squarely in any of the camps. Most people are making compromises between virtues of all the categories, they might just weight them a bit differently.

Fourth Camp: You are a tinker and a smithy. You build tools for other developers to use.

* Source Code: Your code is clean enough for you. Your top priority is thorough documentation and intuitive API design.

* Execution: Critical around bottle necks, like large batch processing and build times, otherwise it doesn't matter. Iterate and optimize based on feedback from your devs.

* Correctness: The program should function exactly how it's described to function in documentation. If something unexpected happens, the error is clearly and concisely exposed to the developer so that they can understand what they did wrong.

* UI: Usually not a thing, but when it is, your users are developers and they should be able to figure it out ...

Personally, I'm a gamedev, super in Camp 3. I've worked with a lot of folks who could care less about product and polish, but love making their colleagues lives easier. It's pretty similar to Camp 3 in the sense of "making for your users", but the skillset and priorities are very different.

Favorite languages: TypeScript

Hangouts: npm, github, anywhere open source code is distributed

I was going to post a comment like this if I couldn't find one! As a DevOps-type engineer who writes mostly internal tooling - I really couldn't relate to any of the 3 camps that the author mentioned, but I can relate to what you wrote. Tooling for developers and opearations / SRE types in general all follow a similar paradigm to what you mentioned.

I'd add to add: Fav languages: Whatever is already installed and easy to deploy and maintain/debug on your target system. For linux systems, this might mean Python, Bash, Go.

Additional Hangouts: Forums about AWS/GCP/Azure tooling, Hashicorp projects, Config Management Software projects (ie, ansible)

> * UI: Usually not a thing, but when it is, your users are developers and they should be able to figure it out ...

There is still an interface that the developers are using, whether it be command-line based, graphical, an API, or something else entirely. And hopefully it is well-designed!

I take issue with him blanket categorizing Rich Hickey and clojure (spelled closure by him none the less) in the first category along the same lines as haskell. These languages are quite different in almost all respects minus being functional. While the focus of clojure is on simplicity and expressiveness as the author does mention, it was fundamentally created to be a builders language and for getting stuff done fast with minimal complexity and headaches. I think it is actually a perfect mix between the first category and the third category, which is why I love it so much.

There is a large overlap in ideas between Haskell and Clojure.

You will also find that many of the people who are interested in Clojure are also interested in Haskell and vice-versa.

In fact, they share enough that it causes a tension because it is a little "too close for comfort". i.e. the concepts they share are quite strong, and the concepts they differ are stark by virtue of being polar opposites.

No, they aren't they same along every axis, but they share enough axes that the crossover is quite palatable.

I feel like I can relate to all of the tribes' value systems, depending on various things, one being time... time of day, time spent on a project, time in my life.

I've come to view many supposed divisions between people this way. There aren't homeless and successful people, so much as there are people that are homeless right now, or people making lots of money right now. People can certainly swing between both. Nothing is forever.

I find this perspective helps me to appreciate more my present situation in life, as well that of others.

Getting back on track, we should find value in the diverse perspectives in programming and find things to learn from them. One of my pet peeves is the programmer who does not have a learning mindset. That toxic behavior transcends the divisions laid out in the article, and is to everyone's detriment.

When you take all three to extremes you get problems, but when you take the third to an extreme you get problems which hurt other people.

Extreme mathematical programming is turning theorems into code; Metamath is an example of this, as is Coq. Nobody uses this code because it isn't meant to be used outside of a mathematical context.


Extreme hardware hackers are either designing missile guidance systems or mirrors which turn your face into a plot of its Fourier transform. If their code explodes, it's either doing so in accordance with a design document taller than you are or it isn't a problem because exploding mirrors are even more fun than the normal kind.

Extreme maker programmers, as the site says:

> Taken to the extreme, this world view doesn't value the beauty in the engineering itself.

Taken to the extreme, this group actively derides good design because good design takes time and Real Artists Ship. Real Artists Make Deadlines, too, and Real Deadlines Are Set By Marketing. You end up with janky crap that looks good but leaks your password to anyone who breathes on it, as sold by people who think being proactive with lawsuits is a good substitute for keeping your data secure. Security Through Suing Anyone Who Says It Isn't Secure, in other words.

Bah, I love Lisp (particularly Clojure), have used (and rather liked) Ada in the past, but I'm not sure I'd consider myself in the first group: "Applied Mathematics."

I fancy myself more of a maker (I like making useful software) who happens to dislike like Python and Javascript. And also Java. Because the lot of them are inelegant and I hate reading and writing them.

I believe this is true in all fields, not just programming.

- Tribe 1: the art component wins.

- Tribe 2: the science component wins.

- Tribe 3: the business component wins.

Your life is easier when you belong to tribe 3. I also believe that you can't choose your tribe.

Robert Kegan developed a theory of adult development. He identifies five stages. Stage 3 can be described as communal, stage 4 as systematic and stage 5 as metasystematic. These are modes of thinking and describe how you relate to others, how you make sense of the world, etc. He says that most adult people belong to stage 3, some to stage 4 and very few to stage 5. He also holds that higher stages include the capacity to think in lower stages and are really better, in the sense that they increase your capacity to make sense of the world.

I believe that the three groups mentioned in the article map pretty nicely onto this framework and that, while you may not be able to choose your (maximum) stage, you can over time progress into higher stages.

I don't think that you can't choose them, to me which tribe you consider yourself in reflects your ideals in software, and that may change over years.

Your tribe represents your personality. While I believe that belonging to tribe 3 could make my life way easier, unconsciously, I'm always leaning to tribe 1. I could resume my life with this sentence.

The second tribe sounds more like engineering than science though

Similarly, I think there are only three versions of software.

Version 1 is what you write fast, to ship it quickly. Corners are cut. It isn't even held together by duct tape and baling wire. It is glued together with bird spit. But it gets the crucial first dollar of revenue. Version 1 is programmed by hackers.

Version 2 is what you write more slowly, painstakingly, to replace version 1 before its innards inevitably spill out onto the pavement. Version 2 is paid for by version 1, but is programmed by the math-poets, the software "engineers". It is very elegant and clean, but doesn't always do what the customer needs. There is zero technical debt. People weep when reading the code, it is so beautiful. But it still doesn't export the management report to Excel yet.

Version 3 is what you get after version 2 has been in production so long that many of the conscious design decisions introduced by forward-thinking architects have been patched out and replaced with simpler things that just work, and are easy to maintain. The ultimate goal of version 3 is to replace itself with a shell script, and then take a nap until a new requirement or feature request comes in. It does everything the business wants, but everything is a massive wad of cruft, and there are legacy bits that no one wants to touch.

The number reported by the software has nothing to do with this. A lot of software never gets out of version 1, or goes straight from 1 to 3, or skips 1 and starts at 2.

What a delightful piece of writing! The three catagories really seem to fit. It explains the frequent arguments about electron vs native, new JavaScript libraries and battle tested C. Wonderful and insightful.

> I did a Haskell short course late last year and I challenged the main instructor. I told him "this is all well and good, but I bet I can still make useful software using my practical languages faster than you can". He said no way - using haskell he was convinced he could implement anything I could implement, faster and better and with less code. We didn't test the claim - but I still wonder - is he right?

OK, here's a problem. Read a file of text (the name is to be passed in as a command-line parameter). For each line, if it begins with a number, print out the number.

I'd use Perl, and it would take me one or, at most, two minutes. It would take me seven lines, only because I put my curly braces on their own lines.

Now, I picked a problem that is a better fit for Perl than for Haskell. But that's kind of the point - there are problems that are a better fit for other languages than for Haskell, and when you hit one, you're better off writing the program in a language that fits better.

Haskell is actually one of the greatest text handling languages out there, and will beat Perl5 on most such tasks. (Perl6 was made similar to Haskell, so none would beat the other.)

This one contrived example does favor Perl, and will beat Haskell by a small margin. But as soon as the user says "Oh, sorry, I was mistaken, I needed the number and the next letter" or something like that, Haskell is on top again. As Haskell is one of the greatest languages for handling "Oh, sorry, actually..." requisites, and Perl one of the worst.


As long as the "actually..." only needs a small change to a simple regex (as in your example), perl probably wins the "actually..." game as well until you pull in enough libraries that the Haskell looks a lot like the perl. It's when the regex starts getting overcomplicated and the Haskell breaks out parser combinators that Haskell probably moves into the lead.

As you say, though, the margin perl maintains is small.

I think marcosdumay's claim is that Perl is less editable than Haskell. That's arguably true, though I'm not sure that editing a simple regexp in a simple script actually shows the issue.

Yeah, I agree with the broader claim. IMO well-structured Haskell will tend to be easier to maintain then well-structured Perl, and poorly structured Haskell will tend to be easier to get well structured than poorly structured Perl.

I just thought the express claim being made significantly oversold it. Whichever approach you take with the Haskell in the example under discussion, modifying the Haskell is not easier than adding a handful of characters to a simple regex.

Actually, that problem sounds fairly well-suited to Haskell, because it's essentially a series of pure transformations. My Haskell is quite rusty, but I imagine the program would look something like:

    mapM_ putStrLn $ filter startsWithNum $ lines $ readFile (args !! 0)
        where startsWithNum = ...
Still, I agree with your point -- no language can be optimal for every problem.

You're printing out the line, not the number. You want `takeWhile isDigit`, followed by `filter (not . null)`.

I don't disagree with your thesis, but Haskell isn't too bad here - it took me one or two minutes and is somewhere between three and ten lines depending on how I break it up, including imports. IMO, it's uglier than the equivalent perl but ymmv.

Seven lines is even a bit much. You could do it all on the commandline if you don't mind a bit of ugliness, and all Perl programmers should be used to some ugliness.

  perl -ne 'if (/^(\d+)/) { print $1, "\n" }'
Put the list of input files at the end of the line.

    grep -oP "^\d+"

  grep -Eo '^\d+' file

The article claims that most professional software engineers are "makers" - people who build things for other people to use. I would put myself in this category, but I really struggled when I was a professional software engineer because the job seems to be set up for "poets" and "hackers", not for "makers".

Once I've finished building something, as a "maker", I want to be involved in communication with customers and to see how my work is being used. If I've done the hard work of programming something that's useful to others, the reward I need is to see how useful they are finding the thing I've made.

However, for a professional developer the reward for finishing a programming task is just "more programming". I can see how this would appeal to "poets" and "hackers" - it gives them the opportunity to "write more poetry" or "do more hacking" - but not to "makers".

I don’t buy this.

I am a mathematician who makes things and uses math to understand how the code executes. Execution is not an implementation detail to me.

Instead of thinking of them in nice ways think of the by their pejoratives. Architecture Astronauts, Premature Optimizers and script kiddies. You personally are more of a premature optimizer than an Astronaut. Makes sense that there would be lots of mathematicians and physicists in the optimizers. I'm an Astronaut mostly myself.

Me personally?

I think it’s weird as fuck that you are telling me what I am.

It is an implementation detail when you go to the extreme. Most people are not segmented this rigidly though so of course they worry about execution as well as the high level mathematics. But most of the high level math and designs give a high level view of everything.

Category theory and type theory don't fit cleanly with assembly language (the implementation detail).

Additionally at the very fundamentals of mathematical CS: the Church–Turing thesis doesn't describe anything about the real world. It says that the implementation of a true lambda machine vs. a turing machine are essentially the same thing, the thesis does not describe how it's basically impossible or extremely hard to build a true lambda machine.

To be a mathematician computer programmer, you don’t have to use the Church-Turing mental framework all the time. Sometimes it’s useful and sometimes not.

Of course you don't. I never said you did. In fact I would argue you never think about this isomorphism 99% of the time.

I'm just saying that a big portion of the math doesn't describe the real world implementation details.

As I said the Church side of the theory doesn't have a real world machine equivalent. We have machines that move things and save things but we don't have a physical machine that represents the concept of a function call. What we instead have is a Turing machine that emulates a function call, not a true simulation of it.

Clearly these camps are meant to represent extreme points in the developer space. It's not meant to pigeonhole all developers into one and only one of them. Of course most people sit somewhere between these three camps.

I don't know all of the examples cited, but bringing up Bret Victor in the sentence immediate following "Beautiful code is more important than beautiful UI" surprised me.

Up and Down the Ladder of Abstraction is still one of my favorite examples of an interactive webpage, and is beautifully elegant in how it integrates with and supports the text.


It's cleanly designed as does exactly what it needs to. Hard to beat, IMO.

Except that I can't scroll the page, because the car-driving illustration at the top hijacks the arrow keys.

Bret Victor seems badly miscategorized. He obviously cares more about people than code and validates his ideas with prototypes written in javascript. I would place him squarely in tribe 3.

I'm clearly primarily a maker: I make applications for users, mostly websites, and I care about them being easy to use and useful to the user. I also care about easy of maintenance, and therefore about clean code.

I notice I do strongly identify with the Poet/Mathematician, I'm just not one in practice. I do love elegant code, algorithms, data structures, code that's concise, logical and easy to read. I love that many programming languages have become more functional. I wish I could do a project in Scala. I wish I understood Lisp.

In the end, though, I don't care as much as the real Math/Poet. I don't care for Scala's over-the-top Turing-complete type system. I don't care for proof of correctness. I care that my code works and looks good and is easy to maintain, and joyful to work with, and those are practical matters for makers.

I also appreciate the work of hackers, but mostly because their compilers and VMs and OSs make it so I don't have to worry about those things. I've programmed in C, but I love not having to worry about memory allocation anymore. I want my algorithms to be efficient, but I don't pretend I can reinvent an existing algorithm and implement it better than the standard library has already done for me.

So I don't see the strife, I see different roles. Makers make the end-user applications, but to do so, they use languages and programming principles designed or influenced by the Math/Poets, and they run on efficient and secure platforms built by hackers.

We need each other.

This type of article is like politically targeting citizens, their purpose is not to unite but divide...

Hack, I started as a FE intern in Amazon, originated Amazon Kinesis, built tools for managing google's data center network software, Borg core and user library, and now other stuff.

My work as a programmer constantly change. Am I in any tribe then?...

The tribes exist and people can straddle more than one.

I would say you're not a poet though.

Hmm, thought-provoking. I take issue with this post if it's proscribing all programming into these three camps. Most notably, I'm not sure how important camp #1 is, and I get the sense that there are several separate camps buried in #2 and #3. Another commentator makes the point that there's the smithy tribe, and I think that's a great example. At the end of the day, what it is that the code does seems to be variegated and broad enough that I look at #2 and #3 as two dimensional axes with a huge amount of sub tribes in between. There are definitely parts of #1 there, for sure: I think it's how we got to the current popularity of Python and Ruby, and I also think it's how we got from initial versions of JavaScript to ES6 onwards and TS.

I'd consider myself almost entirely between the 2nd and 3rd "tribe", and I very much disagree with this:

In modern app development our computers are fast enough that this kind of thinking isn't really important any more.

Thinking it doesn't matter is how we end up with things like instant messaging clients using billions of bytes of memory and billions of CPU cycles to receive a dozen bytes of text and display it on the screen, and when every application on the system wants to consume like that, none of them can, and the result is unhappy users.

That said, from my experience it often turns out that the simplest code is also the most efficient and elegant as well as being likely to be correct, so from that perspective I'm essentially valuing all 3 tribes.

You say you're between 2 and 3, but everything else you wrote in that comment puts you pretty squarely in #2.

I find myself constantly split between camps 1 and 3. Whenever I try and get into game development, #3 pulls me to use Unity, then #1 gets nauseous and has me start writing my own (high-level) game engine, before I just give up.

Rust has been fun because it allows me to indulge in the good parts of #2 without totally losing my sanity. It's not great for #3 though.

I don't think most people fall into just one camp, but these three dimensions make a really useful "personality test" for programmers, and do a good job explaining conflicts like those mentioned by the author.

If, to the first tribe, "[T]he source should read like poetry - dense, with very few lines of code needed to express an idea", how can you even bring up Ada.

This is the kind of piece I am happy to forget about as soon I stop reading it in the middle of the page, because its basically strong opinions on how pretty much everybody should see everything in CS and the whole industry in general.

I mean, "cool". You have ideas, but everybody has one, I have mine and I guess there will be someone with even multiple ideas on the matter. So we will not ever be able to agree, point.

So why bother?

Except he's largely right. His tribes are real things, as real as the dichotomy between SQL admin and python programmer.

I know what you're talking about though... Lots of blog posts talk about their own ideas about the industry that are largely irrelevant. But if you touched all the technologies he has listed in his write up you'll see he's completely correct. He's not speculating about something. This is reality.

Good article, though Ada is misplaced there. It is more of a maker’s language. It just has a formal proving add on (SPARK) available to test correctness because of its use in mission critical software where correctness really really matters. People who love Haskell, lisp, etc. despise Ada.

> People who love Haskell, lisp, etc. despise Ada.

I guess I'm not a person, then? All three are great languages. (Well, language families, in the case of Lisp.)

> People who love Haskell, lisp, etc. despise Ada.


Ada code is not very beautiful nor mathematically elegant. I think _despise_ is probably too strong but all the things people like about Haskell and Lisp are not in Ada.

I think the author probably thinks Ada's type system is more powerful than it actually is (or is just thinking of SPARK). Ada is basically just verbose C with a slightly nicer type system and better aliasing rules.

I think that in imperative programming, like in Ada, the mathematical elegance comes from ensuring the post-conditions from pre-conditions and maintaining invariants and so on.

I'm seeing a new generation of kids coming out of school who are just pissing on those techniques: only functional is mathematical, and the rest is outdated, intractable garbage that causes software crises and meltdowns.

That's reasonable (and I actually do like Ada somewhat) but the satisfaction of figuring out a nice algorithm in APL and writing an equivalent in Ada are just… not the same.

Though I'm not really sure I'd call maintaining invariants and pre/postconditions mathematical elegance per se, it feels like good engineering. Like you've built something that's solid.

I love Lisp, and I don't despise Ada. I mean, I would never pick it over Lisp for a new project (well, I can think of one or two very narrow niches where it would probably be the most appropriate choice), but I would rate Ada above, say, Java, C++, and Go.

Very interesting article, even though I'm not a fan of Alan Kay anymore due to the disaster of the STEPS project: a research project on how to better create software which results in papers and demos but not (or very little) software sources???

* language wonks * systems programmers * product engineers

nice terminology and nice categories

Very cool article, but also a little depressing. I probably fall mostly into the "poet" camp and it often feels like the industry is setup to beat people down who approach code that way.

I like this breakdown. I want to make a radar diagram of my personal weighting of these three groups, and put it on my resume. I think, something like 75-15-10.

kloviaclinks com hack tools sent me $75,000

I apparently fall into the latter tribe and feel the need to justify myself, so begin rant!

There may need to be a fourth tribe? I write my programs to accomplish tasks for the user, but I use tribe A and tribe B languages to get there as they make the computer 'smarter' while I'm designing and coding.

My programs should encapsulate and execute whatever work needs to be done as quickly, safely, and correctly as possible so the user can get on with their day. After all, programs exist to accomplish tasks for people, whether directly (my app code) or indirectly (memory allocators).

I try to design/code for the scenario of a new user who knows logically what task they want to accomplish, but not how to get the computer to do that task. My programs should guide the user like a travel map. You are here, you want to go there, and you need to do the following things to do so.

This means if they are missing or have malformed input, I tell them what input they are missing and what the program expects it to look like, along with trimming leading/trailing spaces.

Nobody likes a picky program, like the accounting system running on that one AS/400 in the basement that MUST have a CSV with exactly 15 columns and no more than 32 characters per column (and don't even think about using commas anywhere) or the whole thing silently fails after 12 hours.

As the user learns how the program works, they don't see/need the guides any longer as they know more and more of what they are doing. They want to speed up. Binding keyboard shortcuts to every menu option enables advanced users to breeze through the program from muscle memory.

So what languages do the mythical fourth-tribers use, those who are fine with standard libraries and not sorting binary trees, but don't countenance Electron web bloat or ever-vanishing discover-ability/accessibility/readability sacrificed on the altar of 'mobile first design'? Over the next 3 years, I plan to learn the following high, medium, and low-level languages so I can be productive in each domain, that way wherever my users are, I can empower them to rule their machines like a boss.

F# is great because of features like pattern matching, static types, and immutability, which all combine to uphold the 'pit of success'. Other languages tend to uphold 'check it all at runtime, cause I won't check it for you'.

Rust is a low-level language without the apparently rampant memory leaking remote code execution undefined behaviors of C or C++. Writing secure C or C++ code is just about impossible for experts, let alone curious beginners like myself, so why even bother? Rust it is.

Due to its trendiness (okay, more like more active community) Golang just took over Free Pascal for my next up middle level language. It sits between native low-level Rust, and JIT high-level F#, and it features easy parallelization and has just one or two ways of doing things, reducing code complexity.

Free Pascal and Erlang are on the list too for historical and always-stable-forever reasons, respectively.

This is simplistic. There's way too many tribes. Programming has embedded itself into tons of domains. <Domain> x Hacker is the number of tribes that we have. Language Hacker, Security Hacker, Frontend Hacker, Ad Tech Hacker ....

The tribes describe domains within programming devoid of external details. Security, UI and ads are external as these can be applicable on things outside of programming.

Most people are makers and hackers.

The poet is a rarity.

I work in a golang shop and when I tell people that json and unions are hard to work with in GoLang because it's missing an essential part of the poem (the coproduct) I get blank stares. Not one person knows what I'm talking about.

I think of it as the next level. Everyone starts off as a maker or a hacker, then if or when you get really good you discover the poetry behind all of it. Most people don't ever get that good though. All they are concerned about is the next implementation detail

For sufficiently complex and large programs like writing an operating system, writing a computer language... you need to be a poet and a hacker.

Makers are a dime a dozen. In the end everyone is "making" something so everyone is a "maker" in a sense. It's just the "makers" described in the article don't know how to hack or write a poem so they just concentrate on delivery time.

Anyone who isn't part of all three tribes needs to find a new job NOW!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact