Six languages to master.

Eric Raymond, in “How to Become a Hacker“, recommended five languages: C, Java, Python, Perl, and Lisp. Each he recommended for different reasons: Python and Java as introductory languages, C to understand and hack Unix, Perl because of its use in scripting, and Lisp for, to use his words which are so much better than anything I can come up with, the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot.

It’s 2012. Many languages have come to the fore that didn’t exist when this essay was written. Others, like Perl, have faded somewhat. What is today’s five-language list? I won’t pretend that my answer is necessarily the best; it’s biased based on what I know. That said, I’d think the 5 highest-return languages for people who want to become good engineers are the following, and in this order: Python, C, ML, Clojure, and Scala.

Why these 5? Python I include because it’s easy to learn and, in-the-small, extremely legible. I’d rather not use it for a large system, but people who are just now learning to program are not going to be writing huge systems. They’re not going to be pushing major programs into production. At least, they shouldn’t be. What they should be able to do is scrape a webpage or build a game or investigate an applied math problem and say, “Shit, that’s cool.” Python gets people there quickly. That will motivate them to get deeper into programming. Python is also a language that is not great at many things, but good at one hell of a lot of them. It’s quick to write, legible in the small, and expressive. It allows imperative and functional styles. It has great libraries, and it has strong C bindings, for when performance is needed.

People who are getting started in programming want to do things that are macroscopically interesting from a beginner’s perspective. They don’t just want to learn about algorithms and how compilers work, because none of that’s interesting to them until they learn more of the computer science that motivates the understanding of why these things are important. Compilers aren’t interesting until you’ve written programs in compiled languages. At the start, people want to be able to write games, scrape webpages, and do simple systems tasks that come up. Python is good because it’s relatively easy to do most programming tasks in it.

After Python, C is a good next choice, and not because of its performance. That’s largely irrelevant to whether it will make someone a better programmer (although the confidence, with regard to understanding performance, that can come with knowing C is quite valuable). C is crucial because there’s a lot of computer science that becomes inaccessible if one sticks to higher-level languages (and virtual machines) like Java, C#, and Python. Garbage collection is great, but what is the garbage collector written in? C. As is Unix, notably. For all this, I think C is a better choice than C++ because there’s another important thing about C: C++ is a mess and it’s not clear whether it’s a good language for more than 1% of the purposes to which it’s put, but C, on the other hand, has utterly dominated the mid-level language category. For all its flaws, C is (like SQL for database query languages) a smashing, undisputed success, and for good reasons. The high-level language space is still unsettled, with no clear set of winners, but the midlevel language used to write the runtimes and garbage collectors of those high level languages is usually C, and will be for some time.

Python and C give a person coverage of the mid- and very-high levels of language abstraction. I’m avoiding including low-level (i.e. assembly) languages because I don’t think any of them have the generalist’s interest that would justify top-5 placement. Familiarity with assembly language and how it basically works is a must, but I don’t think mastery of x86 intricacies is necessary for most programmers.

Once a programmer’s fluent in Python and C, we’re talking about someone who can solve most coding problems, but improvement shouldn’t end there. Taste is extremely important, and it’s lack of taste rather than lack of intellectual ability that has created the abundance of terrible code in existence. Languages can’t inherently force people to learn taste, but a good starting point in this direction is ML: SML or OCaml with the “O” mostly not used.

ML has been described as a “functional C” for its elegance. It’s fast, and it’s a simple language, but its strong functional programming support makes it extremely powerful. It also forces people to program from the bottom up. Instead of creating vague “objects” that might be hacked into bloated nonsense over the lifespan of a codebase, they create datatypes (mostly, records and discriminated unions, with parameterized types available for polymorphism) out of simpler ones, and use referentially transparent functions as the basic building blocks of most of their programs. This bottom-up structure forces people to build programs on sound principles (rather than the vague, squishy abstractions of badly-written object-oriented code) but ML’s high-level capability brings people into the awareness that one can write complex software using a bottom-up philosophy. Python and C teach computer science at higher and lower levels, but ML forces a programmer to learn how to write good code.

There’s also something philosophical that Python, C, and Ocaml tend to share that C++ and Java don’t: small-program philosophy, which is generally superior. I’ve written at length about the perils of the alternative. In these languages, it’s much more uncommon to drag in the rats’ nest of dependencies associated with large Java projects. For an added bonus, you never have to look at those fucking ugly singleton directories called “com”. Once a person has used these three languages to a significant extent, one gets a strong sense of how small-program development works and why immodular, large-project orientation is generally a bad thing.

When you write C or Ocaml or Python, you get used to writing whole programs that accomplish something. There’s a problem, you solve it, and you’re done. Now you have a script, or a library, or a long-running executable. You may come back to it to improve it, but in general, you move on to something else, while the solution you’ve created adds to the total stored value of your code repository. That’s what’s great about small-program development: problems are actually solved and work is actually “done” rather than recursively leading to more work without any introspection on whether the features being piled on the work queue make sense. Developers who only experience large-program development– working on huge, immodular Java projects in IDEs a million metaphorical miles from where the code actually runs for real– never get this experience of actually finishing a whole program.

Once a person has grasped ML, we’re talking about a seriously capable programmer, even though ML isn’t a complex language. Learned in the middle of one’s ML career is a point to which I’ll return soon, but for now leave hanging: types are interesting. One of the most important things to learn from ML is how to use the type system to enforce program correctness: it generates a massive suite of implicit unit tests that (a) never have to be written, and (b) don’t contribute to codebase size. (Any decent programmer knows that “lines of code” represent expenditure, not accomplishment.)

The fourth language to learn is Clojure, a Lisp that happens to run on the JVM. The JVM has its warts, but it’s powerful and there are a lot of good reasons to learn that ecosystem, and Clojure’s a great entry point. A lot of exciting work is being done in the JVM ecosystem, and languages like Clojure and Scala keep some excellent programmers interested in it. Clojure is an excellent Lisp, but with its interactive “repl” (read-eval-print-loop) and extremely strong expressivity, it is (ironically)  arguably the best way to learn Java. It has an outstanding community, a strong feature set, and some excellent code in the open-source world.

Lisp is also of strong fundamental importance, because its macro system is unlike anything else in any other language and will fundamentally alter how an engineer thinks about software, and because Lisp encourages people to use a very expressive style. It’s also an extremely productive language: large amounts of functionality can be delivered in a small amount of time. Lisp is a great language for learning the fundamentals of computing, and that’s one reason why Scheme has been traditionally used in education. (However, I’d probably advocate starting with Python because it’s easier to get to “real stuff” quickly in it. Structure and Interpretation of Computer Programs and Scheme should be presented when people know they’re actually interested in computing itself.)

When one’s writing large systems, Lisp isn’t the best choice, because interfaces matter at that point, and there’s a danger that people will play fast-and-loose with interfaces (passing nested maps and lists and expecting the other side to understand the encoding) in a way that can be toxic. Lisp is great if you trust the developers working on the project, but (sadly) I don’t think many companies remain in such a state as they grow to scale.

Also, static typing is a feature, not a drawback. Used correctly, static typing can make code more clear (by specifying interfaces) and more robust, in addition to the faster performance usually available in compiled, statically typed languages. ML and Haskell (which I didn’t list, but it’s a great language in its own right) can teach a person how to use static typing well.

So after Lisp, the 5th language to master is Scala. Why Scala, after learning all those others, and having more than enough tools to program in interesting ways? First of all, it has an incredible amount of depth in its type system, which attempts to unify the philosophies of ML and Java and (in my opinion) does a damn impressive job. The first half of Types and Programming Languages is, roughly speaking, the theoretic substrate for ML. But ML doesn’t have a lot of the finer features. It doesn’t have subtyping, for example. Also, the uniqueness constraint on record and discriminated union labels (necessary for full Hindley-Milner inference, but still painful) can have a negative effect on the way people write code. The second half of TAPL, which vanilla ML doesn’t really support, is realized in Scala. Second, I think Scala is the language that will salvage the 5 percent of object-oriented programming that is actually useful and interesting, while providing such powerful functional features that the remaining 95% can be sloughed away. The salvage project in which a generation of elite programmers selects what works from a variety of programming styles– functional, object-oriented, actor-driven, imperative– and discards what doesn’t work, is going to happen in Scala. So this is a great opportunity to see first-hand what works in language design and what doesn’t.

Scala’s a great language that also requires taste and care, because it’s so powerful. I don’t agree with the detractors who claim it’s at risk of turning into C++, but it definitely provides enough rope for a person to hang himself by the monads.

What’s most impressive about Clojure and Scala is their communities. An enormous amount of innovation, not only in libraries but also in language design, is coming out of these two languages. There is a slight danger of Java-culture creep in them, and Scala best practices (expected by the leading build environments) do, to my chagrin, involve directories called “src” and “main” and even seem to encourage singleton directories called “com”, but I’m willing to call this a superficial loss and, otherwise, the right side seems to be winning. There’s an incredible amount of innovation happening in these two languages that have now absorbed the bulk of the top Java developers.

Now… I mentioned “six languages” in this post’s title but named five. The sixth is one that very few programmers are willing to use in source code: English. (Or, I should say, the scientifically favored natural language of one’s locale.) Specifically, technical English, which requires rigor as well as clarity and taste. Written communication. This is more important than all of the others. By far. For that, I’m not complaining that software engineers are bad at writing. Competence is not a problem. Anyone smart enough to learn C++ or the finer points of Lisp is more than intelligent enough to communicate in a reasonable way. I’m not asking people to write prose that would make Faulkner cry; I’m asking them to explain the technical assets they’ve created at, at the least, the level of depth and rigor expected in a B+ undergraduate paper. The lack of writing in software isn’t an issue of capability, though, but of laziness.

Here’s one you hear sometimes: “The code is self-documenting.” Bullshit. It’s great when code can be self-documenting, making comments unnecessary, but it’s pretty damn rare to be solving a problem so simple that the code responsible for solving it is actually self-explanatory. Most problems are custom problems that require documentation of what is being solved, why, and how. People need to know, when they read code, what they’re looking at; otherwise, they’re going to waste a massive amount of time focusing on details that aren’t relevant. Documentation should not be made a crutch– you should also do the other important things like avoiding long functions and huge classes– but it is essential to write about what you’re doing. People need to stop thinking about software as machinery that “explains itself” and start thinking of it as writing a paper, with instructions for humans about what is happening alongside the code actually doing the work.

One of the biggest errors I encounter with regard to commenting is the tendency to comment minutiae while ignoring the big picture. There might be a 900-line program with a couple comments saying, “I’m doing this it’s O(n) instead of O(n^2)” or “TODO: remove hard-coded filename”, but nothing that actually explains why these 900 lines of code exist. Who does that help? These types of comments are useless to people who don’t understand what’s happening at all, which they generally won’t in the face of inadequate documentation. Code is much easier to read when one knows what one is looking at, and microcomments on tiny details that seemed important when the code was written are not helpful.

Comments are like static typing: under-regarded if not ill-appreciated because so few people use them properly, but very powerful (if used with taste) in making code and systems actually legible and reusable. Most real-world code, unfortunately, isn’t this way. My experience is that about 5 to 10 percent of code in a typical codebase is legible, and quite possibly only 1 percent is enjoyable to read (which good code truly is). The purpose of a comment should not be only to explain minutiae or justify weird-looking code. Comments should also ensure that people always know what they’re actually looking at.

The fallacy that leads to a lack of respect for documentation is that writing code is like building a car or some other well-understood mechanical system. Cars don’t come with a bunch of labels on all the pieces, because cars are fairly similar under the hood and a decent mechanic can figure out what is what. With software, it’s different. Software exists to solve a new problem; if it were solving an old problem, old software could be used. Thus, no two software solutions are going to be the same. In fact, programs tend to be radically different from one another. Software needs to be documented because every software project is inherently different, at least in some respects, from all the others.

There’s another problem, and it’s deep. The 1990s saw an effort, starting with Microsoft’s visual studio, to commoditize programmers. The vision was that, instead of programming being a province of highly-paid, elite specialists with a history of not working well with authority, software could be built by bolting together huge teams of mediocre, “commodity” developers, and directing them using traditional (i.e. pre-Cambrian) management techniques. This has begun to fail, but not before hijacking object-oriented programming, turning Java’s culture poisonous, and creating some of the most horrendous spaghetti code (MudballVisitorFactoryFactory) the world has ever seen. Incidentally, Microsoft is now doing a penance by having its elite research division investigate functional programming in a major way, the results being F# and a much-improved C#. Microsoft, on the whole, may be doomed to mediocrity, but they clearly have a research division that “gets it” in an impressive way. Still, that strikes me as too little, too late. The damage has be done, and the legacy of the commodity-developer apocalypse still sticks around.

The result of the commodity-programmer world is the write-only code culture that is the major flaw of siloized, large-program development. That, I think, is the fundamental problem with Java-the-culture, IDE-reliance, and the general lack of curiosity observed (and encouraged) among the bottom 80 percent of programmers. To improve as programmers, people need to read code and understand it, in order to get a sense of what good and bad code even are, but almost no one actually reads code anymore. IDEs take care of that. I’m not going to bash IDEs too hard, because they’re pretty much essential if you’re going to read a typical Java codebase, but IDE culture is, on the whole, a major fail that makes borderline-employable programmers out of people who never should have gotten in in the first place.

Another problem with IDE culture is that the environment becomes extremely high maintenance, between plugins that often don’t work well together, build system idiosyncracies that accumulate over time, and the various menu-navigation chores necessary to keep the environment sane (as opposed to command-line chores, which are easily automated). Yes, IDEs do the job: bad code becomes navigable, and commodity developers (who are terrified of the command line and would prefer not to know what “build systems” or “version control” even are) can crank out a few thousand lines of code per year. However, the high-maintenance environment requires a lot of setup work, and I think this is culturally poisonous. Why? For a contrast, in the command-line world, you solve your own problems. You figure out how to download software (at the command line using wget, not clicking a button) and install it. Maybe it takes a day to figure out how to set up your environment, but once you’ve suffered through this, you actually know a few things (and you usually learn cool things orthogonal to the problem you were originally trying to solve). When a task gets repetitive, you figure out how to automate it. You write a script. That’s great. People actually learn about the systems they’re using. On the other hand, in IDE-culture, you don’t solve your own problems because you can’t, because there it would take too long. In the big-program world, software too complex for people to solve their own problems is allowed to exist. Instead of figuring it out on your own, you flag someone down who understands the damn thing, or you take a screenshot of the indecipherable error box that popped up and send it to your support team. This is probably economically efficient from a corporate perspective, but it doesn’t help people become better programmers over time.

IDE culture also creates a class of programmers who don’t work with technology outside of the office– the archetypal “5:01 developers”– because they get the idea that writing code requires an IDE (worse yet, an IDE tuned exactly in line with the customs of their work environment). If you’re IDE-dependent, you can’t write code outside of a corporate environment, because when you go home, you don’t have a huge support team to set the damn thing up in a way that you’re used to and fix things when the 22 plugins and dependencies that you’ve installed interact badly.

There are a lot of things wrong with IDE culture, and I’ve only scratched the surface, but the enabling of write-only code creation is a major sticking point. I won’t pretend that bad code began with IDEs because that’s almost certainly not true. I will say that the software industry is in a vicious cycle, which the commodity-developer initiative exacerbated. Because most codebases are terrible, people don’t read them. Because “no one reads code anymore”, the bulk of engineers never get better, and continue to write bad code.

Software has gone through a few phases of what it means for code to actually be “turned in” as acceptable work. Phase 1 is when a company decides that it’s no longer acceptable to horde personal codebases (that might not even be backed up!) and mandates that people check their work into version control. Thankfully, almost all companies have reached that stage of development. Version control is no longer seen as “subversive” by typical corporate upper management. It’s now typical. The second is when a company mandates that code have unit tests before it can be relied upon, and that a coding project isn’t done until it has tests. Companies are reaching this conclusion. The third milestone for code-civilizational development, which very few companies have reached, is that the code isn’t done until you’ve taught users how to use it (and how to interact with it, i.e. instantiate the program and run it or send messages to it, in a read-eval-print-loop appropriate to the language). That teaching can be supplied at a higher level in wikis, codelabs, and courses… but it also needs to be included with the source code. Otherwise, it’s code out-of-context, which becomes illegible after a hundred thousand lines or so. Even if the code is otherwise good, out-of-context code without clear entry-points and big-picture documentation becomes incomprehensible around this point.

What do I not recommend? There’s no language that I’d say is categorically not worth learning, but I do not recommend becoming immersed in Java (except well enough to understand the innards of Clojure and Scala). The language is inexpressive, but the problem isn’t the language, and in fact I’d say that it’s unambiguously a good thing for an engineer to learn how the JVM works. It’s that Java-the-Culture (VisitorSelectionFactories, pointless premature abstraction, singleton directories called “com” that betray dripping contempt for the command line and the Unix philosophy, and build environments so borked that it’s impossible not to rely on an IDE) that is the problem; it’s so toxic that it reduces an engineer’s IQ by 2 points per month.

For each of these five programming languages, I’d say that a year of exposure is ideal and probably, for getting a generalist knowledge, enough– although it takes more than a year to actually master any of these. Use and improvement of written communication, on the other hand, deserves more. That’s a lifelong process, and far too important for a person not to start early on. Learning new programming languages and, through this, new ways of solving problems, is important; but the ability to communicate what problem one has solved is paramount.

54 thoughts on “Six languages to master.

  1. I will not comment on your choices on the five languages but your opinion about Java and Java developers which is I think somehow biased. It is not always as bad as you describe it. You can do some work with Java. I have to admit that after having used other languages than C++ and Java I realized that your expression capability is greatly reduced with Java and C++. C++ is sometimes too convoluted for its own good. Now people will argue that you can shoot yourself with C++ and its your fault. But in practice it is not always true, as people will say for example use stl and then you got all these rules you have to know to use stl libraries properly. However C++ IMHO has changed a lot with Cx11. With Java the situation is worst it is like the language itself discourages you to do things differently and every time you write a line of code you have to carry this whole bag of unnecessary stuff that the language imposes irrespectively of your current problem. Java is like precooked food. it helps but it has always more or less the same taste.

    • Biased, but biased with good reason. I started out as a Java developer, and the biggest problem I see with Java is that you cannot build maintainable and extensible projects in just Java – for that you need to introduce complex design patterns such as abstract factories and inversion of control strategies that result in a lot of XML, JSON, etc. to force Java to do things that functional languages do natively (currying, function composition, lambdas, etc. replace these things natively).

      The advantage (and the FP folks will hate me for saying this) is that Java is, frankly, easier to understand for greener or less well-rounded software engineers. I say this from experience in learning Haskell – it’s simply more straightforward to go from pseudo-code to Java than it is to go from that to ML/Scala (unless you want to write Scala that looks like Java). No, your solution will not be organized in a way that maximizes its extensibility, but it will be more maintainable in the sense that it will take less time for most developers to read and understand the code (even if that code is fragile). Humans naturally think it terms of classifications and objects – we do it everywhere all the time. We don’t think naturally in terms of abstract algebra and category theory, and the fact that these are dedicated disciplines of mathematics, while the OO system really didn’t exist before large software systems came into being is evidence of that claim.

      Java gets a bad wrap because it’s overused. The crazy Spring API which has everything and the kitchen sink is evidence of that. When building sizable Java desktop applications where concurrency is a must, the shortcomings of Java start making a real difference. It then comes down to which is easier, teach Java programmers the complexities of writing concurrent Java applications and the problems with deadlocks and how to write thread-safe code (which is essentially teaching them to write FP style code in Java), or just teach them a functional language (like Scala) and let the language features help them out? Some may disagree, but I tend towards the latter viewpoint – teach them Scala and introduce them to the Scala concurrency model which I think is easier to understand than Java’s model.

      I say this with the utmost love for FP. I chose to stick with Haskell because of what it forces me to learn about my algorithms and code, but I must admit to myself that it’s also less natural; if I need to develop in an environment where correctness is less important than speed and agility, and the size and complexity of the software is small to medium, I would not choose ML or Haskell – I would choose something imperative (Python, C, Ruby, Java).

      • Humans don’t naturally think in terms of objects and classifications, at least not in the same way as the OOP paradigm. Algebra is actually more natural especially since most modern programming problems boil down to some Mathematical model and functional programming is the most natural way to represent that Mathematical model.

        That being said however I do not particularly like “pure” languages (especially pure functional languages) and tend to prefer multi-paradigm languages, there are just some problems which are best solved using a good old imperative loop rather than trying to implement them as tail-recursive functions, and there are times when you just have to mutate some local variables. My philosophy is that if you’re spending most of your time trying to get around the restrictions of the paradigm then you’re better off using another paradigm for that particular problem.

  2. What is your opinion with regards to GO? I have been playing around with it recently and have found it a pleasure to use.

  3. As someone who feels like they’re stuck in a dead-end language, I really found this to be a helpful beacon for the future. Thanks!

  4. I think C# is a very good candidate to be on this list as well. I think as a language, it is one of the most well rounded and most mature languages that’s out there. And with Mono (and MonoTouch and MonoDroid), you can target pretty much every major platform that’s out there.

    • I actually don’t know much about C#. F# seemed really promising and cool when I looked into it, but this was 2008 and I wasn’t aware of Mono if it existed… and I am just not using Windows for my personal projects.

    • C# is a great language, its a high-level Object-Oriented C but without the bloat, mess and unnecessary complexity of C++. I would be happy if C# becomes a multi-platform language and replaces C++ – a language which I absolutely hate.

  5. It’s in fact quite common for garbage collectors to be self-hosted in languages with high-quality AOT compilers. Various Common Lisps and Haskell come to mind. I think C is obsolete except as the output of code generators and compilers, but I agree that the word on the street has not yet caught up.

    I also agree that Python is the best first choice and ML belongs in there along with a Lisp (even Emacs Lisp, messy as it is, will teach you the Lisp Lessons well enough). I haven’t felt any desire to learn Scala: reading through the reference manual gave me the impression it was the next C++. And Java doesn’t have to be as toxic as you make out, as I’ve said here before.

    • Scala is immensely complicated, but I feel that it’s the most practical of the statically-typed functional languages out there. It’s managed to build a community that Haskell and ML haven’t been able to summon.

      When I finally got monads in learning Haskell, it blew my mind. Scala is a language where you can actually (a) use monads, and (b) get a job without a 6-month search. :)

      I agree that there’s a C++ danger in Scala, but C++ isn’t all bad. I don’t like C++ at all (as you know) but there are some neat and useful things about it. One of these days I might do a C++ project just to see if I really hate the language, or if the problem was with the (disreputable) codebase I was working in.

      If Scala becomes crufty and baroque (and I doubt Odersky will allow it to become too out of hand) we’ll probably see a simpler, more elegant version that delivers most of the power. I figure Scala is a good language to work in because, if that happens, I’ll be well-prepared to transition to that “next language”.

    • C is not obsolete, what do you think those high-quality AOT compilers are written in, C++? Assembly Language? C is still the best low-level language, for LOW-LEVEL work, it abstracts away the Assembly details yet still gives you full control of memory and even allows embedded Assembly if you need that extra performance. C is fast and C output programs are small making C a great language for language compilers, interpreters, etc.

      On the contrary C is not used as the output of code generators and compilers, which is almost always native Assembly or some byte-code.

  6. I wasn’t exactly sure where you were going in the second half of the article. It seems like it started with the top 5 (6) programming languages and ended up being a rant about IDEs. Interesting nonetheless.

  7. “When one’s writing large systems, Lisp isn’t the best choice, because interfaces matter at that point, and there’s a danger that people will play fast-and-loose with interfaces”

    Exactly the same thing happens with statically-typed languages, too. Every time some interface uses XML or JSON, you have people “playing fast-and-loose with interfaces”. Where have you seen Lisp run into trouble when building a large system?

    “Lisp is great if you trust the developers working on the project, but (sadly) I don’t think many companies remain in such a state as they grow to scale.”

    Exactly the same thing happens with statically-typed languages, too. If you don’t trust the developers, no language can save you. If you don’t think Java programs can go bad, I’ve got a few million projects to show you. (The only difference is that Lisp has macros, so for a given size project, it can actually do more.)

    “Also, static typing is a feature, not a drawback.”

    Heh. If you really believe that, and that Lisp is a language worth learning, then why not make a new statically-typed Lisp? That would be an improvement, right? :-)

    • The older I get (and I’m only 29, but sometimes I feel like an outright curmudgeon) the more I am convinced that you are right on this: it’s more about the developers, and the culture, and the communication, than the language. “Ruby/Lisp rock-stars” are annoying as fuck, but there are solid people who make Ruby (or any other dynamic language) work well every single day.

      The real problem, I’m starting to realize, is Big Software… which is occasionally quite appropriate but usually not. Small-program development is the way to go: build modules and libraries of general use, get shit done, and improve the business environment incrementally (as opposed to building huge “visionary” all-or-nothing projects, which you should only do if you have rock-solid trust in the people who’ll build the thing). Dynamically typed languages fall down in million-line code bases, but so do C++ and Java, and I have no idea whether Haskell or ML would do the same because I’ve never seen a 1MLoC codebase at that size, but I’m guessing that they probably would (or, at least, there’d be parts that get crufty and horrible). The problem isn’t languages because we have an abundance of really great ones. It’s Big Software and the fact that mere mortals can’t handle that much complexity.

      • I’m only 28, but I completely get what your saying about being a curmudgeon. I’m also one of the rubyists out there (hopefully a solid one, not a rock star :)). I think the point here is key though, Big Software is one of the key issues, not the technologies or people implementing it.

      • “The real problem, I’m starting to realize, is Big Software… which is occasionally quite appropriate but usually not.”

        Yes yes and yes. I could not agree more. When I read your original article, many of the problems that you posed seemed so foreign to me. However, I have limited experience in software at a real company. I have only worked at one, and we build our software in small modules that do one thing and do it very well. This makes the dynamic language we use far more than adequate for our purposes. It also enables us to work on very small teams, generally with 2-3 developers working on one part of an application at a time. We know each other’s code intimately. We code review. We write unit tests. And it all works very well for our purposes.

  8. While I agree with most of you post (and your points about Java and IDE toxicity are spot on), I really cant agree with such a list without Javascript in it. Learning to work with asynchronous APIs (Node.js) and slinging anonymous functions/objects around all the time are techniques that I have not found to be as natural in other languages. That and you get to experience working with a dynamic “scripting” language that is not dog-slow for nontrivial tasks, something you really get to appreciate after working with Python or Ruby.

    • Excellent point. I hope it came across that my “list of 5” was limited by the context of how little one programmer can actually know. There are literally hundreds of languages out there that have cool things to teach, and most of them I’ve never seen. I didn’t even touch on Haskell or Mozart/Oz (used in CTM, one of the best books on practical PL and programming models). I limited myself to a small number and it was a guarantee from the outset that I’d miss a few gems.

      I haven’t mastered all those languages (actually, I’d say that I’ve “mastered” none of them, but my bar for mastery is quite high). I only know a little bit of C (enough to read it and understand the model) and Python I’ve used, but I don’t know the libraries and frameworks. But I’ve written them enough to have a minimal fluency. JavaScript, on the other hand, is pretty foreign to my experience. That’s not a knock on it. That says more about me (and the fact that I’ve been working on back-end projects for most of my life).

      Now that I’m working on an implementation of Ambition that will inevitably propel me into some front-end work, I hope to get a sense of what JavaScript is about and how to use it productively. I’ve played with it, but not really used it yet.

      • When you do, I would highly recommend checking out some Douglas Crockford, to really dig into the fun aspects of the language and how you can play to its strengths and bypass its weaknesses (there is a great 5 hour video series on youtube if that is your thing).

  9. I suggest two other ones. First of all, assembly, at least a bit of it. That is the key to really understand what the machine does. C Pointers are so much easier if you know assembly.
    Second, Ada. Why? Because it places a lot of emphasis on correctness by design.

  10. From your description of IDEs i am very confused, since my experiences with them has been nothing like what you describe, since i am able to set my IDE of choice (or acceptable fall-through backups, or alternatives) up quickly in any environment, allowing me to hack anywhere in the comfort i am used to.

    Which IDEs do you personally have had experiences with and if they were multiple, which ones gave you the experiences described?

    • I agree with Christian. I see an IDE as a nailgun and the command line as a hammer. A lousy nailgun may misfire and electrocute you but that means that you bought a lousy nailgun, not that nailguns are useless and bad. Not a good reason to retreat to the Stone Age.

      I always find at least a few coding mistakes when I pull up code in an IDE for the first time from somebody who wrote it using their own command line environment. The IDE marks it in yellow or red and, 99% of the time, it is a coding mistake that should be corrected.

      • The command line is a starship, not a hammer. Mastering it requires much more skill and patience than a nailgun, but when you do, it will make you lightening fast and a much more capable programmer. Additionally, any syntactic mistakes that an IDE would pick up will also be picked up in any properly written unit tests, which any one living in 2013 should be writing. If you are not, then you are the one living in the stone age.

  11. I think you meant to write “hoard personal codebases”, not “horde”.

    A couple of things from the old days (I’m 53):

    “Besides a mathematical inclination, an exceptionally good mastery of one’s native tongue is the most vital asset of a competent programmer.” – Edsger Dijkstra, 1975

    In 1984 I was excited by the publication of Knuth’s “Literate Programming”, which introduced a new approach to writing programs interspersed with documentation and, perhaps more significantly, told the programming world that one of its gurus thought this was really important (“I believe that the time is ripe for significantly better documentation of programs”). Unfortunately it didn’t have the influence I expected it to, and the typical level of program documentation today seems to me about the same as it was 30 years ago.

  12. interesting post. nothing like telling people what languages to learn to start a fire :)
    not sure if it’s pride or ignorance that causes software developers to make statements like “Software exists to solve a new problem”. 99.9% (made-up statistic, but it’s in the right ballpark) of software being written today is solving the same damn problems. there are no new problems to solve for the most part.i’m talking about enteprise/commercial development of course. lots of room for creativity, sure.
    the entire IDE-and-the-archetypal-“5:01 developers” argument is completely specious. most of us 5:01 types bring our work laptops home, and have the entire arsenal of support at our disposal.

    • You’re not a “5:01 developer” if you take your laptop home.

      Even when I love what I’m working on, I couldn’t stand to spend 10 contiguous hours in an office building. I leave around 6:30 at the latest, but I also spend a lot of time reading and learning about technology, and coding my own personal projects.

      A “5:01 developer” doesn’t take work home or learn new programming concepts outside of work at all. There’s nothing wrong with this– not everyone has to be passionate about technology– but I’d prefer to live in a world where major technical decisions aren’t made based on this being the norm.

  13. Caveat: I only skimmed through this, it was way too long.

    Probably due to your self-described biases (and maybe even your age), you left out Smalltalk. It’s a gem of gems for learning and “getting” OO.

  14. Pingback: Why IDEs are Wrong for Embedded Developers | Atomic Spin

  15. Pingback: Learning C, reducing fear. « Michael O.Church

      • With both Python and Haskell on my list of languages to learn, let me suggest two free and challenging resources for learning any language that attracts your fancy. The EdX and Coursera are two great resources ( and EdX was started by MIT and Harvard and Coursera by a similar group of distinguished universities. 1) Python “An Introduction to Interactive Programming in Python” (Rice University) — great course that uses classic games like ‘Pong’ and ‘Astroids’ to learn how to program in Python. You actually create games; it’s not a learning game. 2) Haskell — “Introduction to Functional Programming” This course is brand new and has been running a week. It uses Haskell, but it is a general functional programming language course. (Delf University, The Netherlands.)

        The best part is that you can audit the courses at no cost! (i.e., Free!)

      • Oddly enough, I think the language list is dated.

        I’d probably remove Scala (it’s nice in some ways, and not in some others) and add Haskell.

        “Learn You a Haskell” is a good intro for Haskell. Then you have Real World Haskell, Beginning Haskell (which is actually more intermediate) and Parallel and Concurrent Programming in Haskell.

        For C, Zed Shaw’s Learn C the Hard Way is really good IMO. C is a finicky, detail-oriented language that it’s hard to learn if you don’t actually type the programs in.

        Clojure’s got some great books out there, including the O’Reilly reference and Joy of Clojure. A book on Clojurescript would also be useful because it’s a great front-end option. (I don’t know enough about Purescript yet to have an opinion on it.)

        • I would agree with your decision to remove scala and add Haskell. A beginner should probably skip the “Hello World” to avoid the intricacies of IO, but otherwise it’s a great way to learn functional programming.

  16. I’ve currently learned C, C++, Ruby, and Javascript. I’m ready to move on to a functional language. I was thinking of learning Haskell next, but I’d like to know why you recommend ML/Clojure/Scala over Haskell? I was under the impression that Haskell was the “purest” of the bunch, and thus provided the most paradigm shifting returns.

    • Haskell’s a fine choice as well. I think the exposure to the Hindley-Milner family is important, and ML is simpler; I also like Clojure because I think it’s useful to learn a Lisp.

  17. Many foundation big projects are builded by c++, and more and more projects are moving from c to c++, whether you like it or not, it is a trend, the simplistic of c make it unsuitable to deal with large scale, complicated projects.Even gcc are move to c++ totally, c is good, but c++ is far more better when you know how to use it properly.

    The programming language beacon—move from c to c++

  18. I’ve seen dozens of these “programming languages you should learn” lists, and despite myself, I like your reasoning–certain languages give you an understanding of programming even though you may not use them. Haskell is on my current list both as a functional language but more importantly as one where multi-core and parallel programming are possible. Years ago I came to a fork in my own programming road–Pascal or FORTH. I took the FORTH path which (in my case) led to ML and AL, and while I never use FORTH any more, it remains one of my favorite. For close to 10 years I attended a FORTH luncheon discussion at General Dynamics in San Diego and even wrote our group’s newsletter in PostScript. Usually, the Lisp group would show up at these same meetings and we had a lot in common. (They liked to say that they found AI more of the former and less of the latter.)

  19. I don’t think IDEs are bad, but I haven’t used one in a decade. Informix 4GL, its embedded modules, Perl and Clojure on Linux tend to do better with vim or emacs and whatever “make” you are using.

    As to large software, it seems to me that many of todays’s software producers/vendors, especially those who sell into the municipal space, want to own it all in the application space, rather than have nicer interfaces that encourage inter-vendor cooperation. I remember at FTP Software someone saying it wasn’t the stack that made money; instead it was the toolkit that allowed applications to be built.

  20. Pingback: Three plus One Programming Languages to Learn | Gregor Ulm

  21. Your writing is so freaking amazing. I just started reading your articles and they are really engrossing.

    Couple bones to pick, though: You say “I do not recommend becoming immersed in Java,” yet explain that this is because of the culture. If you’re learning Java on your own, you are hardly forced to become part of this culture. Also, I honestly think that MUMPS is categorically not worth learning (except as a sort of macabre intellectual exercise).

    Finally, as a person who writes a lot of numerical code, I think MATLAB is seriously worth learning. Sure, it’s ugly, but it heavily favors small-program development and it really gets the job done.

    • You can learn several different languages and from each find value that can be used in other languages. Right now I’m learning functional programming in Haskell and I plan to use functional programming in PHP derived from the “pure functional programming” found in Haskell.

      Of course you run the risk of becoming a ‘big talking schmuck.”

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s