1. 87

  2. 13

    Reading this made realize I don’t see myself in any of the 3 groups. I’m probably closest to a “maker”, however, the author seems to tie that somewhay to UI and “front-end”.

    I work on line-of-business systems that tend to be large and complex. In that, I most consider myself a modeler. I’m primarily about modeling systems, real and imagined, into a working program, but not through the lens of a UI (or a relational database model).

    Instead, I see functional requirements for a large, complex system being implemented in an object-oriented “domain model”.

    Am I just a dinosaur, and lonely group of one, these days?

    1. 40

      Am I just a dinosaur, and lonely group of one, these days?

      I think the author is just wrong. People really like putting things into neat little boxes, but I would guess there are more than 3 types of programmers out there.

      1. 15

        I’m going to go one further and say these 3 “tribes” are just different ways of thinking that anyone can adopt at any time, or depending on the situation. I could plausibly claim membership of a different tribe every hour of the working day.

        1. 7

          To me, that flexibility is one of the most rewarding things of the profession: I can inhabit the mindset that best fits the problem I’m currently faced with, and I find my best ideas often by flipping to another perspective.

          1. 5

            Indeed, in fact the thing that would most likely make me say someone isn’t a “real programmer” is not their membership in the “wrong tribe”, but rather their inability to switch between all three of these modes as appropriate.

            1. 2

              I think the difficulty lies in that the initial discovery of each tribe is met with the revelation of, “ah, I’ve found the way to build software.” Then you sit with it for a few years and start to see the weak spots.

          2. 13

            Agreed. This is an arbitrary distinction and many programmers don’t tend to fall neatly into one category or the other. As a Scheme implementor, I believe “camps” 1 and 2 are not mutually exclusive, and in fact there’s a long history of programming language implementation research that tries to bridge the gap between beautiful mathematical constructs and how to make a machine execute it as fast as possible. In fact, this is the most interesting part of PL implementation!

            1. 3

              not to mention programming language and library design as the user interface you present to other developers.

              1. 4

                Absolutely, that’s more the “craft” or engineering aspect of programming, which fits better in the third “tribe” from the article. You need to be able to work on and balance all three aspects, really :)

            2. 4

              I agree with that. Furthermore, categorizing in general throws away information and that may or may not be suitable depending on the context. Perhaps a better approach would be to identify different traits of programmers and treat each of them as a continuous variable. Based on that it would be possible to categorize less arbitrarily (e.g. by finding clusters in the data). This would be a more data-driven approach and one would obviously need a representative dataset for that.

            3. 11

              No. As an experienced software person, you simply have to divide your time into multiple heads-paces.

              Sometimes you can really appreciate something like this:


              Other times, you might just do lists:sort(A++B), and yet still other times you would be like no you really can get away with lists:merge(A,lists:sort(B)).

              That’s ok. It doesn’t make you alone, but it can be lonely: Most teams in my experience have just one of you, and even in a large company there are likely to be very few of you.

              The article may be written by someone just discovering these different head-spaces exist and jumping to the conclusion that they fit a taxonomy, instead of more like a venn-diagram of considerations that go into implementation and design. That’s unfortunate, but it doesn’t mean there isn’t some good stuff to think about.

              1. 5

                I think this post would make more sense if it focused less on UI and more on shipping things. This would also avoid the awkwardness of writing “Bret Victor” below this:

                How the code interacts with humans is a separate consideration from its implementation. Beautiful code is more important than beautiful UI.

                I think I am personally a bit of all three, naturally trending more towards 1 but trying to be more like 3.

                1. 3

                  Yeah, I had a similar feeling when reading this. I have mostly worked on HPC systems which are used for scientific simulations, and my primary concern is helping scientists do that. I write software in the course of building and maintaining those systems, but if I could make “simulate scientific problems” work without writing any software, I’d do that instead.

                  Or, as a friend of mine put it: computers are just a means, not an end.

                  1. 1

                    Reading this made realize I don’t see myself in any of the 3 groups.

                    I’m glad I came to the comments and saw this as the first line of the first comment. I absolutely feel the same way.

                  2. 10

                    I enjoyed this. Of course most people won’t slot neatly in these tribes, but it seems a useful way to think about where you and others stand personally, and how your focus changes with time.

                    While I share a good part of the doubts against average industry front-end development, I have to say that that part came across a bit too negatively. You can also find plenty of people wanting to make something useful outside frontend web dev, and that got lost a little here.

                    1. 2

                      Agreed, but I just ascribed that entire section to the colour of people who say “I don’t care as long as the client/user is happy” and maybe considered the examples as things the author has seen in that group.

                      A lot of programmers don’t like that guy, but myself being that guy: I know that formalism can reduce surprises for that client/user, and that sometimes the hardware-level decisions can make a huge difference in the balance of costs to acceptance.

                    2. 9

                      I think this person would say I’m tribe one. I’m not experienced with the specific examples he gives, but I know enough to claim they’re inconsistent.

                      So I asked how his prover would discover that the function had the wrong name, and he got delightfully flustered.

                      That’s easy: it wouldn’t. “Correct” means a very specific thing in formal verification. Your code is “correct” only with regard to a specification. If you specified that function as “addition” and proved it does “addition”, then it’s “correct”, even though the name is wrong. This is one of the reasons we make it clear that verification is not validation, and a correct implementation does not mean a correct specification. You don’t get to skip code review.

                      Correctness: A program is correct if it implements the spec exactly. The best programs use tools like Ada to formally prove correctness.

                      Ada isn’t a prover. It’s a programming language. It’s not even provably correct. SPARK, a specific subset of Ada, is provably correct. This tastes like an Igon Value to me.

                      Execution: How the program is executed by the computer is an implementation detail of the compiler. It is more important that the code is simple than the execution is fast.

                      Favorite languages: Haskell, Lisp, ML (Ocaml, etc), Closure [sic], ADA, [J, mentioned earlier]

                      In Ada you can specify the exact range of bits each field in your record uses. And while J doesn’t let you manipulate memory or anything, J programmers are obsessed with performance. Any J question on the newsgroup will spark a weeks-long discussion of how to shave 5% off the memory usage. I mean, we have pages of special verb combinations that trigger hardcoded optimizations when you use them.

                      1. 2

                        “Correct” means a very specific thing in formal verification.

                        It’s really unfortunate terminology, partly because it over-promises and partly because it causes some amount of self-selection churn as people think they care about it but find out they don’t. Or vice versa.

                        There’s a style rule for writing about avoiding words ending in -tion or other such generic suffixes. I think it also applies to naming things. Perhaps judicious use of the word “property” would help.

                      2. 6

                        I miss a very utilitarian business-oriented group. My code is valuable as long as it generates business value. The means are secondary.

                        1. 4

                          As a wise K sage once told me, “I like money.”

                        2. 6

                          So I asked how his prover would discover that the function had the wrong name, and he got delightfully flustered.

                          It’s not the wrong name. It’s the correct name, written by a programmer with the flu.

                          Seriously though, the software craftsmanship approach to meticulously naming things just falls away when you use a good type system, and this is partly because coming up with descriptive names for various data structure traversals and other kinds of functions is really hard.

                          It’s common that a programmer will ask something like:

                          hey, where can I find a function that does

                          :: [(a, Maybe b)] -> [Maybe (a, b)]

                          What would you call that?

                          I realise this isn’t really the point of the article, but to me this doesn’t sound like the “aha, gotcha!” that the author seems to think it is.

                          I also get that programs are meant to be “written for humans first”, but on balance I think I’d rather work with a program where summation is provably correct and inappropriately labelled than vice-versa (not that we actually have to choose between the two).

                          How the program is executed by the computer is an implementation detail of the compiler. It is more important that the code is simple than the execution is fast.

                          Of all the languages I have used, Haskell is the only one where I’ve fairly often seen algorithmic complexity included right there in the documentation. My colleagues at my Haskell company discuss the big-O of various parts of their implementation.

                          Furthermore, it is true that it is generally more important to be correct than to be fast. You can’t build a business by very quickly not solving your customers problems.

                          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”.

                          Stop this. It’s embarrassing.

                          And if you just want to ship a product, you don’t care. In javascript (third camp), there is no integer type at all. JS just uses floats for everything. And if they overflow, tough luck.

                          This is completely wrong. I “just want to ship a product”, so I do care. Those little correctness details stack up over time. If they’re all just a little bit wrong, as your software grows it will become [opinion here; no hard data] exponentially more unreliable and exponentially more costly to maintain.

                          Ultimately code is code. Even though we have different reasons for writing software, what we write is (usually) compatible. And even when its not (looking at you, Haskell) - there’s always a lot of ideas we can learn from and steal.

                          …What does this mean? In what way is Haskell “incompatible”?

                          1. 10

                            Engineers have a pretty reasonable approach to names. Common universal categories have names like lathe, plane, screw, while more specific instances get names like “DIN 335.” Coding has a kind of metaphor sickness where we believe that in order to be “intuitive” we need to give things names from reality, but since our field is so abstract then we can only really borrow abstract and pointless words like “manager” and “object” and “handler” and so on. The problem of naming is not just a simple matter of being clear and careful, it’s a deep poetic issue—how do words arise? How can we communicate both precisely and correctly?

                            Engineers also tend to have a great respect for mathematical fundamentals and not see them as somehow antithetical to building.

                            1. 1

                              I feel torn by your post :)

                              The problem of naming is not just a simple matter of being clear and careful, it’s a deep poetic issue—how do words arise? How can we communicate both precisely and correctly?

                              Could not agree more

                              Engineers have a pretty reasonable approach to names.

                              Ime the average engineer, even many good engineers, are quite bad at naming.

                              but since our field is so abstract then we can only really borrow abstract and pointless words like “manager” and “object” and “handler” and so on.

                              Agreed these are terrible names 99% of the time. But are you claiming there’s no other alternative? Because, again ime, there almost always are better ones:


                            2. 1

                              Seriously though, the software craftsmanship approach to meticulously naming things just falls away when you use a good type system,

                              Implementing ‘add’ and accidentally naming it ‘sub’ is not an issue of ‘meticulous naming’. The whole point of the example is that no prover, of which a type checker is an example, can prevent this kind of mistake, so saying it ‘falls away when you use a good type system’ is begging the question.

                              A type with sufficient complexity to prove that

                              square :: Int -> Int
                              square x = x**3

                              wrong is as complex as the implementation itself and equally likely to be wrongly defined. More general: there is a large category of errors that no type system can fix for you, because if it could, you would need to start independently validating the type definitions and you’d be back to square one.

                              1. 2

                                Yes, I am aware of all of that.

                                My point was — as I already had noted in my comment — that the author has drawn a false dichotomy.

                                Correctness does not come at the cost of sensible name choices. We can have both.

                                1. 1

                                  I don’t see them draw that dichotomy. What do you read as an argument that correctness comes at the cost of sensible name choices? I see them tell a story where their friend argued they could prove all their code correct and the author gave a counterexample: when something is implemented differently from what the function name promises/implies to a human.

                                  1. 2

                                    I see the author moving the goalposts while telling that story.

                                    “My functions are provably correct!”

                                    “Ah, but the names are wrong! You are not so smart!”

                                    “My functions are provably correct, and I have used NLP to ensure these functions are labelled sensibly!”

                                    “Ah, but you have not proven that these functions provide business value to the customer! You are not so smart!”

                                    etc., etc.

                                    The author’s “counter-example” is completely orthogonal to the topic of proven correctness, as another user has already pointed out. I feel that bringing up naming as any kind of counter-argument in this context suggests exactly the false dichotomy I described.

                                    1. 1

                                      OK, interesting. I see how the author could start moving goalposts like that, but I don’t see the initial argument as already initiating a moving of goalposts. I’d rather say it forces the static typing / proof system enthusiast to retreat from the motte (I can prove all my code correct) to the bailey (I can prove a bunch of things about my code). After that the argument has lost its force: then complaining that typing or proving isn’t much use, because it doesn’t prove names correct would be ludicrous. I don’t interpret the author as making that argument, but I see how you could.

                            3. 3

                              After using Unity for ~9 years, I’ve come to a different conclusion on performance: When you’re further from the metal, you don’t get to stop thinking about the machine, but you do need to grab a 3 meter long screwdeiver sometimes

                              I think this is what Jonathan Blow was talking about when he said you’d have to rewrite many of Unity’s systems if you wanted to make The Witness in it. You still need to understand how the hardware works if you want to have any hope of making your code fast, but you’re going to need to work around/replace parts of the higher-level engine/language, and sometimes that’s more work (or more annoying work. I think Blow has low tolerance for that kind of code) than doing everything in a lower level environment

                              I’m very pro-Unity for most games. You’ll get to a prototype way faster, and the pain of making a few rube-goldberg machines to get it running fast enough is usually far less than writing a whole engine. If you want to be Id and work on bleeding edge rendering tech, it’s not going to be a good choice. But almost anything short of that, the code and time saved is worth the gross hacks

                              1. 2

                                Seems like one could have some fun mapping these proposed tribes to other archetypes. Here’s an example :

                                applied mathematician -> priest
                                hacker -> warrior
                                maker -> blacksmith
                                1. 2

                                  I liked reading the piece, but it’s very clear that the author is the least informed about the views and the tools of the first camp. I consider myself somewhere in between (1) and (3) and mostly hanging out in (1) communities. I don’t think (1) values poetry above utility. (1) just thinks that good code is the only way to build useful systems in a sane and maintainable way.

                                  The portrayal of Haskell is also very uninformed and unfair. When a haskeller with >3-4 years of experience needs to ship code fast and says “fuck it”, you wouldn’t believe how the language can become more fast-and-loose and more pragmatic than Python. On the other end of the spectrum, you can make it produce code as fast as C if you’re willing to spend as much time and have the stomach to write C code.

                                  I’m not saying there aren’t any trade-offs, but the author is doing his reader a disservice by trying to hammer Haskell into a mold that best suits his taxonomy.

                                  1. 1

                                    I see myself as solidly in both the last two camps. I do not appreciate the beauty of that word so many on here worship: Types. But the hardware is sometimes important (running a service on a low budget or high requirements) and overall only things that ship are worth anything.

                                    But on the post: I’d put Clojure firmly in the last camp, and I’m surprised the creator is put in the first bucket. Not where I expected his name.

                                    1. 1

                                      I really enjoyed the article because it made me think about my journey as a software developer, a journey which I started back in 2005 when I was hired as a junior C#/ASP.NET developer.

                                      Almost a year later I discovered Ruby and I now realise that what I really enjoyed about Ruby was its ability to write beautiful code, at least when compared to the C# code I wrote before. The idea of an Enumerable mix-in that would magically allow you to iterate through your custom objects was pure poetry when you’d compare it to the utilitarian foreach found in C# at that time.

                                      What’s quite interesting is that I’ve been feeling the desire to move from Ruby to another language and I couldn’t understand why. Since I have a friend who’s also thinking of moving away from Ruby, I thought it’s the community not evolving at the same pace as I was but I now I think that I’m exposed to other programming languages and ideas though communities like Lobsters and Ruby doesn’t feel as “poetic” as it once felt, not when comparing it with languages as Clojure or Haskell. As a fun exercise, I’ve shared the link to my friend, I’m pretty sure he’ll consider himself in the second “tribe” (although I’m more inclined to see it as “school of thought”).

                                      Stories with similar links:

                                      1. 3 tribes of programming via cadey 1 year ago | 42 points | 7 comments