In this episode, we talk with Alan Dipert and Micha Niskin about solving problems and Boot.
You can send feedback about the show to email@example.com, or leave a comment here on the blog. Thanks for listening!
EPISODE COVER ART
In this episode, we talk with Alan Dipert and Micha Niskin about solving problems and Boot.
CRAIG: Hello, and welcome to Episode 111 of The Cognicast, a podcast by Cognitect, Inc. about software and the people who create it. I'm your host, Craig Andera.
Okay. Well, in our notes today, things we want to make you aware of, includes a number of conferences. The first one I'll mention is the FinDEVr's west coast conference. That's happening Tuesday, October 18th through Wednesday, October 19th, 2016. Our very own Timothy Baldridge will be presenting. This is a technology conference about the technology side of FinTech. If you happen to be in the Santa Clara area where that is being held and you can get there, then have a look. Look for the FinDEVr Conference. You'll find that.
Of course I can't not mention EuroClojure. That's coming up soon now, Tuesday, October 25th and 26th. Tickets are still available at this point, but quite a few have already been sold. We're getting into the later part of ticket sales, so if you're planning to go to EuroClojure in Bratislava, Slovakia, you should definitely go and pick up tickets. You'll find those at the EuroClojure website.
Michael Nygard, who has been on the show a bunch of times, one of my favorite guests, will be presenting at the DevOps Enterprise Summit in San Francisco, Monday, November 7th. That's the conference is Monday, November 7th through Thursday, November 10th. That again is in San Francisco, so you can look for the DevOps Enterprise Summit if you want to go to San Francisco and hear Mike Nygard talk. He's always great to listen to as, if you've listened to the show, you're well aware.
The O'Reilly Software Architecture Conference is also in San Francisco around the same time. That's actually Sunday, November 13th and Monday, November 14th. We will be holding a training course, a two-day training course also given by Mike Nygard. The title is Architecture Without an End State. This is not a Clojure specific course. I don't really have the space to describe it here. Again, look for the O'Reilly Software Architecture Conference and you'll be able to find details about it on their website.
Finally, I'll mention the Clojure/conj. That's coming up. That's going to be Thursday, December 1st through Saturday, December 3rd. I'll be there. I'll be teaching the Intro to Clojure course immediately beforehand, the two days beforehand. You can find all of the information about that at the Clojure/conj website at Clojure-conj.org. Always fun. Just a great time. One of my favorite things during the year is to go to that. Tickets are also still available for that, but there's no guarantee that will remain true forever. We're about two months away. It would not be a terrible idea to go and get your tickets for that. Head on down to Austin and join us there.
I think that's all I have for announcements. We'll go ahead and go on. Upcoming now is Episode 111 of The Cognicast.
[Music: "Thumbs Up (for Rock N' Roll)" by Kill the Noise and Feed Me]
CRAIG: Cool. Well, I think I'm set. How are you guys?
ALAN: Yeah, we're ready to go.
MICHA: Ready to go.
CRAIG: Excellent. Excellent. Excellent. All right, then. Here we go.
All right. Welcome, everybody. Today is Friday, July 29th, 2016, and this is The Cognicast. I am very pleased today to welcome back to the show two friends of mine, Alan Dipert and Micha Niskin. Welcome to the show, guys.
ALAN: Thank you.
MICHA: Thanks. Yeah, it's great to be here.
CRAIG: They are both developers at Adzerk. Alan is a former coworker of mine. I will point out he was the first ever guest on The Cognicast, coming up on six years ago now, although we never actually aired that episode. Alan is one of the mysterious lost episode guests. Alan, I think you may have been the guest on every episode that we never aired for one reason or another. Anyway, it's been quite a while since we've had you on, but really, really glad that you're back to talk to us again and super excited to talk to Micha as well. You guys have done some really cool stuff that we will get into.
But before we do that, we are going to throw to you the question that we always throw to our guests, which is, at the beginning we ask people to relate some experience of art, whatever that means to them. Even though you told me approximately 30 seconds ago which one of you was going to do this question versus the one we ask at the end, I've already forgotten. Which of you said that you would like to answer the art question?
MICHA: Hey, this is Micha. I will. I'll do it.
MICHA: Two things, actually. I saw the other day a picture of a newborn baby's skull without any flesh on it. Seeing how the teeth are, you know, kind of cued up inside the jaw, man, I cannot get it out of my head. I don't know if this is exactly art, but, man, it's an image that I can't stop thinking about.
But, like, for actual art, there was a guy. He would take, like, an aluminum, a big aluminum plate, like 20, 30 feet square and put an emulsion on it and then made a camera obscura where he would take a landscape shot and develop it on this plate. You could go up to it, apparently, with like a magnifying glass and see more and more detail because it's like infinite depth of field. That was super fascinating to me, the idea that you could have, like, this enormous image with just endless detail, as much as you could ever want.
CRAIG: Now I feel like I want to do that, but for a baby's skull. Both of those are super cool. The baby's skull one obviously is a little – I don't know. I guess I find it a little – I think if I saw it, I would have a hard time forgetting it too. But to me, kind of art is something that someone does with the intention of making you feel something, and I could well imagine that falling into that category. The camera obscura thing is also very neat. We'll make sure that we drop a link to that in the show notes so people could check that out too.
MICHA: I'll have to find it.
CRAIG: Yeah. No worries. We can look for it too. That's very, very cool.
Well, so you guys have been doing cool things together for quite a while now. Kind of the reason that I wanted to have you on is that, Alan, you actually were on the show over two years ago now. At the time, we talked about boot and hoplon and javelin. I feel like those were really good ideas then, and they are still really good ideas now. But one of the things is that I've actually been starting to see more of them out in the Clojure universe. People around here have been talking a lot about boot lately.
I have actually personally switched over to using boot and hoplon and, of course, by extension, javelin. We'll explain what all those things are, to our listeners who aren't familiar, in a minute. I've been using all those for my personal projects lately, and I've really been digging it. They're different from some of the other things that are out there right now, and I just thought what a great time to follow up with these guys to go back and revisit those topics to get more in-depth into them, especially now that I have a little more context and maybe I can actually ask slightly more intelligent questions. Of course, like we always say, and this is always true, we'd love to hear about whatever is interesting to you, but are you guys up for a chat about some of those things on the way to whatever else we talk about?
CRAIG: Excellent. Maybe you could just start with talking about this triad. I know that they are things that you can independently: boot, hoplon, and javelin. But maybe you could just give us the tour for anybody that hasn't encountered them.
ALAN: Well, I think I might take a tack with this that Micha took with a podcast he was recently on, the Defn podcast, which was a fun listen for me. The way he began telling about the trilogy is basically how Micha and I met. Micha and I met in a context that had nothing to do with computers. In fact, we were maybe even starved for the keyboard. In the Army we did work that had nothing to do with computers, but he was the only programmer I ever met, so we would often have conversations about computers and programming. Micha was one of the few people I knew who had actual C programming experience, and I knew a lot of things about the Web that Micha didn't know, so we had a lot of interesting conversations.
It's funny. I feel like a lot of the most interesting conversations about computers and programming happen at times and in places when the keyboard and the computer and Wikipedia are far away because that's when you're really forced to imagine what could be.
ALAN: We had a lot of those kind of conversations. Then when we both left the Army later, we started to work together at places. This is another kind of cool phenomenon in the professional computing world that I know a few groups like us who sort of do this, but basically you work at a company and then you can influence hiring. You know who you work with well. You look in your address book, and you call those people up. You get them into a team.
I think some company out west even started hiring teams. Just flat out they would hire groups of two or three people. I found that my professional trajectory has kind of orbited groups of people and individuals and one of those individuals is Micha. The same is true for him. We were working at places, and we would hook each other up with contract work or jobs at those places.
As we worked together more, we started to develop – I wouldn't call it a philosophy since it's not formalized at all, but basically when you work with someone or a small group of people, you develop a way of working. You develop a perspective on how you gather the information and materials together that you need to do work, the toolset and the outlook. I think, after that, after you've done some things together in a small team or with another person, then you start to develop actual tools that you use to do these jobs that both people know how to use.
Boot and hoplon and javelin are things that emerged from that collaboration. They are more or less tools that followed conversations that Micha and I had. We would independently go research things and build our own prototype things. Show them to each other and argue about it, and then we ended up arriving that these set of tools, I guess, a few years ago is when we arrived at them. Not much has changed about them since I last told you about them two years ago.
MICHA: Yeah, I mean we were basically, like, in it together, like doing – you know, working, trying to make money and there were problems that we needed to solve to be able to – you know, you don't want to solve the same problems all the time. So, you know, little bit little, we were working on these problems. Because there were two of us, and because we were always working on the same kind of things, we could be a little bit more ambitious. You know what I mean?
For us, we've solved some of these problems forever. We're just going to use the things now and we do other things. You know?
CRAIG: Mm-hmm. Yeah.
ALAN: Yeah. Yeah, I guess if we had a dynamic, it would be maybe the idealist and the skeptic. I'm pretty idealistic about computers, and you know what a gift to humanity they are, and Micha is right there to cut me down. He freely mentions how anything computers do instantly make worse and there's all kinds of holes in this idea. But if you go back and forth like that with somebody, particularly if it's a friendly rapport, I feel like we've managed to make some decent decisions, or at least come up with a set of tools that we both like to use.
CRAIG: Yeah. Go ahead.
ALAN: Yeah. This is a roundabout way of getting to describing what boot, hoplon, and javelin are, but boot is a build tool, basically. It's more a library of Clojure functions that help you craft your own build tool to match whatever your build scenario is for any definition of build that you have, which makes it difficult to explain, but we'll get into that, I'm sure.
We came up with the idea for boot after working on a Web framework called hoplon because the Web of today requires sophisticated tooling to get anything done just because there are so many technologies, file formats, and….
MICHA: Yeah. Not only that. At the time, so this was in, like, 2012, ClojureScript was pretty rough then. It was still awesome, but we needed different things. Having our own – you could do a lot of things in the build process if you have a flexible enough environment to build in, and that's where we found. We didn't have that, so we made it.
In hoplon, originally, there were a lot of things that were actually going into the ClojureScript world and changing things around. So implementing stuff that we wanted, but it doesn't make sense to go and try and get it into the ClojureScript compiler. We just want to get work done. If it works out, it could be, you know, upstream can take it. But right now we want to get our work done. You know?
ALAN: Yeah, so boot basically filled in the holes that were missing for us in our workflow because we were very convinced that ClojureScript is the way to build stuff, especially when we need to build a single page app. But the tools were not just immature. They're more or less nonexistent. The line cljs built predated what we were doing, but it was not used very widely, and ClojureScript, in general, wasn't.
Then javelin is a ClojureScript library that was part of the hoplon framework. They're all loosely related to each other through this goal of ours back in 2011, 2012, to come up with a solution for building Web apps. But now they're usable separately from each other. You can use boot without using hoplon. You can use javelin without using either. They're definitely separate pieces.
CRAIG: Yeah, and so of the three, I think boot is the one that people are most likely to encounter simply because the other two are ClojureScript specific. Boot, of course, is usable even if you never touch ClojureScript. I think it exists in the same space as Leiningen. That's the tool that most people are using that if they go use boot, then they're no longer using Leiningen, which is what I've done. It's kind of an either/or. Although, I believe there is some. Maybe you guys can talk later about what it would mean if anything is sensible to use both.
But I've been using boot for this process of building. The thing that I've been struck by, really–and this is something, Alan, that you explained to me last time, but that once you get a chance to use a tool that sometimes is what it really takes to kind of start to viscerally understand things–is that it really is quite a different approach in that it feels more like programming Clojure, about writing functions and passing data through functions than something else where you have like a DSL and you're building an interpreter over that DSL. Right? Does that make any sense?
ALAN: Yeah, totally.
MICHA: Yeah. The way I see it is the boot, I mean the reason why it's called boot is because all it really does, like the objective of boot is to bootstrap you to a place where you can program in Clojure. It's like the minimum that you need to get Clojure, to make a Clojure program that will do something useful. But then, additionally, it provides some functions that you can use, like namespaces, libraries, and whatnot that you can use to do things that you commonly want to do when you build stuff. But primarily it just gets you to a place where you can start writing a program. Then you can do anything.
CRAIG: Right. Of course, you guys do provide some. Actually, that's a good question. What does it look like to start a project in boot? If I'm using Leiningen, I say "lein new" whatever and then I have a project CLJ. Then I say "lein REPL," and now I've got a REPL, and I'm off and running. I add dependencies in my project CLJ. For people that haven't used boot yet, what is the process like for boot? Then we can get into how you advance your project, like how you go beyond the default. What is the sort of default introductory user experience?
MICHA: What do you do?
ALAN: Well, I think for the default – so, you know, project, I think is a pretty overloaded term because it can mean one of experiment, application, or library - in general. An experiment is something where you don't even care to have a file. You just want to see how some library works or try out some function idea you came up with on the train or whatever. There are libraries where you already have some code or some idea for what you want to create. It's going to be supporting some other application, which is a separate project.
Then you may have an application, which is going to be code that's purpose built to solve a problem in the real world outside of the domain of programming, probably for your client or your boss. All of those three things in boot have the same starting point, usually, which is the boot command. You can start development on any of those three kinds of things just by typing "boot REPL," and that gets you to a Clojure REPL.
The biggest distinction in the beginning part of a project between boot REPL and lein REPL or Clojure's native REPL is that boot has the ability for you to bring in dependencies from the REPL. So you don't need to specify your dependencies in a file before starting the REPL. At the REPL, you can bring them in. This is analogous to, I think, a lein plugin that Ryan Neufeld wrote a couple years ago called lein-try, and the idea is you want a REPL with a dependency on it just to experiment. That's where a lot of projects begin. That's probably how most or at least how I start almost anything with boot.
Then for an application or a library, you're going to probably have some idea ahead of time of what dependencies you need already. You're not going to be dynamically discovering things trying libraries out. You probably have an idea of what you want to work with, so you'll create a build.boot file. That's analogous to pom.xml or project.clj. The main difference is that a build.boot file is a Clojure program. It's not a language other than Clojure. It's interpreted by the Clojure evaluator.
MICHA: Yeah, because the boot tasks are just functions – well, everybody always says everything is just functions, but anyway you can compose them like functions and call them like functions and stuff. We have a library, this bootlaces library, but that's kind of what I do. I pre-stage my own little workflow as prepackaged tasks. I can pull that Maven and have it loaded. Then I have the normal ways that I build jars and all that stuff, you know, configured the way I like it already set up.
ALAN: Which is kind of analogous to the way that compile and run time are interleaved in Lisps traditionally in the sense that a defmacro and a defn can inhabit the same runtime. You can defn something and then make a defmacro where you call that thing that you defn. Then you make another defmacro, so the phases of macro, expand, compile, and run are interleaved over the lifetime of your execution. This is the sequential evaluation model of Lisp interpreters.
Boot kind of supports that, so you can create a boot task, run it, edit it, reload your build.boot file, try it again in a build tool that has a static build description language like Make or Maven. You're going to need to edit that file, shut down your JVM, restart your JVM after you've edited the file. I would say it's just Lisp-ier, in general.
CRAIG: Yeah. That's exactly one of the things that I've really been enjoying about it. I think the one that hits me right away is the one you mentioned, which is the ability to pull in new dependencies dynamically and to really – I mean, you know we talk about you could sit down at a REPL and build your whole program, right? You could just say, defn, defn, defn. Oh, I'm going to redo that one. I've got state. Boom. I have a running program. I never saved a file, really. I just typed it all in.
CRAIG: I think it's kind of the same way that you could do with boot. Now the same way that you don't typically create production systems by opening up a REPL on the prod box and typing until the system is working, you would probably not create nontrivial systems with boot by simply building it up. But you can, and then you can go from that to kind of capturing what you've come up with interactively and working with that. I really, really like that approach. It resonates with me very well.
I think there's another thing I would like you guys to comment on is how much of this was planned, how much of it you think is an outcome of the philosophy that was happy accident. It seems to me one of the places where boot really shines is actually hard to explain to beginners because it has to do with the wins that you get as you get into projects that are less trivial, that are more kind of industrial strength.
Micha, you said, "The way that I like to work." Well, you have these projects and, over time, you're like, oh, we have to have some special asset built, asset pipeline build because people from the documentation team are sending us Word docs, and we need to transform those somehow. We want to integrate that all in. You wind up with these extra bits that you need to do. If you have the DSL approach, then you have to write an interpreter and find a way to express it or do some other type of integration. Maybe it's a bash script.
With boot, it's really – let's have an execution model so that, since my model is execution and it's in Clojure, I start right there. I say, well, I have a process, it has steps, and it does things, not a language where I say things and then I have to write something that knows how to speak that language. I don't know if that makes any sense.
ALAN: It makes a lot of sense, and it actually gives me a thought of how to set up Micha to explain it. I'll try this. I'll try to–
MICHA: Okay. Hit me.
ALAN: –pass it to Micha and then he can spike it.
CRAIG: Bump. All right, I did the bump. You're doing the set. Got it. All right.
ALAN: Okay. Yeah, I'll set it up. I heard Rich Hickey say, maybe in a talk when I was in the beginning of my Clojure learning five, six years ago, seven years ago, about why Java "won" and C++ "lost." Now, of course, C++ hasn't lost. A lot of people use C++, and there's definitely a space within application and library development where C++ is very much alive.
I think 15 years ago or 20 years ago people saw Java and C++ as competitors in the development of large-scale applications where large-scale is some function of application size and team size. He made the point that Java developed over time this library ecosystem where C++ more or less stagnated as far as libraries go. His reasoning for that disparity was Java gave library authors the elements they needed to capture workflows in a way that could work universally. One of those key things is probably garbage collection.
You can't combine libraries that have different strategies for allocating and de-allocating memory because each of those strategies forms a lifecycle and it's very hard to interleave resource dependent lifecycles. It's just a super hard problem coordinating IO like that, and that's basically the problem that garbage collection solves. Obviously there are tradeoffs involved, but if you want to share workflows and combine them meaningfully, you definitely need garbage collection.
What garbage collection lets you do is have what you might call first class data structures in the sense that the system supports the tracking and management of anonymous structures, so functions can take managed structures that are managed invisibly by the garbage collections underlying part of the language run time, and they can also return these structures. They don't need to manage them while they're using them. That lets us bundle up solutions to problems in ways that are very easy to consume.
I think one of the things we came to appreciate after working on boot, and I should say it's not like all the pieces of boot we just figured out in one of our conversations in the Army and then sat down and typed it out. It's definitely been years of fumbling, hitting guardrails, slapping each other around, and eventually arriving at something that works. But one of those things was identifying what are the parts, what are the aspects of build processes that are preventing us from doing this like programming? What is preventing us from capturing workflows and sharing them in libraries like the way we do in the JVM or in Clojure? I think the two things in boot that represent those first class structures are pods and file sets.
ALAN: Then, Micha, it's over to you now to spike it.
MICHA: Yeah. A weird thing, well, a different thing about boot is that there's no dependency graph or anything like that. Boot isn't going to do anything. Boot doesn't try and figure out what you're trying to do, and it won't do anything unless you explicitly tell it to do it. You need to call a function or compose some things together and then call that. That's kind of different than any of the other things that I've really used in the past.
But one of the things that means is that it gives you – I think it gives you a lot more flexibility and reach because, to the programmer when you're setting up a workflow, a pipeline, it's obvious to you what you need to do first and what you need to do next and so on. But it might be very, very difficult for the computer to figure out what the dependencies really are.
You might make a mistake and, when you do your build, you see immediately what went wrong, and you reorder things. To a human it's pretty obvious what you want to do. You just have to have a very direct way to tell it, to tell the computer to do it. Lisp obviously gives you the best way to describe to a computer what you want it to do. That's one part.
Another part is that a lot of the more odd things in boot arise from the need to keep this JVM alive for as long as possible because it's expensive to keep restarting JVMs and stuff. That means that we have to think really hard about how to manage the mutable JVM sub-strait and build things on top of it that you could still program with some of the affordances of immutability. That's where pods and the file set kind of come in where you can isolate things that mutate. In other words, you can make a pod that isolates classpath mutation, and you could have that pod creating files in an anonymous, temporary directory that only boot really knows where it's located. Then you could take those files and add them to a file set, which is an immutable representation of the class path of the main pod that you're in.
Yeah, I think a lot of it kind of immerged from the fact that there is a need to get incremental compilation and long-lived. You know, like that's a lot of the reason why the REPL, why there was so much emphasis on everything being workable from the REPL because you have a long-lived REPL session and you want to leverage that. You don't want to have to keep restarting it. Yeah.
CRAIG: Right. You mentioned a couple things in there. A lot of super interesting stuff, but you mentioned, concretely, pods and file sets. I have to say, as a relatively new user of boot, these are not actually things that I am smacked in the face with. I know they're there, but I write a build boot file and I kind of say boot REPL and maybe a couple other things. It's fairly easy for me to add my own steps into the build and whatnot. I haven't really had to confront what a pod is, what a file set is, so educate me. What are these things and how would I use them? What am I missing out on by not taking advantage of them?
MICHA: Man, you know, that's actually – that's a thing that I really – I like it when people say that because I think it's really great to have software that separates architecture from building an actual application. Meaning this is what we try and achieve with hoplon as well where you make a bunch of libraries where the actual functionality is, but you should be able to assemble an application out of those components just by composition without knowing too much about the internals. If it's really done well, then there are so many ways that you could compose them that you could stay out of that world unless you need to do something novel.
I'm glad you said that. It makes me feel good.
CRAIG: Good. Yeah. I have quite enjoyed it. We'll talk more about my experience because I've been primarily using it with hoplon, and maybe when we talk about hoplon. But explain to me what–? Given that I don't have or have not yet had to know, I still am enjoying boot enough that I'm like, well, at some point I'm probably going to want this stuff. Arm me. Arm me with the knowledge of what pods and file sets are so that when I have a problem, I will go ah-ha, that is a file set shaped problem.
MICHA: Sure. Maybe I'll do file sets and then Alan can do pods.
ALAN: Yeah. I guess it's worth saying that kind of the three pillars of boot are probably tasks, file sets, and pods. Tasks came first, and those are the things that are just functions. Pods and file sets came after when we really wanted for tools to do functional programming in the build setting. It turned out the tools….
MICHA: …build large projects too.
ALAN: Yeah. Yeah, and it turned out the tools we needed to work with these things were not functions. We had functions up the wazoo. We were composing them and calling them. But the problem is, to do functional programming, you need not just functional – not just functions. You need really immutable collection types and immutable aggregates that you can build on incrementally, immutably, and efficiently. I think pods and file sets are really the values that you work with, with tasks, which are functions.
MICHA: Yeah, so maybe we do file sets first because pods are more useful when you're using them kind of with file sets.
ALAN: Yeah, or we could do a problem approach, like you're building a thing and you want to do some kind of processing, and how do you do it.
MICHA: Yeah. I mean for file sets, though, at the high level what you want to do in a build is you have a bunch of artifacts, which is things that are on the classpath in the JVM and things that might end up in some kind of packaged artifact like a JAR file or just a directory that has a bunch of files. Whatever you want at the end, like when boot stops running, you're going to want to have something, usually. It might be something that you ship to S3, so maybe it never exists on your disk, but there's this concept of having an artifact that you're creating. In order to create that, you take some source files that are usually in Git or something. These are the files that are owned by you that you're working on. Then you run this build process on it, which performs a number of transformations and does a number of steps sequentially and, at the end, produces these artifacts.
Working in the JVM and in Clojure, you're going to need to manage the classpath, which means you could pull in JAR files and things like that, which are treated more or less immutably by the JVM, meaning once a class loader has loaded a JAR in there, you can't really unload it. But there's also immutable classpath, which is you could add a directory to a class loader. You could add, remove, or change files from there, and it doesn't cache them. It doesn't cache the byte code that was generated from them.
Part of what boot does is manage the classpath for you. The reason why you'd want to do this is because one task might create some files that need to be on the classpath for the next task because traditionally all the actual Java machinery that you're going to use, like the Java compiler, the ClojureScript, the Google Closure Compiler, all these big, giant projects that predate Clojure, boot, and everything expect to find things on the classpath and they put things back somewhere in a directory, usually.
We needed to work within that world. We don't want to throw away everything from the JVM. That means that when a task is doing its work, its input is generally going to be on the classpath and its output is going to go into some directories or something. Then we're going to want to take the output, maybe, and merge it into the classpath. That's where the file sets come in.
The file set is an immutable snapshot of all the files related to this build. Some of them are on the classpath. Some of them are not. They're organized in different ways. But it's like an immutable snapshot of the file system and its physical manifestation, sort of, is a record type, so a Clojure record, which is an immutable data structure. Given a file set object, this immutable record, you can call methods on it to sync it with the file system, say, which means make the real file system and the real classpath and so on like my file set object. You can also do Git-like operations, so you can say, add all the files in this directory here to the file set.
ALAN: Underneath it is the implementation of it is more or less Git, content address stuff.
MICHA: Yep. Yeah, so you can add files and then commit them. When you commit them, they get synced to the file system. Then you can pass. You can hold onto a file set, so if somebody passes you a file set, you do some work, maybe create a new file set, give that to someone else, but you can still hold onto the one that you had, which is the benefit of immutable data, right? If you want to roll back time and reset the file system to where it was when you first started, you can just commit the file set object that you've saved. The file system will be just like it was in that state.
The idea is that a task gets a file set given to it. It's an immutable representation of the state of the file system. Then it does some work, which is for side effects, creating files and things like that.
ALAN: Compiling stuff.
ALAN: Less Java, AOT, Clojure, whatever.
MICHA: Making ERB files into HTML files, whatever it is.
MICHA: Then it takes the output of that and adds it back into the files to a new file set and then passes that to the next task. This is good for, like, the incremental build cycle because the pipeline is a bunch of nested middleware, kind of like a transducer, and it can keep calling itself. Each step can call the next step one time, zero times, or many times–however they want–and pass it, you know, a saved file set.
CRAIG: Mm-hmm. Right. That's the pipeline aspect. Right?
MICHA: So the file set was necessary for the pipeline to work properly because you need to be able to rewind to any step in the pipeline to rerun it - if that makes sense.
CRAIG: Actually, I don't quite follow that bit. What is the–? Maybe you can help me with an example of where I would need to rerun some step of this process.
MICHA: Sure. I made a task recently. I wanted, in ClojureScript, to be able to do refer all and use accept. You know what I mean?
MICHA: In other words refer all the names. I don't want to distinguish between macros and so I thought it could be done. I was like the first thing I'll do is I'll make a boot task to transform a file into a different ClojureScript file, right? I have foo.cljs in my source directory of my repo, and I put NS+ instead of NS. I make a boot task that looks for every CLJS file in my project and, if it sees that the first form is NS+, it's going to perform this transformation, which finds out which things are macros, which aren't, and adds them and transforms it into a regular ClojureScript NS macro.
What I want to do, though, is I want to replace the file that was there. If I made foo.cljs in my project, I want it to just replace that with the modified one so that it can go through the compilation, the rest of the pipeline, which includes maybe the ClojureScript compiler and stuff like that. They won't even know that this transformation took place.
In order to do that, you really need to have some kind of immutable representation of the file system because you're actually replacing a file with a different one. If I'm running an incremental build where every time I change a file it rebuilds things that have changed, so whenever I type in foo.cljs and I save it, it's going to run this thing, this pipeline again. And so it needs to be able to start off, to undo the changes that were done by subsequent tasks.
CRAIG: Hmm. Yep, that makes sense.
MICHA: You know what I mean?
MICHA: I mean because you're doing destructive actions, mutating all over town however you want, and so you need to be able to roll back those commits. Reset minus, minus hard, is basically what it is.
CRAIG: Yep. That makes a lot of sense. That example is a good one, I think, because you mentioned the NS macro. That's actually a tough one to do any other way, right?
ALAN: Yeah. Yeah, the NS macro is maybe the one thing in Clojure that the user has no control over the operation of.
ALAN: It's funny. Over the years since we started on hoplon, we've added all kinds of cool features to Clojure like multiline strings. What else? All kinds of automatic refer stuff because basically we'd be working on these big applications and it's like, man, who wants to copy a 20-line NS thing into every single file that they're working on? This is where the build tool needs to help us because the language can't. You know just the way Clojure works, we can't draw that up.
Historically, we've been pretty skeptical of features going into Clojure that solve these problems because our view is kind of if the build tool can solve it then the language should not because every time something goes into language, everyone has to use it. But we're kind of–
MICHA: And the administrative overhead of, like, you know, just discussing with hundreds of people when you could just have your own – you know what I mean? Like ES6 versus making a macro that gives you let in five minutes.
MICHA: We wanted to be able to just make whatever crazy thing that maybe is unwise, but we could do it inside of our build task. Nobody needs to care.
ALAN: Yeah, we needed no approval.
ALAN: Yeah, so we have kind of this suite of experiments, really, extending the language syntactically, semantically, in various weird ways. Boot is a great way to do that, and I would encourage people to explore that aspect of using Clojure because I think if you've used it for more than a few months, you probably have gripes and you might be able to craft it into something that you like more.
CRAIG: Yeah. I think the analogy is if you're working in a language like Java, there are a lot of things you can't do and you wind up repeating yourself a lot. Then people say, well, why do you like Clojure? It's like, well, because of that. Right? Because I don't have to do almost any of that any more. I can mutate the language to fit my needs. I think what you're saying is that although boot is not limited to that, it gives you even more power to do that when the language can't or doesn't.
ALAN: Yeah. It gives you a limited form of syntactic extension of Clojure, which is traditionally poo-poo’ed. But we know when you own the files that the syntax is in, you can do whatever you want to them before you hand it to the Clojure compiler.
ALAN: We found doing that was pretty useful.
CRAIG: Yeah, you use it to good effect in hoplon, which I hope we will – I might have to have you guys on again at this point because this is super interesting and I want to move on yet.
CRAIG: You certainly use it to good effect in hoplon where you have crazy stuff like you write what looks like HTML, what any designer could pick up and look and say that looks very, very familiar. Yet at some point it turns into something else. It's very cool.
ALAN: Yeah, we're kind of calling off that experiment, though.
CRAIG: Interesting. Okay. All right, well, we'll have to talk about that. I actually haven't gone down that road, but anyway.
CRAIG: Let's not lose track. File sets I understand. Great explanation. I get why you'd want to have that. I think it's pretty straightforward.
The other thing we wanted to talk about, though, was pods.
ALAN: Yeah. I can maybe try and do that one.
MICHA: Yes, please.
ALAN: The JVM is a very compelling platform for many, many reasons, but maybe one of the most underappreciated and misunderstood and maybe even hated feature is this concept of the classpath and the business with class loaders. This is like mid level to advanced sort of Java person adventure at some point if someone interacts with class loaders and dynamically adding Java classes or resources to the classpath depending on various situations. It's something people will run up against at some point in their usage of the JVM platform regardless of what language they're on.
They're one of those things that are very unwieldy, but it's also very powerful. Once you understand how class loaders work, you can do some pretty powerful things. Java application servers are examples of things that people have built that are based on the utility of the class loader, the idea that you can have a JVM, for instance, serving multiple different Web applications, and each of those Web applications is its own set of dependencies. Maybe a different version of the same dependency. The way you can do that is with class loaders.
The class loader thing is not – I'm not aware of any other language run times. I don't know much about the CLR. I'm not sure if it has a class loader type thing. But the really weird, compelling thing about class loaders in the JVM that distinguishes them is that they are values, more or less. They're first class in the sense that you can create a variable that contains a class loader where a class loader is effectively a global scope for some execution context.
Code that runs inside that class loader can see things that code running outside of it can't necessarily see. It's almost like you're running JVMs within JVMs for a lot of values in JVM. So it's a scoping mechanism. It's basically a first class global scope.
But because it's so difficult and tricky to work with traditionally, few people, even if they need them, sort of shy away from working directly with class loaders. There are some gotchas, some historical things about class loaders that make them kind of daunting. But any JVM language makes good use of class loaders, and anybody who is doing any kind of application server type stuff where they have some kind of container for other kinds of app is going to do class loader stuff.
Pods in boot are basically the working person's practical class loader. It is a set of functions that give you the ability to create a class loader, more or less, and to run code inside of it, and to get and to ship data to and from this isolated environment. It's like a very lightweight container.
MICHA: Clojure runtime specifically.
ALAN: What's that?
MICHA: Specifically Clojure.
ALAN: Yeah. Yeah, so each pod is an instance of the Clojure runtime running inside the same JVM that the creator of the pod is running in. But it's a totally different Clojure runtime. For instance, if you do def X1 in the parent Clojure runtime, but then in the pod you do def X2, and then you evaluate code in both places, in the runtime where you created the pod X is going to be 1. Inside the pod, X is going to be 2.
They're different Clojure runtimes, but they're also different JVMs to the extent that you can use boot's dependency resolution set to load dependencies into pods that sibling pods or parent pods will not see. And so the utility of this is, I guess, one of the reasons I use pods a lot is we do a lot of stuff on AWS. When I can, I use Clojure libraries that add niceties to working with AWS Java APIs. The problem, though, is that a lot of these different Clojure libraries depend on different versions of the AWS SKD, which is a massive dependency, and you can run into weird problems if you load it multiple times, different versions of it.
One mitigation is you can add. You can create a pod, so you create a Clojure instance. Then you add dependencies to it. For instance, the AWS SDK and then maybe Bandalore, which is a library for working with SQS that depends on the SDK.
Now inside that pod you can run Clojure code that uses Bandalore, uses that version of the AWS SDK, but is not impacted by whatever version of either of those libraries you load into the parent pod or the parent environment in which you've created the pod. It's a way for you basically to program as if you're spawning new JVMs with totally different sets of dependencies and then communicate with these runtimes. That really reduces the likelihood of you running into strange dependency problems. They're, I guess, a mitigation tool, a tool for mitigating classpath issues.
CRAIG: Would you use this at development time for an exploratory program, or is this something that you would deploy? What's the use case here?
ALAN: I guess there are two. The first use case that it was developed for primarily was, say you're writing a task. Say you're writing – say Micha ships a library that has this NS+ library in it. He depends on some other library. What would be one that you would depend on? Tools namespace or–
ALAN: –ClojureScript Analyzer.
MICHA: Anything from Apache with a million dependencies.
ALAN: Yeah. StringUtils from IO Commons or whatever he uses in there. Let's say he distributed this not as a boot task, but as a library, just a Clojure function and a Clojure project with dependencies in Maven and a single function that maybe let's say it takes a file and it rewrites it into one of Micha's NS augmented files and ClojureScript files.
I would look at this. I would be like, well, I want to use Micha's thing. I have a build going on over here in boot, but I see he depends on, like, all kinds of stuff from IO Commons and whatever that conflicts with things that are already in my application. The question is, how can I integrate Micha's cool function for transforming files into my build without messing up my build time dependencies and potentially my runtime dependencies depending on what I'm doing? The answer there is I write a boot task and, inside the boot task, I maintain a pod that contains an instance of Micha's library that's totally isolated from everything else in my application, and I can feed it files to transform, and I can get files back from it that have been transformed. But that is totally isolated from a dependency perspective from the rest of my JVM or my runtime.
In the build context, pods are a way to use libraries from the Internet from Maven that do useful things, integrate them into your build process without imposing on yourself any kind of classpath pollution or overwriting or general classpath problems. Basically, you bring them in scot-free. That's kind of the reason we came up with them.
The second reason you might use them, which is rarer, is if boot is the entry point to your application in production. In most cases people are –say you're building a Web app with boot. What you'll do is you'll work with the Web app locally with the boot REPL or you start a local ring jetty or you'll use the Web serve task to work on it locally.
But at the end of the day, you want to ship a WAR file. That's going to go up to Heroku, Beanstalk, or your own Tomcat, whatever. In the local development case, the entry point to your application is you typing boot development and whatever your task name is. In production, the entry point to your application is the servlet entry point that was produced by the WAR task.
In the local case where boot is the entry point, all of the boot runtime stuff is available for you to use like pods and file sets. But in the production setting where Tomcat selects and uses the entry point to your function, the boot runtime stuff is not available there because, in order to make pods work, we need to run Java code before we run any Clojure stuff. Basically, we set up the pods before starting any Clojure instances. It's kind of a hand-wavy technical description of the issue.
MICHA: Yeah, like all Clojure code needs to run in a pod and, if it's not running in a pod, then it kind of ruins it for the rest of us. Yeah, the boot executable starts with the Java program that constructs the first pod where your code is going to run.
ALAN: But if there is no phase distinction between build and run, like they're just kind of interleaved and production boot is your entry point, which it might be if you're running–I don't know–we've done this in Docker. You can run boot in Docker and then boot is your entry. Then all the boot runtime stuff is available, and then you can use pods at runtime.
I've done this in the past with this Bandalore library. I was using dependencies at runtime to interact with SQS, and I didn't want to suffer their transitive dependencies. In retrospect, maybe ill-advised. I don't know. Maybe it's good to–
MICHA: I think it works out well with Docker because, with Docker, you can bake the Maven cache into the….
ALAN: Right, yeah. That's right. The problem with doing it at runtime is the Maven resolution then also happens at runtime, which means that you're potentially pushing something into production that can't yet run.
ALAN: It still needs to talk to Maven central or whatever to download the stuff. Yeah, if you're working in Docker, you can build your image separately from deploying it and, as part of the build step, you can cache the dependencies you're going to need at runtime.
MICHA: Yeah, and being able to use pods, like if you run into some problem, you could spend a long time messing around with dependencies and trying to figure out a way out of it–
MICHA: –by negotiating amongst all the libraries. It's like the U.N. You could just throw a pod at it and the fire is out, at least.
ALAN: Yeah. Yeah.
CRAIG: Yeah, that's interesting. I've definitely dealt with that problem of kind of different fiefdoms, right? It's worse than the U.N. because at least there you have national borders. This is like, well, I'm going to take the U.S. and overlap it with Canada.
CRAIG: There are two St. Louises or two towns that want to occupy the same piece of ground. How are we going to do that?
CRAIG: Yeah. Yeah, St. Louis 1.0 and 2.0, and they're incompatible. Yeah. No, that makes a lot of sense to me. Okay. Very cool. This is such good stuff.
I am quite happy with what you said, Micha, which is being able to use boot without having to have had a really deep understanding of this stuff. But I'm certainly glad we had this discussion about it. It's funny. We've been talking for close to an hour now, and very usefully, I think, and yet when I step back, and maybe this is me being naïve, but I don't think so. It really is a fairly smallish thing, right?
You mentioned tasks, file sets, and pods. I've only really had to kind of vaguely understand one of those things to be useful with it. That's pretty cool. I always like it when that happens with software that I write, although I can't claim to have done anything as elegant as what you guys have pulled off.
ALAN: Thank you.
MICHA: Thanks. Yeah, that's–
ALAN: That's very high praise indeed.
CRAIG: Cool. Well, man, I really do want to talk about hoplon. I think we're going to wind up abbreviating the discussion, but it's just something I've been working on lately, working with lately, rather. Maybe we can at least–
Well, I guess maybe I should stop there and say, is there anything else that we should say about boot? Is there another important part of the boot story that we haven't discussed?
ALAN: I would say a couple things about boot. First of all, the barrier to trying it is super low. It's as low as it ever has been. We have a number of – for a long time a lot of people didn't like boot or at least were discouraged from using boot because it was a real pain to use in Windows. We still don't support Windows 7 and below and never will because of limitations of the file system API. But actually Sean Corfield, who is a heavy boot user and contributor and sort of friend to the cause, has been happily using boot on Windows 10. As far as we know, it works very well on Windows 10.
ALAN: And on Mac and Linux, those are the platforms we use boot on every day, so it's in really good shape there. It's really easy to install. The second thing I would say is that we have probably one of the most friendly and knowledgeable communities out there in the Clojure world, maybe even in the open source at large, and particularly on the Clojurian Slack thing in the boot channel. I guess we can make a liner note for this.
We have a boot channel in there of people who have written tasks. There are people who are using boot for Web development. There are people who are using boot to work with. One guy did it – they used it in stuff like protobuf.
ALAN: All kinds of interesting things going on and people are very friendly. Like I said, the barrier to entry is very low and it's very easy to get help if you're stuck.
MICHA: Yeah, and Martin and Juho work on the ClojureScript front.
ALAN: Yeah, there is a tremendous momentum in the ClojureScript world, and a lot of it is boot centric. Basically people extending boot and, well, not even boot. Basically creating and sharing and integrating libraries to sweeten the ClojureScript development experience in a boot based app. There are a lot of directions, somebody interested in learning about boot, could go with it, but I think you'd be hard pressed to come up with some kind of application that you're going to do on the JVM that boot wouldn't help you do it somehow.
CRAIG: Yeah, I've certainly had no trouble doing the things that I've wanted to do, and I've done so far one, I would say, definitively non-trivial application. Nothing at a client yet, nothing kind of that kind of environment, but I've shipped a single page Web app that's a real piece of software. It's not one weekend hacking or anything like that.
CRAIG: I had no trouble whatsoever with boot. Boot never – I shouldn't say that. I think I have a very small amount of times where I had to go read the wiki to overcome some minor thing, but I don't remember any time where I was like, oh, my God. I just spent an entire day just getting files to compile or something that should be trivial, so it was a good experience.
MICHA: That's really awesome.
CRAIG: Awesome. I really want to talk about hoplon, so let's do that. We are going to wind up cutting it short. There's no question because I think hoplon is another very interesting piece of kit and given that we just spent an hour talking about boot, which is also interesting. But given the relative surface areas, I suspect that we would wind up with a three-hour show, which we attempt not to inflict on our listeners.
I think maybe if we could at least get you guys to mention what hoplon and, of course, javelin are, I do have a couple quick things I'd like to touch on and then we'd have to figure out a time it makes sense for you to come back and for us to really devote the time to it that it would deserve.
ALAN: Sure. Well, I guess, I would say we can cover. We can get into it here, but there's also a hoplon channel in Clojurian Slack that has an active user base. We're there, so anyone who is listening to this and is wanting for more on hoplon or any of the things we're about to discuss, they can always find us there.
MICHA: Yeah. You know what? I have to say that all these things, for me anyway, is like the main – it's really – I don't know. For me, Clojure is very unique in my experience. Hoplon, boot, and all these things, they're very – it's kind of like – it's very rewarding to me because they are things that, as far as my use of them professionally to make money and to get actual work done, they're pretty much done. They do everything we need them to do, and we're moving on. We're thinking about other problems now, and we don't need to keep solving these problems. I've never experienced that before using Clojure.
Using other languages, I'd always end up – I could never form the abstractions that were durable and composable enough to be used in the next project. I would always end up having to rewrite something or solve the same problem over and over again. I'd never experienced actually solving a problem before or even thinking that it was something that was worth spending your time on trying to do, like trying to solve a problem of making websites once and for all. That's all due to Clojure, I think.
CRAIG: Yeah. I have had the same experience with a couple and I mean two different things that I've written. I've got this little Stochastic Markov chain thing, and it's like it's done, right? If anybody asks me, should I use that, I'd be like, yeah. Go for it. It's good.
If they say, is there anything that you could change? I'm like, well, sure. I've got a laundry list, but do I need to bother? Eh.
CRAIG: It's great. It's a great feeling.
ALAN: Then people have so much power to pave over whatever omissions you made too, thanks to Clojure's dynamism and stuff.
CRAIG: Yeah. Cool.
CRAIG: Awesome. We are actually going to save hoplon and javelin for another time because I really don't want to shortchange them. I think you could probably explain them in five minutes, but people can go over to the Web page for that. I think there's useful, extended conversation we could have. Let's save that up. Let's have you back on and have that discussion some other time rather than attempting to shortchange these technologies now. What do you think?
ALAN: Sounds like a good idea.
MICHA: Sounds good.
CRAIG: Yeah. Cool. Awesome. That's great. I just got you to agree to come on again, which is fantastic.
Cool, so I guess I will say, though, even though we're not going to spend an hour on hoplon, I always reserve time at the end of the show, as much as makes sense, as much as we need, to talk about anything else. We often have a main topic in mind. Today we certainly did. But is there anything else?
CRAIG: Here we are, right? It's a good opportunity. What else is going on that we should talk about today?
ALAN: There was something that I wanted to mention. It's funny you brought up earlier in our conversation the production on the Pluralsight course. There is a project that I have started with Daniel Higginbotham.
Daniel Higginbotham, author of Clojure for the Brave and True, man about town in really every single way, he's made his brave Clojure thing. He's got a Clojure jobsite now. The dude is–
MICHA: Also works at Adzerk.
ALAN: Works at Adzerk, a great person, working on all kinds of fun stuff, very enthusiastic. He and I collaborated, I guess, two years ago on his Clojure for the Brave and True book. By saying we collaborated on it, really I'm taking way more credit than I deserve because he had it basically written before he went to a publisher.
I had the opportunity to be the technical editor and even write the foreword, and I kind of developed a cool working relationship with Daniel. He and I both have a lingering interest in the concept of education, or at least we're just so excited about Clojure that we feel like it's something we should do. I don't know. I feel like a lot of Clojure people have this inclination. It's like I know this awesome thing. How do I tell other people about it without getting slapped?
He and I started on this project called MX Go, mxgo.io. The concept is basically online learning, short courses modeled more after talk length things than course length things. I guess the TLDR would be what if Strange Loop had a baby with Pluralsight.
ALAN: The site isn't up as of this recording, but that's something we're going to be developing. I think, by the time that this goes out, we'll have that up, so mxgo.io. If it's something you're interested in, either producing content for or subscribing to, then I would encourage you to check that out. That's kind of been ramping up in my world. Then hopefully I can convince Micha to come on and do the boot course. Maybe you can do the hoplon course. Then instead of recording another Cognicast, we can just tell people to subscribe to MX Go.
CRAIG: There you go. Is this all going to be–? I mean obviously you and Daniel are both huge fans of Clojure. Is it going to be specific to Clojure and related technologies?
ALAN: That's a really good question and a cool thing about it is that it's not specific to Clojure. Like I said, one of the main inspirations for it is the Strange Loop sort of…. The world filled with inquisitive minds, and there's a lot out there in computing going on outside of Clojure and outside of functional programming. A lot of times people are – you don't know what you want to learn, right? How do you find things that you would like to learn? Well, you kind of need to be exposed to things that you weren't looking for.
No, the content will not be limited to Clojure. We've got some ideas lined up for different kinds of languages and CS topics. We hope to mine the papers we love presenters. We're really attracted to the idea of getting people to produce content who have already given a talk and encouraging them and helping them to convert their talk into a set of 20-minute explications with exercises on that topic. Yeah, hopefully we have a pretty diverse set of topics.
CRAIG: Cool. You just said "with exercises," which I think is a key point because people might say, well, YouTube.
CRAIG: I can go watch ten million conference talks, no problem.
ALAN: Yeah, the big difference, I think, will be exercises, but also very few things actually go through the edit repeat cycle, which I experience in real time with you when you and I were making the Pluralsight Clojure course.
CRAIG: Yes, you did.
ALAN: I can lay down a track and in my mind it was amazing. But if you look at like, you know, you forgot to talk about this. You said this word three times. There's a typo on line 25. Not to disparage people who make content on YouTube because I think that's a great way to find new material too and just see awesome stuff, but it's free for a reason.
CRAIG: Yeah. Addition definitely makes a difference. You mentioned that you and I spent a week together producing a video. I think that video was a total of maybe 3 or 4 hours, and it was two people for 40. I mean it wasn't 40 hours. You and I worked like at least one 10-hour day, right? It was a boatload of work to produce, and there was no video.
ALAN: That's true.
CRAIG: It was slides and voice, so it's just a lot of work to do video. There's no question about it.
ALAN: That's why we're hoping we can cut down the size of the deliverable and then hopefully authors can leverage the fact that they've probably already given a talk or at least have notes on the topic, so then that cuts down on prep time too. We don't want the production side to be too daunting.
CRAIG: Right, and I think there are a lot of things you can do there for sure. The comment was more aimed at the fact that when you see something polished there's a difference.
CRAIG: It's one thing to aim a camera that keeps tipping over at somebody standing at the front of a room full of people and hopefully you can hear them in whatever, versus oh, yeah, I can make out what all this, and there's bookmarks or whatever it is.
CRAIG: Yeah, totally. Absolutely. Cool. Awesome. Yeah, that's great. I'm actually super excited to check that out. I'm looking forward to seeing what you guys have to offer. I mean one of the reasons I go to Strange Loop is exactly what you're talking about. Just a world full of cool stuff and, quite frankly, I'm not aware of a lot of it. Just being around people who are essentially a list of what's exciting is awesome.
ALAN: Yeah. I think it's super cool that, in our profession, you can meet – like at one Strange Loop I had the chance to meet Chuck Moore, which was like one of the formative experiences in my computing adventure. Meeting Chuck Moore, holy cow, this is one of the names in computers and will be forever. The fact that our profession is small enough and that the celebrities are usually friendly enough that you can meet really cool people and hear about really cool ideas.
MICHA: I wonder if Larry Wahl was there.
ALAN: I don't think he was, but he gave that talk that you linked me to at some other conference recently that I ended up watching. It was really awesome too. Yeah.
CRAIG: Cool. All right. Awesome. Anything else that we should make sure to get to? Micha, you have anything you wanted to share?
MICHA: Well, I mean I have like a little reflection on boot, or are we past that time?
CRAIG: No, it's all good.
MICHA: Okay. Yeah, so one thing that I think is good about it is maybe that it exposes the Java primitive, the JVM primitives to you in kind of a direct way, like when you make a pom.xml separately from the rest of the packaging. What I think is good about this is, like, I'm not a big fan of Java, the language, but looking at java.util.concurrent, for me that was like a computer science education. The way Maven is engineered, it's great that I knew that when I started working on node.JS stuff because then I was like in NPM land and I could see exactly why things were not going well.
I think for beginners, they might be exposed to a lot of the JVM things, but I think that that's actually good because the JVM, the parts that we have to deal with, at least in Clojure, are super well engineered. If you need to get stuff done reliably and people are depending on you, you can't go wrong with all those things. I think boot exposes it to you, which lets you learn about them in kind of a friendly way.
ALAN: We definitely – the JVM, the Java language are very conservative and well thought out approaches to managing change and improvement in their APIs. Clojure, of course, does a spectacular job of basically never removing things. Things will be added to the Clojure language, but things are never removed. It's an extremely stable runtime environment.
Then we kind of try to do the same thing with boot. We haven't had a breaking boot in two-ish years, a year and a half. Basically, it's a huge goal of ours to not introduce breaking changes to boot because we have dozens of services that are boot based that we would like to upgrade periodically, and we do not want to suffer for it. Yeah, the whole stack, I think is like Micha says, can be daunting. But once you learn it, you'll know it for a long time and it'll give you the ability to look at other systems and work with other systems in a new and powerful light, for sure.
I totally just hijacked your moment.
MICHA: No, I'm in agreement, dude.
ALAN: Oh, okay. All right. I felt like I kind of swooped in.
MICHA: Well, that's what I was going to say.
ALAN: Okay. Cool.
CRAIG: Cool. All right, well, that sounds like as good a place to wrap up as any. Assuming you agree, then, Alan, I will throw it to you for our final question, the one we always ask at the end of the show. We ask our guest or guests to give us a piece of advice. This can be of any form that they prefer, whether it's advice that you've been given or that you like to give. I often throw in the addendum, it could be good advice or bad advice. I don't think I've had anybody take me up on the bad advice one yet, but what do you got for us, Alan?
ALAN: Well, so I found this really challenging because I have a conflicted – I'm conflicted about the very nature of giving and taking advice. I don't know. I look at a lot of things, and I see someone got very lucky. It seems like the luckier someone is, the more freely they give advice. But what does their advice mean?
It's like getting number suggestions for the lottery from the lottery winner. Is that going to help you? Is that meaningful to you? Maybe.
I wracked my brain for, like, okay, this is a computer podcast. What are some – who are the lottery winners and what–?
MICHA: Give advice on being tall.
MICHA: Tell people how to be tall.
ALAN: Yeah, how to be tall.
MICHA: You obviously know the secret.
CRAIG: I have a bit of advice about being tall.
CRAIG: Can I inject it? So I am myself nothing like your height, Alan, but I always wanted to be taller just so I could use this line where someone walks up to you, and I'm sure you've had someone ask you, "Oh, do you play basketball?" I always wanted to be tall enough to get that question so I could respond, "No, do you play mini golf?"
CRAIG: I hope you'll use that sometime. Anyway, back to your advice.
ALAN: Oh, man. I need to get a Google glass or something so I can record that moment and send it to you because I do get asked that question a couple times a year.
Anyway, I wracked my brain for what is some advice that I've really taken to heart or has really paid off for me. Then I thought, well, you know, in Matthew 25 Jesus' Parable of the Talents, is that the direction we want to go with this, you know, go religious with it? I thought, well, probably no. It needs to be like a computer thing.
I thought, well, you know, it's really dumb, but one of the best pieces of advice ever was given to me by my drill sergeant in basic training, which was, if you're going to do something important tomorrow, get everything ready the night before. That's something that never really came naturally to me, preparing for things that are important, but it's a very simple thing, especially if it's going to be early in the morning. It's very simple. You just lay out the clothes you're going to change into. Or if you have a test, you study for it. A very simple piece of advice, but I feel like I personally was never good at preparing for things, so I just had great faith that it's going to work out for me every time. That was a piece of advice that I reflect on sometimes and I think is very simple and good. Be prepared for things that are happening tomorrow.
CRAIG: Well, we're all Clojurists. We like simple, and that does not – as we are well aware, something being simple does not prevent it from being correct, profound, or any one of a number of other desirable qualities, so I definitely appreciate the advice. As a father of two smallish children, you know, things like that need to be said to you at some point in your life. It's not obvious automatically, so I'll have to maybe bring that….
ALAN: Yeah, well, I guess as a new father, I can say it's definitely paid off too with bottle prep and clothing prep. There's a lot of costume changes when they're two months old.
MICHA: You waited until the night before to prepare for your kid?
MICHA: Laid out some clothes – ready. Done.
ALAN: Well, you know. What is it? Amazon. There was Amazon Prime, but now there's Amazon – what is the hourly one?
MICHA: Oh, yeah.
ALAN: Yeah. Just in time. I need a crib. I need a box of diapers stat.
CRAIG: Yeah. You just install Amazon Echo or whatever it's called, the thing that listens, and it hears you swearing and the next thing there's a knock on your door with a bunch of diapers or whatever you need.
MICHA: Oh, the button. Right, right.
ALAN: Yeah. Yeah.
CRAIG: Yeah. Cool. Well, all right. We've degenerated into puns and computer jokes, but I do appreciate. The advice is very good, and I thank you for sharing it with us.
CRAIG: I love the fact that it came from a drill sergeant. That just makes it so much better in my opinion.
ALAN: Yeah. His version of it was a little more obscene, so I toned it down.
CRAIG: Appreciate that. I appreciate that. I'm converting it back in my head right now, but I won't share it. Anyway, like I said, clearly people know that I've worked with you a lot, Alan. You've worked with Micha a lot. Micha and I have hung out a bit, so rather than make people listen to our idle banter for the next 45 minutes, I'm going to wrap it up there. But I will stop to thank you both very much for coming on. I really, genuinely enjoyed the conversation, learned a lot. Thanks for the tools, too, by the way. I really have been digging using this stuff. Change is always fun, but I've also found it productive, useful, and enabling, so thanks on both counts, guys.
ALAN: Thank you.
MICHA: Thank you.
ALAN: Yeah, really fun to be here.
CRAIG: Cool. All right. We'll wrap it up there, then. This has been The Cognicast.
CRAIG: Cool. Thanks.
[Music: "Thumbs Up (for Rock N' Roll)" by Kill the Noise and Feed Me]
CRAIG: You have been listening to The Cognicast. The Cognicast is a production of Cognitect, Inc. Cognitect are the makers of Datomic, and we provide consulting services around it, Clojure, and a host of other technologies to businesses ranging from the smallest startups to the Fortune 50. You can find us on the Web at cognitect.com and on Twitter, @Cognitect. You can subscribe to The Cognicast, listen to past episodes, and view cover art, show notes, and episode transcripts at our home on the Web, cognitect.com/podcast. You can contact the show by tweeting @Cognicast or by emailing us at firstname.lastname@example.org.
Our guests today were Alan Dipert on Twitter @AlanDipert and Micha Niskin on Twitter @MichaNiskin. Episode cover art is by Michael Parenteau, audio production by Russ Olsen and Daemian Mack. The Cognicast is produced by Kim Foster. Our theme music is Thumbs Up (for Rock N' Roll) by Kill the Noise with Feed Me. I'm your host, Craig Andera. Thanks for listening.