Joy Clark: Hello everyone, and welcome to a new conversation about software engineering. This is Joy Clark and today on the CaSE Podcast I am talking with David Nolen about ClojureScript.
Joy Clark: David is a member of the core ClojureScript team at Cognitect, and he has been so kind to take the time to talk to me today. Welcome to the show!
David Nolen: Hi! Thanks for having me.
Joy Clark: I mentioned that the topic for today is ClojureScript. Could you maybe briefly introduce ClojureScript?
Joy Clark: I'm a Clojure developer who has done that, so... We did do a podcast on Clojure itself, so we'll link that in the show notes. But maybe for those listeners who might have missed that episode, could you just briefly describe what the language looks like?
David Nolen: ClojureScript, or Clojure?
Joy Clark: Well, it looks the same, right?
David Nolen: If you're not familiar with Clojure or ClojureScript, Clojure is a functional Lisp, it emphasizes programming with values through a standard suite of relatively performant, persistent data structures. Clojure did quite a bit of innovation there when it was released in 2007, and those implementations were more or less ported to ClojureScript I think in 2012. So the same immutable data structures that you like and enjoy in Clojure are available in ClojureScript.
David Nolen: Almost all the standard libraries are mirrored... That's another thing that's kind of fun about ClojureScript - you get to have all this Lisp goodness when doing front-end programming. There is a small, but I think growing community of people who aren't coming from a JVM background, where actually ClojureScript is their first introduction to a Lisp, to functional programming, and then it's not uncommon to hear people really like it, and then be like "Oh, maybe I should check out Clojure, because ClojureScript is pretty cool." That's not how it used to be, but that's definitely a growing area of the user base.
David Nolen: If you think about ClojureScript, ClojureScript ships out of the box with persistent data structures; it's just the default. Every library that you might use that's written in ClojureScript - the currency is immutable values, so everybody is sort of bought in, and functional programming is highly idiomatic. When you meet somebody else and they say they do Clojure or ClojureScript, there are certain expectations about what that means, and assumptions that you might have.
David Nolen: If you're sitting down an API or a library, that's actually really freeing. You know that the people that might use your thing are going to understand the choices that you made. And that I think is the real difference. It's not a specific feature, it's "What's the philosophy? What's the frame of mind that you can expect when you're interacting with Clojure or ClojureScript libraries?"
David Nolen: Adoption trend...? It's more or less Clojure programmers, and that's to be expected. It was created for Clojure programmers, and most of the people that use it are Clojure programmers. Even the people that come to ClojureScript out of curiosity, it's more common that those people end up being like "Oh, I like Clojure." ClojureScript is an introduction to Clojure... So that's the main adoption trend.
Joy Clark: Where do you see the language heading?
David Nolen: We really don't try to do anything in the language that's different from Clojure. Most of the language changes happen in Clojure first, and then once they look like it's definitely going to be a certain way, we end up porting that to ClojureScript. Spec is a good example - Spec appeared first in Clojure and was available first in Clojure, and then slowly, over a period of several months, we reached parity, and so on and so forth.
Joy Clark: Yes, I have stumbled on that problem before. That's the externs file, right?
David Nolen: Yes.
David Nolen: Yes. Just to stick on that for just a moment - the Google Closure compiler is a whole program optimizing compiler, so its expectation is that it sees every line of code that will ever be run in your program. The problem is that you want to use a third-party library that's not Google Closure compatible that it's never going to actually analyze or look at. The issue is when you're calling out into what we call foreign libraries - these libraries that the Google Closure compiler will never see - in order to prevent Google Closure from either eliminating something that doesn't need to be eliminated or renaming a property... A huge optimization that the Google Closure compiler does is it takes your human-readable names and it shortens them down into one or two characters. But that doesn't work for properties that it didn't see, some property in a third-party library. In that case, you provide something called an externs file which says "There's an external library that exists, and these are the names that we're calling into, and it's not okay to rename those properties."
Joy Clark: I heard a rumor that that's not going to be necessary in the future... Is that correct?
David Nolen: It's going to require effort on our part to interact with that community and show them that it requires very small changes. My suspicion is for the most popular libraries this is going to be a pretty straightforward thing. And then it's going to be harder -- for just any old, random library it'll probably be a bit more challenging and we'll have to solve that on a case-by-case basis. But my impression so far is that if we could cover especially the React ecosystem, because so much of ClojureScript is around React and React-based libraries... If we could cover React and React components and the most popular libraries in that world, as well as React Native, I think the happiness level of the average ClojureScript developer would be greatly improved.
Joy Clark: I believe you. So is ClojureScript like a transpiler or a compiler?
Joy Clark: My next question is a bit of a personal one - how did you get started doing compilers? Was ClojureScript your first one?
David Nolen: I would say ClojureScript was my first one. I was always a fan of Lisp, so of course I've done some interpreters. And to be honest, if you've done an interpreter or two just for fun, then you kind of at least have some context for how a compiler might work. In an interpreter you learn how to make an environment... With Lisp it's easy, because you don't have to deal that much with syntax. And really, a compiler is -- instead of writing code to run the thing, you're just like "Well, we're just going to take what was an interpreter, and instead of running stuff, you generate some other thing."
David Nolen: So the early versions were pretty easy to understand, but I would actually argue that even though in this current state it does a lot more, particularly around the area of optimization, it's still a pretty straightforward, simple thing. I think a lot of people's first impression is that it's intimidating, and they play around with it and they're like "Oh, this is really actually a lot of fun, and it's actually not that hard."
David Nolen: I worked on it on my free time - ClojureScript was very much a free time open source thing for me for about three years, and then I joined Cognitect in 2014 and at that point, officially, a good chunk of my time is dedicated to ClojureScript, in a more official capacity.
Joy Clark: We'll link that talk in the show notes, so listeners can look it up late. Concerning the compiler itself, it's written in Clojure?
David Nolen: Yes. ClojureScript is written in Clojure, which is actually quite different from Clojure itself. Clojure is written in Java; the compiler, the analyzer and the data structures are all written in Java. ClojureScript, since day one, the whole thing was written in Clojure. Rich Hickey actually said in the early days "This is the first attempt at a Clojure in Clojure", meaning a Clojure that could be self-hosted. It actually took us four years to actually get to self-hosting, but that was the idea... ClojureScript - the compiler is written in Clojure, the data structures are written in ClojureScript, but it's Clojure...
Joy Clark: When you're running the compiler, do you run it in ClojureScript? You said that it could be self-hosted - does that mean I don't have to have Java installed? I mean, you need Java for Clojure, so...
Joy Clark: And do macros still work in ClojureScript?
David Nolen: Macros are different in ClojureScript than in Clojure.
Joy Clark: Could you briefly explain what a macro is for the listeners?
David Nolen: Yes. A macro is -- so one of the early discoveries around Lisp, since Lisp has this fairly self-similar representation... You have these S-expressions, and most Lisp systems act on that representation, but that representation is a data structure, right? So when you write a function and you (defun parameter-list body-of-the-function), well you can not only just run that thing, but it also is just a piece of data, it's just a list with symbols in it, and maybe some other data structures. And Lisp programmers realized "Oh, it's just a data structure and we have functions to manipulate data structures. We could just take an S-expression and transform it into something else and then evaluate that.
David Nolen: So the big idea behind macros is that because Lisp is homoiconic, as they like to say (Code is data, data is code), a macro is this idea of taking a source and expanding it into something else. It's so trivial in Lisp; most Lisp has this capability, and Clojure is no different. And ClojureScript has this capability as well. The difference though is that when we target web browsers, we don't wanna ship -- when you're writing a GUI app in the browser, we don't want to ship the analyzer or the compiler or all this other stuff that we use to generate the program, because that would bloat your final artifact. You would have all this extra stuff that you're not actually using in your UI, that we would have to hand to you. So ClojureScript's macro system is a bit different in that the macros are compile time only.
David Nolen: Some people refer to this as sort of like staging. So the macros that you write are written in Clojure, so that we don't need to include the analyzer, the compiler or the source-level reader inside of your running program. All this stuff happens only at compile time. While it would seem like it's a big limitation - and it is a little bit tricky to get used to it if you're coming from Clojure - this means that what you're sending (your final program) is really really really small. In fact, I think the entire ClojureScript standard library - if you're not bringing in a bunch of other dependencies - is under 30k. The entire core library is under 30k gzipped, which historically speaking, that's smaller than jQuery, that's definitely smaller than React, and all this is due to the magic of the Google Closure compiler, that even though we have this massive standard library that is quite small -- but if you were going to add all the stuff that you need to get macros at runtime, I think the smallest size you're going to see is more like 60k or 70k at minimum; it could be even bigger than that. It's been a while since I've checked. So that's why we don't do that.
Joy Clark: When you're using ClojureScript for doing front-end development, do you have to do the whole front-end in ClojureScript, or can you just choose parts where it's the most effective?
Joy Clark: The Google Closure compiler - does it do dead code elimination on the core library as well? The core library is probably pretty big, and if I don't use most of the functions - which I probably don't - will those also be shipped to the UI?
David Nolen: No. One of the tests that we do is just to make sure that we haven't messed up dead code elimination is if you write a ClojureScript program and the only statement in that ClojureScript program is js console.log("hello world"), then out of advanced compilation you're going to get something that's just a few bytes; you're not going to get the standard library.
Joy Clark: That's good.
David Nolen: Yes, it's also why I would say in ClojureScript as a general rule users are significantly more fearless about their ClojureScript dependencies, because they know -- if I take on a very large ClojureScript dep, I'm very confident that I'm only going to get the pieces from that dependency that I actually need, because Google Closure compiler works great.
Joy Clark: Great. Concerning front-end development, you mentioned that React is used in a lot of the libraries in ClojureScript. I've heard a lot of people describe React using a term like "the functional way to do UI design." Could you explain to me what that means?
David Nolen: ClojureScript is the functional way to do UI design?
Joy Clark: React. React is the functional way...
David Nolen: Oh, React is the functional way, sorry. The cool thing about React is React sort of introduced people to functional programming as a philosophy. People think that functional programming is like map and reduce, persistent data structures, or whatever, but that's not really true. To me, functional programming is a mindset about how one goes about organizing their programs. React, even though it had this object-oriented veneer, it really was getting people to think about a very functional approach to UI development.
David Nolen: A lot of people got hung up in the early days on this thing called component local state, but the truth is that if you think about component local state as like the transient part of your program and it's not the essence of what you're doing in the UI, then React is a very functional, friendly system.
David Nolen: I remember my friend Brendan Bloom introduced me to React, and I was very skeptical because I said -- of course, I also thought on the surface it looked very object-oriented, but I think I spent like four or five days and I realized that you could write a very clean binding to React with ClojureScript, and you could basically do functional UI programming in a way that at the time seemed to me very novel. The Clojure and ClojureScript community more or less came to the same conclusion. There's Reagent, there's re-frame, which is built on top of Reagent, there's Rum, you've got the library that I've worked on, called Om, as well as the successor, Om Next, there were other things like Quiescent... Everybody more or less jumped on board because React again, fundamentally encourages (in a big picture sort of way) a functional approach to UI development.
David Nolen: There are, of course, a lot of other problems that need to be solved, but to me it was a big step forward. Basically, the way that React works -- it's functional. You have a component, you pass some props, and then you have something that will get rendered by some other thing, and you don't really care. But it's a function of, you know, from your data to something that will get rendered by something else, and you're not really that concerned about how that's going to happen, and that's the big idea.
David Nolen: So there's nothing about ClojureScript that requires React, and that's very intentional. React is great, and there's a lot of excitement around it because of things like React Native and so on and so forth, but if you want to do HTML and you want to do lightweight scripting with ClojureScript, we've certainly made no choices that would prevent you from doing that.
David Nolen: Yes, it's a great point. Keep going, I didn't mean to interrupt.
Joy Clark: I just wanted to hear your thoughts on that. I feel like there's a push for using React and like a single-page approach to every kind of application or website on the internet, regardless of if it's good for the use case... And I guess I wanted to ask you how you would make the decision about what technology you would want to use for the UI.
David Nolen: For me it's quite simple - if I'm building an SPA (single-page app), then there's no problem with React. Or if I'm doing mobile, then I want to use React Native; it doesn't really matter. I have a blog, and my blog isn't so active these days, but my blog is a Jekyll blog with Ruby, and I do very light scripting with ClojureScript. I'll bring in Code Mirror, and whatever... I don't use React. There's all these use cases where there's no huge benefit from using React. I just need to program a couple of elements on the screen, and that's it.
David Nolen: For me it's just like it was before - does it make sense for the task at hand? Would I say that you always need React? No. Should you always design like you're building an SPA? It doesn't make any sense to me. I wouldn't encourage that or do it that way.
Joy Clark: Do you have any ideas about how user interface design might change the next few years? I'm just wondering what the next big thing is going to be.
David Nolen: I think the things to follow are no different than things that I think are interesting... It's not like I know the answer, or whatever -- the stuff that I like is good or bad. It's just the things that I think are interesting that have a high impact for UI, it's definitely GraphQL. The GraphQL approach will likely have a huge impact -- not GraphQL specifically as a specific technology, but just that idea, GraphQL and Falcor... This idea of allowing clients to have finer grain control over what data they pull from the back-end. It really can radically simplify how you go about doing UI stuff, especially for more sophisticated SPA-style applications. So I see that as having a huge impact.
David Nolen: I also think that it's not like that people have completely solved the new sorts of problems that React introduces; there's still a lot of friction that didn't exist when you weren't doing things in the React way. Traditional MVC has some nice properties that I would argue still haven't really been fully recovered in the React approach, and that's something for people to reconcile. I don't know if people are going to do it, but I would say there's some work to be done there. I would see that as being the next important step, to sort of reconcile the lessons of the functional UI with more traditional approaches. But I suspect it's going to take some time yet, for people to really identify that as a problem.
Joy Clark: With so many libraries being based on React in the ClojureScript world, do you think there will be an issue for the libraries with this -- there's recently been the outrage over Facebook's licensing treatment...
David Nolen: I think that's a team-by-team, company-by-company, case-by-case basis. I definitely sympathize with the frustration about that. My impression is that in the end most users really aren't that concerned about it, they just want to ship stuff. In the end, I see that as having a very minor impact... Largely because I view the Clojure community as being a fairly pragmatic community; it's sort of a community of people that want to ship stuff and get stuff done. In some sense Clojure and ClojureScript programmers are not purists. Clojure programmers are okay with the JVM, they're okay with talking to Java libraries. A lot of programmers wouldn't touch a Java library with a mile long pole; just the idea of Java being their stack is revolting, and Clojure programmers just don't have this.
David Nolen: You understand the value of what Java and the JVM bring. You don't necessarily wanna program it, but you appreciate access to that ecosystem, and I would argue that in the ClojureScript world it's the same. The React patent thing kind of sucks, but until somebody else comes up with something that has the same properties and has the same amount of reach, specifically something like React Native, I suspect you're not going to convince many people.
David Nolen: At the same time, my point there is that React could totally get replaced if somebody comes up with something that delivers the same value on the same level of reach, but I don't think the patents clause is compelling enough for people to -- that alone is not going to cause people to rewrite everything.
Joy Clark: That's probably true. You mentioned React Native a couple times - could you explain a little bit what that is and how that can be used to help create mobile apps with ClojureScript?
David Nolen: Yes. Something that a lot of companies struggle with - and I saw this when I was at the New York Times - is that you build an app, and then you have to build that app again with Java on Android; assuming you've done it once on the web, you have to build that app again on iOS, with Objective-C or Swift. And that's great when you have tons of money and can afford to hire tons of developers, and you can pay an Android developer, an iOS developer and all the QA-ing that that requires, and the testing that requires... So that's a real pain point. There are a lot of companies that would like to have a better, simpler story for reaching the major client targets without having to invest so heavily in so many different technologies.
David Nolen: You write your component once, and you can use that component on many different platforms. And the performance profile of React Native -- of course it's not going to be as good as if you just wrote it native, but the point is that you've really decreased the gap, where a much larger demographic of applications that you wouldn't have considered doing it this way, now it's fine... It's fine for a much larger set of applications, which is cool, and we see that - the amount of interest in the ClojureScript community around React Native is significant.
Joy Clark: What other frameworks and libraries are available? I don't know if we've mentioned any, but what frameworks and libraries are available for front-end development, or just development in general in ClojureScript?
David Nolen: If I wasn't using React, I would just be using Google Closure library. It's just a massive set of functionality for dealing with browsers. Basically, almost anything you could think of doing, they've done -- they've really thought through hard problems like internationalization, and it's constantly in development, it's not something that's sitting still. Google Closure library isn't just version-controlled, they just use it for master.
Joy Clark: What React-based frameworks or libraries are there in ClojureScript?
David Nolen: The most popular one is probably Reagent now, because it's pretty easy to use. I recommend it if you just want something that's basic React; it's very easy to get started with. If you're doing a blog, again, I would probably do what I've done, which is I wouldn't use anything. If you need something more sophisticated where you're expecting that you're going to have a more interesting relationship between the client and the server, then you have something like Om Next. You may find Om Next to be a bit too abstract, and the truth is Om Next is really a set of ideas, and in fact, I've actually personally worked on projects where we chose Reagent, and then we just had an Om Next architecture, and that worked great.
Joy Clark: Om Next is your library, right?
David Nolen: Yes. Om Next is basically just cribbing a bunch of ideas from GraphQL and Falcor and then just making them a bit more Clojury.
Joy Clark: Are there any major tooling efforts to improve the adoption of the language?
David Nolen: Of course, you have things that are not open source, things like Cursive for IntelliJ... That's actually really far along now. If you want an IDE experience for Clojure and ClojureScript -- that's what I use for work, and I think it's great. So that helps a lot.
David Nolen: Cljs dev tools for enhancing the experience in Chrome is also pretty cool. And then there's also some other interesting things... Another thing that we are interested in about is expanding Clojure and ClojureScript adoption, and we're always thinking about better ways to introduce people to the language. So there's nothing specific here to talk about, but I see things happening in the community where people are looking for better environments for people to be introduced to Clojure and ClojureScript, because I think one of the challenges is that Clojure and ClojureScript assume some familiarity with the Java ecosystem, so a lot of times when people get started, people do get hung up on the fact that they're not familiar with the Java ecosystem. There is a learning curve there, from "I just wanna play around", but then you have to know all this stuff before you can do that. So it's something that is definitely getting worked on, but it's going to take time yet.
Joy Clark: Are there any resources you can recommend for getting started with ClojureScript?
David Nolen: I would say the website is probably a good place to start. We have a tutorial there. Another place - the Slack community is really friendly, it's really active. It's clojurians.net. I recommend going there; there's a beginner channel. People ask advanced questions, they ask basic questions in the ClojureScript channel, and it's totally fine. There's also an IRC channel, there's a mailing list... If you're interested in learning, I would go to the website and then check out one of these community places to hang out.
David Nolen: Unfortunately, there's not really a book -- I take that back, there are books; they're online books. There's no printed book right now from a major publisher that sort of covers everything, and a lot of this is due to the fact that ClojureScript actually is still evolving pretty quickly... Again, not from a language standpoint, but from a tooling and JS ecosystem integration standpoint.
David Nolen: I definitely know and sympathize with book authors... They're afraid that if they write about something, they're going to miss out on very impactful changes, and I would probably argue that it's probably going to be another year before we're at a point where I would say it's harder for me to see bigger changes coming down the pipe.
Joy Clark: Thank you so much for your time. I thought it was very interesting. For all our listeners, thank you for listening. Until next time!
David Nolen: Great, thank you.