Functional programming is a ghetto

Functional programming is a ghetto.

Before any flamewars can start, let me explain exactly what I mean. I don’t mean “functional programming sucks”. Far from it. The opposite, actually. Not all ghettos are poor, crime-ridden, and miserable. Jewish ghettos existed for centuries in Europe, from the Renaissance to World War II, and many were intellectual centers of the world. Some were quite prosperous. Harlem was, at one time, an upper-middle-class African-American community at the center of some of America’s most important artistic contributions. The same is true of functional programming. It’s the underappreciated intellectual capital of the programming world, in that its ideas (eventually) trickle down into the rest of the industry, but it’s still a ghetto. A ghetto is the urban analog of a geographic enclave: it’s included in the metropolis, but culturally isolated and usually a lot smaller than the surrounding city. It often harbors those who’ve struggled outside of it. Those who become too used to its comforts view the outside world with suspicion, while those on the outside have a similar attitude of distrust toward those within. Ghettos usually imply that there’s something involuntary about being there, but that’s often not the case. Chinatowns are voluntary ghettos, in the non-pejorative sense, as are some religious communities like monasteries. “Functional programming” is, likewise, a voluntary ghetto. We’ve carved out an elite niche in the software industry, and many of us refuse to work outside of it, but we’re all here by choice.

What is functional programming? Oddly enough, what I’m about to talk about is not functional programming in the purist sense, because most “functional programmers” are not averse to using side effects. The cultural issues surrounding functional programming are not about some abstract dislike of computational effects, but rather an understanding of the necessity of managing the complexity they create, and using tools (especially languages) that make sane development possible. Common Lisp, Scala, and Ocaml are not purely functional languages, but they provide native support for the abstractions that make functional programming possible. What real functional programmers do is “multi-paradigm”– mostly functional, but with imperative techniques used when appropriate. What the debate comes down to is the question of what should be the primary, default “building block” of a program. To a functional programmer, it’s a referentially-transparent (i.e. returning the same output every time per input, like a mathematical function) function. In imperative programming, it’s a stateful action. In object-oriented programming, it’s an object, a more general construct that might be a referentially-transparent function, might represent an action in a hand-rolled domain-specific language (DSL) or might be something else entirely. Of course, most “object-oriented programming” becomes a sloppy mix of multiple styles and ad-hoc DSLs, especially as more than one developer comes to work on an object-oriented project. That’s a rant for later.

In general, functional programming is right. The functional approach is not right for every problem, but there is a right answer regarding the default abstractions for building most high-level programs: immutable data, and referentially transparent functions should be the default, except in special cases where something else is clearly more appropriate. Why? A computational action is, without more knowledge, impossible to test or reason about, because one cannot control the environment in which it exists. One needs to be able to know (and usually, to control) the environment in which the action occurs in order to know if it’s being done right. Usually, the tester wants to be able to cover all special cases of this action, in which case knowing the environment isn’t enough; controlling it is also necessary. But at this point, the state of the environment in which the test happens is an implicit parameter to the action, and making it explicit would make it a referentially-transparent function. In many cases, it’s better to do so– when possible. It might not be. For example, the environment (e.g. the state in a computer cluster database) might be too large, complex, or volatile to explicitly thread into a function. Much of real-world functional programming is not about eliminating all state, but about managing what state is intrinsic, necessary or appropriate.

For a concrete example, let’s say I have a blackboard, face down, with a number (state) on it, and I ask someone to read that (call it n) and erase the number, then write n+1 on the blackboard. I’m assuming he won’t lie to me, and that he’s physically capable of lifting the board; I want to determine if he can carry out this operation. If I don’t know n, and only see what is written after he is done, I have no hope of knowing whether the person carried out my order correctly. Of course, I could control the testing enviroment and write 5 on the blackboard before asking him to do this. If he writes 6, then I know he did what I asked him to do. At that point, though, the blackboard isn’t necessary. It’s more lightweight to just ask him, “what is 5 + 1?” I’ve moved from an imperative style of testing to a functional one: I’m determining whether his model of the addition function gives the right answer, rather than putting him through an exercise (action) and checking the state after it is done. The functional alternative is a unit test. I’m not trying to assess whether he knows how to turn over a blackboard, read it, erase it, and write a new number on it, because I only care about whether he can add. If I want to assess all of those as well, then I need to make an integration test of it. Both types of test are necessary in real-world software engineering, but the advantage of unit tests is that they make it easy to determine exactly what went wrong, facilitating faster debugging.

Testing, debugging, and maintenance are a major component of real-world software engineering, and functional programming gives us the tools to tackle these problems in a tractable way. Functions should be referentially transparent and, ideally, small (under 20 lines when reasonable). Large functions should be broken up, hierarchically, into smaller ones, noting that often these small components can be used in other systems. Why is this desirable? Because modularity makes code reuse easier, it makes debugging and refactoring much simpler (fixes only need to be made in one place) and, in the long term, it makes code more comprehensible to those who will have to modify and maintain it. People simply can’t hold a 500-line object method in their heads at one time, so why write these if we can avoid doing so?

The reality, for those of us who call ourselves functional programmers, is that we don’t always write stateless programs, but we aim for referential transparency or for obvious state effects in interfaces that other programmers (including ourselves, months later) will have to use. When we write C programs, for example, we write imperative code because it’s an imperative language, but we aim to make the behavior of that program as predictable and reasonable as we possibly can.

Functional programming, in the real world, doesn’t eschew mutable state outright. It requires mindfulness about it. So why is functional programming, despite its virtues, a ghetto? The answer is that we tend to insist on good design, to such a degree that we avoid taking jobs where we’re at risk of having to deal with bad designs. This isn’t a vice on our part; it’s a learned necessity not to waste one’s time or risk one’s career trying to “fix” hopeless systems or collapsing companies. Generally, we’ve come to know the signs of necrosis. We like the JVM languages Clojure and Scala, and we might use Java-the-language when needed, but we hate “Java shops” (i.e. Java-the-culture) with a passion, because we know that they generate intractable legacy messes in spite of their best efforts. Say “POJO” or “Visitor pattern”, and you’ve lost us. This seems like arrogance, but for a person with a long-term view, it’s necessary. There are a million “new new things” being developed at any given time, and 995,000 of them are reincarnations of failed old things that are going to crash and burn. If I could characterize the mindset of a functional programmer, it’s that we’re conservative. We don’t trust methodologies or “design patterns” or all-purpose frameworks promising to save the world, we don’t believe in “silver bullets” because we know that software is intrinsically difficult, and we generally believe that the shiniest IDE provides us enough to compensate for its shortfalls and false comforts. For example, an IDE is useless for resolving a production crisis occurring on a server 3,000 miles away. We’d rather use vim or emacs, and the command line, because we know they work pretty much everywhere, and because they give us enough power in editing to be productive.

From a functional programmer’s perspective, it’s easy to mistake the rest of the software industry for “the ghetto” (especially considering the pejorative association, which I am trying to disavow, with that word). Our constructions are stable and attractive, and we do such a good job of cleaning up after ourselves that there’s not much horseshit on our streets. Outside our walls are slums with rickety, fifteen-story tenements that are already starting to lean. The city without is sloppy and disease-ridden and everything built in out there will be burned down, to kill the plague rats, in ten years. We don’t like to go there, but sometimes there are advantages of doing so– for one thing, it’s fifty times larger. If we lose awareness of size and scale and what this means, we can forget that we are in the ghetto. That’s not to say we shouldn’t live in one, for it’s a prosperous and intellectually rich ghetto we inhabit, but a ghetto it is.

I think most functional programmers only get a full awareness of this when we’re job searching, and thanks to most of us being in the top 5% of programmers, our job searches tend to be short. Still, I’ve lost count of the number of times over the past five years that I’ve found a job listing that looked interesting, except for its choice of language. “5 years of experience in Java, including knowledge of design-pattern best practices.” Nope. It might be a good company writing bad copy, but its technical choices look exactly the same as those of the bad firms, so how can I be sure? The process quickly becomes depressing. It’s not that Java or C++ are “dirty” languages that I would never use. It’s that any job that involves using these languages full-time is so likely to suck that it’s hardly worth investigating. Occasionally, C++ and Java are the right tools for the job, but no one should try to build a company on these languages. Not in 2012. Java isn’t a language that people choose to use, not for primary development. Not if they’ve used three or four languages in their career. It’s a language that people make other people use. Usually, it’s risk-averse and non-technical managers making that call. A Java Shop is almost always a company in which non-engineers call the shots.

What we call functional programming is somewhat of a shibboleth for good-taste programming. We prefer the best programming languages, like Ocaml and Clojure, but we don’t actually restrict ourselves to writing functional programs. Do we use C when it’s the right tool for the job? Hell yeah. Do we put mutable state into a program when it makes it simpler (as is sometimes the case)? Hell yeah. On the other hand, we trust the aesthetic and architectural decisions made by brilliant, experienced, gray-bearded engineers far more than we trust business fads. We have a conservative faith in simplicity and ease-of-use over the shifting tastes of mainstream managerial types and the superficial attractiveness of silver bullets and “methodologies”. We roll our eyes when some fresh-faced MBA tells us that structuring our calendar around two-week “iterations” will solve every software problem known to humankind. Unfortunately, this insistence (often in the face of managerial authority) on good taste makes us somewhat unusual. It stands out, it can be unpopular, and it’s not always good for one’s career. Few stand with us. Most leave our camp, either to become managers (in which case, even a Java Shop is a plausible employer) or to accept defeat and let bad taste win. It’s hard to live in a ghetto.

Now, I have little faith in the stereotypical average programmer, the one who never thinks a technical thought after 5:01 pm, and who doesn’t mind using Java full-time because the inevitable slop is the problem of some “maintenance guy”. That person probably shouldn’t be programming. On the other hand, we’re about 2 percent of the software industry, if that, right now. We can reach out. We can do better. We’re not so brilliant that the other 98% of programmers have no hope of joining us. Not even close. There are many IDE-using, Java-hacking, semi-bored developers who are just as smart as we are but haven’t seen the light yet. It’s our job to show it to them, and if we fail to convince them that they could become 2 to 10 times more productive than they ever dreamed of being, and that programming can become fun again, then we’re the ones to blame. We must reach out, and we can probably bring 10, 20, maybe even 30 percent of programmers over to the light side, bringing about dramatic changes in the software industry.

I think the integrity of our industry depends on our ability and willingness to figure out how to do this.

About these ads

17 thoughts on “Functional programming is a ghetto

  1. I am a person and even a functional programmer who chose to use Java for TagSoup, because at the time I started it, Java had the best Unicode story of any of the many languages I know. Things have changed since, and I might have used something else today, but TagSoup is still a valuable contribution (from everything I hear) to the large and growing Java libraries.

    • There’s a lot of gold in the Java libraries and ecosystem. As you said, Java had far better support for Unicode in the late ’90s and early 2000s. It was also (in its time) one of the most mature languages for concurrency. There were, between 1995 and 2005, many application spaces where Java was the obvious best choice (not just the managerially blessed default choice).

      What I think has really changed the whole process is the advent of more expressive JVM languages, starting with Groovy and now with Scala and Clojure.

  2. Nicely said. I’ve long thought of Lisp as the language I wished I could be professionally programming in, and after reading about them, Haskell, Scala, Clojure seem even better. Where, though, does one go to find such a ghetto?

    (The core of Java isn’t awful, but the whole beans/Eclipse/ant/j2ee pool of muck absolutely repels me as a programmer.)

    • The answer is: be very selective about the programming jobs that you take.

      Jobs are going to last between 3 and 60+ months, and you’re hoping for the 60+, although 18 seems to be the average in our industry. Now, technical job searches last 2 weeks if you’re not selective at all, and 3+ months if you’re selective. Insisting on functional programming and doing things right will lengthen your job searches, for sure, but if you can afford the time without income, it’s worth it. Getting the right job also should lengthen job tenure and balance it out.

      Functional programming can be a ghetto job-market wise, but it’s rocket fuel for your growth as a programmer. Same for strong static typing when done properly (Scala, Haskell).

      I think, sadly, that you can only insist on FP if you’re in a technology hub (San Francisco, New York, Boston) or location-independent (i.e. established and mature enough that you can work remotely, and disinterested in leadership positions). The Great Lakes region (Minneapolis, Madison, Chicago) is my favorite part of the country, but if you have the double disadvantage of being in a non-hub and insisting on FP, I think your job searches are going to be really long.

  3. Pingback: Functional programming is a ghetto « Jelastic — Rock-Solid Java in the Cloud, Java Server Hosting, Java Cloud Computing

  4. I’ve been using Erlang for a few months now any am very pleased how it is helping my programming style to evolve. I saw some of that in this commentary when you talk about the default programming style.

    I was a little bit surprised when you decided to throw in some IDE hate in to the discussion which I think is irrelevant to the point you are making. Presumably you automatically assume I couldn’t be a ‘top 5% programmer’ because I like Eclipse.

  5. Hey, Michael. First, I wanted to thank you for your blog. It is a fantastic read, not just for programming or career advice, but on a number of other topics. It’s not often that someone that is a good writer happens to write on all of these subjects at one time, and in one place. So I think I am lucky to have not only found your blog, but to have shared it with others.

    The second thing is that I have shared it, but I am not sure if I have done it in a way that you would like, so I wanted to confirm. I reposted this article to my blog (my company’s blog — mostly Java since we are a PaaS for Java hosting) so that my readers (about 2k a day) would get a chance to read your stuff. I then posted the link to Hacker News and one of the users made note of the fact that it wasn’t my content (something I made clear, but nonetheless…): so I wanted to make sure that you were okay with me reposting your content. If so, you have a number of other great posts that I would like to share in the future. If not, please let me know, and I’ll remove it.

    Either way, you have a fan here, and many more now–I hope–due to the reposting and sharing.

    Cheers!
    Judah

  6. I really had to chuckle at the “Not in 2012. Java isn’t a language that people choose to use, not for primary development.” I suppose if you’re willing to sacrifice performance, stability, reliably, and all of the tooling around development, building, and profiling, tuning and debugging and the millions of libraries available in an easily consumable format… Ah screw it: Actually, Java is the language a lot of people choose. :) I suppose Twitter, Yahoo, LinkedIn, Google, Ebay, and a crapton of startups like Urban Airship, LMAX, etc are all doing it wrong, but I think I’ll just point to usage numbers instead.

    I guess my point is, I was nodding my head at the first couple of paragraphs, but it completely undermines itself by descending into a rant.

    I think there’s two main things wrong with functional programming. First, the community isn’t inviting and it’s becoming annoying: It’s filling with zealots that whine about Java. Second, today’s hardware isn’t friendly to functional programming. The memory model and stack machine specified by Java was intentionally designed so it could be efficiently implemented on x86 processors. The performance hit by choosing functional right now can’t be ignored. I’m hoping this can be fixed, provided the first problem is fixed first.

    • Twitter and LinkedIn are using Scala, which is a much better language that runs on the Java platform. The Java platform is quite good; the problem is the language (and the BullshitFactoryVisitor culture that has sprung up around it).

      Google has a lot of strong suits, but PL and PL selection are not among them. Google’s limited language white-list (C++ and Java, regardless of whether they’re the right tool for the job) is a source of major morale problems.

      I’d bet even money that the startups are using at least some Scala or Clojure, if only because it’s impossible to develop at a fast enough pace for most startups in an unexpressive language.

      The zealotry comes from experience in most cases. Bad code is so destructive and such a mind-eating time-waster that eventually, people start getting extreme in their views on how to attack the problem. Of course, there is bad code in functional languages; it’s just less common.

  7. Pingback: Functional programming is a ghetto | Platform as a Service Magazine

  8. Pingback: The software career and the Second Design Paradox « Michael O.Church

  9. I agree mostly, but I think you are not going to be well received by anyone at a regular company, including very talented programmers. I am vastly more productive in FP languages, or at least I still hate programming in OOP style. I think OOP just isn’t the way I think about programs, and I think there must be more programmers that feel this way. Functional and Logic programming felt almost immediately natural, in fact before I learned Scheme and Emacs Lisp, I was totally burned out on programming and never wanted to code again. It showed me that programming actually can resemble the prolog-like language that I dreamed of in high school math class — using “mathematics” to compute arbitrary tasks.

    I’m not a great programmer yet, (although I have a repository of Emacs Lisp that is 30,000 lines of very dense and useful code, written by me from scratch in a functional programming style — that language by default is a mess, I will admit…) but I’m incredibly productive and write high quality code in a language like Erlang or something related, it’s almost like night and day. If anything, my productivity given my lack of decades of industrial experience is more evidence as to why FP is such a great way to program: it makes me VASTLY more productive, and I am able to reason about my programs and ensure that they are correct, and equally importantly, concise.

    This, I think is an important question that OOP does not answer — is it Objects that allow for large scale programs, or are large scale programs allowed by OOP?).

    As you said, I’m not adverse to using languages outside of my comfort zone; I routinely use C for non-trivial programs, (in fact, I think all of my available projects on the internet are written in C because they are very OS oriented, outside of some released code in functional languages) among other languages such as Java, Python and so on.

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

  11. Pingback: Blub vs. engineer empowerment | Michael O. Church

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Connecting to %s