In this episode, I talked about my new course on REPL driven development and teaching Clojure.
Daniel: Hello. Welcome to The REPL, a podcast diving into Clojure programs and libraries. This week, I'm talking about teaching Clojure with Eric Normand, the creator of PurelyFunctional.tv. Welcome to the show, Eric.
Eric Normand: Hey. Thank you, Daniel. It's great pleasure to be here. I've listened to your podcast since the beginning and read your newsletter. I'm just very happy to finally get to talk to you.
Daniel: It's great to get to talk with you too. I've been reading your newsletter, and all the other things that you've been doing since, basically when I started using Clojure — quite a long time ago. You've been there all the way through my pleasure journey so it's great to finally talk.
The first thing I wanted to talk about, was a recent course that you created and released just a week or two ago called, Repl-Driven Development in Clojure. I wonder if you could talk to us about that course and then about what it is you do in the Clojure community.
Eric: Repl-Driven Development in Clojure is a video course. It's about nine hours of video.
Eric: Pretty long. You never know how long it's going to be when you first start. It just keeps going. One of the things that is a good sign of healthy Clojure programmer is that they use The REPL a lot. By REPL, I don't mean it's just the prompt, and you type a lot of stuff in the prompt. I mean, you are using the fact that you are interacting with a live system.
That might be redefining functions. It might be testing out an expression or two, to see what it does. It might be even looking at documentation, docstrings that are already in the environment, and doing this live. Let's say you're working on a web server.
You got your web server running. You connect up to The REPL, usually through your editor, and you modify it. You make it do something else. It's completely different from the rest of the world, the non-lisp world where you would, say, modify your files on disc, and then either compile them and run them.
You'd have to shut down the server or, you might have something that's more like a scripting language that's not compiled. Let's just call them non-compiled language, where it reads in the file and runs it a new on each request. That would be something like Ruby or PHP.
What you don't have is any kind of state saved between requests. You don't have a shared memory, whereas on the JVM, you do have that, except if you're doing compile program, you're going to have to shut down the JVM and started up again, lose all your state.
Clojure gives you this really nice ability, this nice workflow, where you're compiling running very small units. You can test things as you edit them. You can kind of grow a function at every step, know that it's working. It's like a superpower of Clojure. I don't think any of the other mainstream languages do it as well as Clojure does.
A lot of people have made the leap from not using Repl-driven development, to doing Repl-driven development somewhere along their journey, learning Clojure. A lot of people hadn't and there's not a lot of good material out there.
I think there's just a lot of mentoring going on — people figure it out by watching other people — but a lot of people don't have a mentor in Clojure. I started getting requests for it. People have been asking, "How do you do this thing that people keep talking about?"
Stewart Holloway had a couple of talks about Repl-driven developments, blog posts, and videos. His material was great, but it wasn't a complete course, a complete guide. I decided I needed to make it happen, so I did that.
One thing that a lot of the material out there does not address, which I think is very important, is how intimately you need to understand the semantics of the language. The semantics of vars and how depths create vars, or modify vars, depending on if they already exist, how name spaces work. Those kinds of things.
You really need to understand those, so that you understand what's going to happen when you reevaluate this function, reload a namespace, and what is that doing? You need to understand that, so that you can choose the right steps to interact with your live system.
I made sure that that was a very prominent part of the course. The course is available for purchase now, or you can become a member of PurelyFunctional.tv and get that and all the other courses.
Daniel: PurelyFunctional.tv is the main way about you since the beginning, which is your training, teaching, mentoring sites. What can we do at PurelyFunctional.tv?
Eric: PurelyFunctional.tv, it's a membership site where I publish video courses. I also have other content that's free, like text guides, textual blog posts, if you want articles, things like that. the main content is the video courses.
You can get a membership. You can also buy the courses individually. This is my main source of income right now. I know you said you wanted to talk about more the business side. This is my job now is creating courses, and supporting the members that I have, and trying to get more people to learn and enjoy and Clojure.
Daniel: I think repo-driven development is such an obvious, in hindsight, course to do. As you say, I don't think there's been scattered blog post or people talking about it, or different facets of the problem. I remember when I first started using Clojure, that it took me quite a while to piece together. Yeah, what does it look like to develop a Clojure system.
Even now, there was a Clojure of this thread, about a year or maybe more ago, about different repo workflows that people had. There were so many different ways that people did the repo, how they interacted with their programs.
It was really interesting to look at different ideas because I sometimes wonder, "Am I doing this the best way I could? Are there tools or techniques or ways that I should be debugging or developing that I'm not using?" Every now and again, I look around and see what tips and tricks I can pick up.
You're having a comprehensive from the beginning, like here's all of the things you need to know about Clojure development. This seems like the missing link in many ways from a junior Clojure developer to an intermediate one, possibly.
Eric: Yeah. I hope I don't sound mean, because I really love beginners, but I've seen this happen so many times. It's one of the things that inspire me to actually do the course. You'll see someone come into, let's say, Slack, or the IRC channel, and they have a question.
In a lot of languages, you might say, "Go read the manual. It's all in the manual." You just link the documentation. It's not even something like that. It's something where they say, "What happens if I pass an empty list to this function?" It's surprising, because if you're doing Clojure, you can just type that into the repo.
Why would you switch over to Slack and ask people and hope that the right people are online, and hope that you can ask it the right way, and that they give you the right answer, when you could just type that in and see what happens? It's those kinds of interactions where you realize, "No, people don't know about this repo-driven stuff."
It's the same thing that happens when they complain about — this is totally justified — complaining about the startup times of Clojure. When you dig into it, you realize they're restarting their server every change. They don't realize that's not how we do it in Clojure. We don't just have a better way than the restarting. It's a better way than every way.
Eric: It's completely you never restart your server, or rarely. Let's just say it's so rare, you don't even think about it. Not only can you do the whole, like, "Oh, I'll reload this page, and I'll see the change." Before you even do that, you can test that it's going to give you the right thing before you like look at it in your browser.
Even simple stuff, like you can create a new atom, while the servers running. You got a bug so you create a new atom. You say, "Every request that comes through, I need to be able to inspect it, so just add it to this atom." You hit reload. Everything is saved in an atom. Now, you can look at the data right there. Who else can do that? It's just an amazing thing that we've got.
Daniel: I completely agree. You've been teaching, mentoring people, sometimes directly and sometimes indirectly through your courses in Clojure. I would guess you've seen probably a pretty high number of new and developing Clojure programmers. Are there any common things you've seen, things you've learned, maybe common things that people get tripped up on that you've seen over time?
Eric: Yeah. I think people get tripped up on how simple Clojure is. Let me give an example of something I've seen. Again, a lot of this just happens in Slack or IRC. Someone just comes in and ask the question.
These are questions where it's like, "OK, I'm I really going to go down to the basics and teach this stuff?" Here's an example. Someone was trying to use an Atom. They had made an Atom in the normal way. They probably found some code online that showed how to do it.
It's like defx is atom with a vector in it. They knew that Atoms were used for mutable state. They were trying to modify the vector inside. They thought that Atom was some syntax that makes the thing inside mutable.
That's what I mean where they don't realize how simple it is. It's like, "No, the vector is a thing and Atom is a separate thing. They don't really cross. You can put anything in an atom. The atom doesn't do anything to the vector. The atom is just an object."
"You can actually look at the source code. It's just the function that constructs an object." Those things where it's you don't have magic syntax for this and that and the other thing. It's just a function that constructs an object, I think those things trip people up quite a lot.
I also see people doing a lot of...they use "def" inside of a function. They are implementing impetrative code. They see that def creates a variable and assigns a value to it and so they just use that everywhere instead of using a "let."
Things like that where it's like, "OK, you're getting there." It solves the problem. It gets the right answer. That's great. I think that that's awesome that they are able to get through that initial part of learning where things really are tough because there's so much to learn to get into a new language.
Then you have to step back and say, "OK, now you're at this point where you have to know that def should not be used like that, def is for top-level things." Now you get into like "Well, what do you use instead?" [laughs]
Now, it's like a fork. It's like, "What are you really trying to do? Are you trying to just give something a name for this little local context?" That's a let. Are you trying to create something so that you can get data out of this function? That a whole other discussion. Do you really need that? Maybe you do.
For instance, if you could have an Atom and you're sharing data between two different functions. I've done that before. It's a possibility or are you implementing an imperative algorithm? Really to do it in an imperative way, you need mutation inside of a loop or something. That's another discussion.
Those are the things that I really like getting into because it shows you how deep this goes. How did the people on this side of that divide who are capable Clojurist, how did we get here?
How did we get from global variables everywhere to knowing like, "Oh, sometimes I need an Atom and sometimes I need to use a loop. I can change the state every time through the loop. Sometimes it's just a let." How did we get here where we are able to see all these different uses for things?
You are asking me about teaching and mentoring. I have made some notes about things. The thing about rapport-driven development that reminds me of this is I was hesitant to make this course at first.
The reason being if you had asked me a year ago like, "Would you make course on rapport-driven development?" I'd be like, "Yeah, but what does that really mean? Everyone's got a different workflow and there's all these different editors. Is there really one thing called rapport-driven development?"
The more I think about it and get into it and really engage with people who need to learn it, the more I realized, "Yeah, there is a thing and I know it." Now through seeing what these beginners do not know, I see, "Yes, this is how I can teach it. How I can."
Is there anything as rapport-driven development? I'm not sure because like you said in this Clojure verse thread, "There were so many different workflows." Everybody's got a different thing that they've picked up over time. It's evolved over time but what is common?
What is the thing that they are able to point at that this is where it's rapport-driven development? "Oh, that's just a workaround because I'm using this editor that doesn't have this tool." You could figure it out. It's just takes a lot of thought and deep digging.
What I'm saying is the more I teach the more I realize I do know more than I think I do. It's all in there. I did have to research somethings like different editors that I don't use, but the core stuff I already knew all of it. I just hadn't organized it into a course yet. Another point that I've learnt over time is that programming it too hard. [laughs]
Eric: Is just really is. I don't mean the cool part of programming which is where you get to make ideas real and anything you can imagine you can create. That part is cool and that's always going to be hard.
I'm talking about the like, get your editor set up, you got some weird thing going on in your machine and you google the error message and no one else has had it before. All the package managers you need to get anything working. All that stuff is just too hard.
I feel we've really — over the last 20 years — painted ourselves into these corners in every language community. It's not just Clojure. It's everywhere. It's just this amount of stuff you have to know is just too much. How did someone learn Git? How did someone learn all the UNIX command line stuff?
All that it's just incredibility arcane. I just feel for anybody starting today. It's really hard. Another thing that I have learnt over time is that people are smart even if they are beginners. I know there's a lot of dissing of users.
I've heard a lot of people say, "Oh users are stupid. They don't know what they are doing. They need all this help." The more I create courses and teach people online, the more I realize, no they are smart. There's just a lot to learn and they are overwhelmed continuously when they are learning.
There's just so much stuff to learn. They are smart people. They want to be spoken to like intelligent people. They can tell when you are oversimplifying or damning something down. They want a deep experience. They want to be told the straight dope about the thing.
I had this period where I was thinking, the value I bring as a teacher is to find a path through all the myriad things you have to learn, and just stick to that path, and get them to a place. I'll give you an example of one of the courses where I did this as well — Web Development and Clojure.
I taught just enough material to get someone to be able to make a to-do-list app and deploy it to Heroku. A lot of people found it successful, but a lot of people were like, "Oh, yeah. But what is a GET request? What is actually going on there? You say that this Ring request is an HTTP request, but what is that? What are all these header things that you keep talking about?"
I didn't explain any of that stuff. This is going to be a deep thing. I realized now that, one of the reasons that we like Ring in the Clojure world, is because it gives us access to the raw HTTP request but in a very convenient format. For us, it's a hash map. We like the control. We'd like to write our own middleware that does exactly what we want it to.
Instead of relying on a framework where half of our time is spent configuring the framework, the other half is spent finding a plugin for the framework to do what we want or figuring out where can I plug this thing in, to make it do this thing?
Since what we want is that control and that deep engagement with the protocol — just give me the raw HTTP, and I'll stream back raw HTTP. It'll be this glorious thing where I'm interacting with your browser. I have to teach that. That is the thing to teach — the protocol and how browsers make requests.
Why is it that with a form, you can only do GET and POST but there's DELETE and PUT that no one talks about? What is a method? All these things — What is MIME? What is a MIME content body? What is this stuff? MIME-type content, Accept, Asterisk/Astrid, what is that?
All these things that I somehow have picked up [laughs] over the years of working on the web, and now that I know them, I love being able to get in there in the raw HTTP request and raw HTTP response. I love it.
That's what I have to teach how to get someone to love that so that they don't want the framework. That's what the framework does is it hides that from them, but now they're safe. They don't have to...Not that they don't have to learn it, it's that they can start working without learning all that stuff.
Anyway, in my next version, which I'm not announcing, I don't know when I'm going to do this, but the next version of the web development course will be that. It will be the web from the perspective of Clojure — a Clojure programmer. You heard it here. I'm not announcing a date. I'm not even really started working on it yet, but I know that that's what it's going to have to be.
Daniel: That's a massive topic. The way this just [inaudible 21:24] . It's in some ways a little bit cruel that you're saying this so much for beginners to learn, and that is in any language. The web in particular is just so what it means to web development. It's sprawling.
You have to learn many different languages, environments, concepts, client server, HTTP, a little bit of networking. There's just so much stuff there. If you can [laughs] simplify that and explain that. That's a lot of work.
Eric: That's the challenge. I'd said my last course was nine hours. This might be 20 or 30, 100 hours. I have no idea.
Eric: Of course, you have to chart some kind of path through it so that they're not overwhelmed. You can't just start with everything. I think that there is a path. It's been brewing in the back of my mind. I'm seeing it more and more like I have to create Clojure programmers.
Instead of saying you're a Clojure programmer and you want to learn how Ring works, which is how I saw it before, it's more like I have to make it so that someone can finally appreciate why Clojure programmers like Ring so much, because a lot of people don't.
A lot of people do appreciate it who are coming at it from a certain place and amount of experience, but a lot of people look at it and they're like, "What? That's it? That's all I get? It's the HTTP request?" [laughs] "Where do I go from here?"
I want to get them to the point where they're like, "Oh, all I get is the HTTP request, and that's perfect because now I can do what I need to do." I feel like that's one of the great things about Clojure, is that we don't overcomplicate things. We add a very small layer of indirection and it's a high leverage layer of indirection.
Then we say, "OK, here it is. You don't have to parse this HTTP request from raw character strings. We're giving it to you in a really nice format. That's all we're doing." It's similar to how the CSV parser is in Clojure. It's just like, "Here's a vector string. It's a vector of vectors of strings, or the lazy list of vectors of strings."
Whereas I know in other languages, they'll do things like turn it into hash maps for you, assume that the first row is a header and do things where you're making assumptions now. [laughs] CSV does not specify that. CSV is just commas. [laughs] It's on the lines. It quotes in case you need them. There's not much more than that.
Clojure, as a language, very much...I feel as a community, we recognize that. The useful thing that this library can do is as little as possible, and let the end programmer do what they need to with it.
Daniel: I like that. That idea the useful thing is to do as little as possible [inaudible 24:41] a pretty key aspect of a lot of Clojure libraries, which I've never quite heard expressed in that way. I like that.
Eric: It's one of the things I really love about our community. It's not the kind of thing that you can shout about. Like, "We do as little as possible, and that's why we're great."
Eric: I think that there's a lot of magic in some other language communities, where it's like, "We do the right thing 90 percent of the time. That other 10 percent, go find another library."
Eric: Those kinds of things...I don't know. I feel like they're not for me, because somehow, I'm always in the 10 percent. Just parse me those commas out, handle the edge cases and that's it. Just give it to me raw. That's the kind of person I am.
Daniel: You've been working in the Clojure community for a while. Video courses is something you're pretty well-known for, but what are some other things people might have gotten from you or want to get from you in the future?
Eric: I'm probably best known for my newsletter. It's a weekly newsletter, email newsletter that is made to inspire Clojure programmers. It used to be like 10 links, 10 things that I liked during the week, but it's evolved now to be the more teaching, more like here's some useful Clojure knowledge. Of course, it evolves over time. It's been many different things.
Get on that if you're interested. If you haven't gotten in a while, I know that as your list grows, it's more common to get put in spam folders and things. I have met people who are like, "Hey, you haven't done your newsletter in a while."
Eric: I'm like, "Uh yeah, it's every week." For the past five years, I haven't missed a week. [laughs]
Daniel: You up to Episode 327.
Eric: That's right. I typically don't miss any. You might want to resubscribe. You might not be getting them anymore.
Let's see. What else? I've got a podcast. The podcast is about functional programming in general. It's called "Thoughts on Functional Programming." It started as me working on ideas for a book that I'm writing for the general programming community, not Clojure specifically, about functional programming.
I feel like functional programming has not really broken out of academia in a useful way. Of course, a lot of ideas have come out of academia and are now being applied in production, but they're still very academic. It's still people reading papers or textbooks about functional programming. The people who read them and study them become like academicians, like armchair academicians.
I think that there's a whole army of people who are doing functional programming in a software engineering as opposed to the computer science.
Software engineering stuff with it. It's just not being written down. Their perspectives and things are not being talked about in books. Books are like a literature. They are like a discussion format.
If you look at object-oriented books, there's all sorts of books about design patterns and how to architect your O code. There's just a lot discussion there, but there's a lot of functional programmers and we don't have a lot of discussion.
I wanted to make a book that open that discussion up. Let's talk about this in a much more practical and friendly way. Talk about, what are we doing as functional programmers that is different from object-oriented programming?
My podcast is me exploring those ideas. Then recently, I went to — I call it season two — where I'm going through functional programming ideas explaining them. It's much less just my thoughts and much more a systematic. Like, "Let's just teach this thing." That's what it is now.
I have a lot of subscribers. I get a lot of good feedback on it. Not trying to tune my own horn, I'm just saying, "You just check it out." If you are interested in hearing functional programming ideas but from a much more practical perspective, there's just going to be a link in the shown apps.
The book — I think I can announce this now — it's very close to being in the early access. It's going to be published with Manning. They have a program where before the book is 100-percent ready, you can buy a PDF version and also the online HTML version.
You get it at a discount. Then you get updates as they come up. New chapters come out or I edit an older chapter or something. That will come out and you will be notified and you can bask in the novel chapter.
Daniel: We've mentioned a few times you have been doing this for a little while. I feel you've probably got a decent perspective on what's changed especially in terms of people new the Clojure community over time and maybe people's attitudes coming to Clojure. Most had the same. What's different that you have seen?
Eric: The big thing is that, it is now much more mainstream. Clojure itself is like a viable option. I think just in a larger context like any non-top three language is now a viable option.
When I started with Clojure if I mentioned that I did Clojure to another programmer they'd be like, "Why don't you just use Java? How is it better than that?" It was just very hard to explain.
They're like, "Different languages are better at different things." The idea was that Java has everything you need and like, "Why are you searching elsewhere?" This is the same for Ruby.
If you mentioned you were into Ruby or...Man I don't even know if Erlang was on people's radar back then. I don't know if it's just the number of programmers has exploded or what but it's now possible to not be a Java programmer. That's great.
You can just be much more open about liking Clojure. The community is way bigger. That's for sure. I lost track. I think back in 2011, I started making a list of everyone who was active enough to have a blog or seen them in a conference talk.
I had a list going with like, "Here's the link to their blog and here's the book they wrote. Here's their conference talks." Man, that's impossible now. There's just too many people. If you look at the number of companies that claim to use Clojure, it's just enormous.
There's just no way to reconcile that with like, "I want to keep up with all this." There's more projects too. I don't know. It must have been three or four years ago where I was following just to get ideas for the newsletter. Things to link to in the newsletter.
I was following some people who are pretty good at keeping up with all the projects that were coming out. I could keep up with that feed and figure out, "Oh yeah, I see what's this is about. I see why we need this." Now it's just too much. I cannot keep up.
It was much more about fundamentals about even like, "This talk was given in 1972 and we just found a recording. Everyone should watch this." More so than like, "The new Clojure con videos came out. Let's watch those."
No, that's old talk is actually [laughs] much more useful so watch that. I just gave up following stuff. I still get people asking me questions like, "Hey, I'm trying to connect this library to this database." Like, "I'm having trouble. Do you know how do it?"
I'm like, "I have never heard of that database." That library like, "Oh, I guess it is a thing. Look it's on GitHub" Like, "I don't know what that is." They are like, "What, you've never used this?"
They are like, "How can you live?" I'm like, "I don't know. I don't try every new thing that comes out. I try to find stable things that I can rely on for a long time and this one just never crossed my radar." That has changed.
I remember back in the day. I got into Clojure in 2008. Back in the day when libraries would come up they were mostly wrappers. Someone made a Clojure idiomatic wrapper around some existing Java library. That was a big deal.
That tapered off because I guess the important ones got wrapped and then that phase was over. We didn't need to do that anymore. Then we had this explosion with...I think David Norland entered the scene. [laughs]
We had this explosion of coil logic and all these things that were like, "Oh my goodness we going to have so much power versus other languages and compared to other languages that is not going to be fair.
I just was waiting for this time when we would all just get connected together and we would just — I don't know — be so much more productive than any language. It would be obvious that you'd have to go into Clojure to compete but that of course never happened.
Now it's just new things popping up here and there but I don't see any real patterns to them. Just fine. I think it just means that our community is big enough. That there's sub-communities. There's little pockets in it. You can't really be in all of them.
Daniel: Interesting. In sites of all the time I'm hemming around quite as long as you saw. I assume you remember those days of it felt like you read other week.
There was something groundbreaking new. Like, "Here's coil Async, here's coil logic. Here's this program rewriting program, rewriting program and..." I definitely think we don't see quite as much of that anymore.
It's interesting to look at why, as if all of the good ideas are being had or probably not. I hope we're not out of good ideas. Clojure feels like it's at a more stable or mature place in terms of those kinds of innovations.
Eric: Yeah. That's an interesting phenomenon. I'm not sure what's going on. If you plotted stuff on a timeline, would you see this big bunch of closely grouped spikes like, "Oh, look at all this creativity." It just tapers off into where it's like, now it's every year, every two years, where there's a big thing. I'm not sure if that's the case. We're only working based on our memories.
A lot of times when you look at the past, what happens is, when you started learning Clojure, you had to learn all the existing stuff, and all the new stuff coming out at the same time. You could choose between all of them. It all seemed like there's so much in the early days.
You don't really think about how much time it took to create those things that were new to you, but had already existed. I always look at those kinds of things with a grain of salt when people say like, "Oh, things are slowing down." For instance, I feel like this is a personal perception that I do not trust.
I feel like conference talks are not as good as they were before. I watch a lot of conference talks and I find myself getting bored faster. I find myself stopping or skipping in the talks. What I wonder is, is it me, or is it the talks because I've watched so many? I'm a different person from when I started. There are definitely more and more talks online now.
More and more conferences are recording their talks and there are more conferences. Maybe that idea of getting bored is more that, there might be other ones that I could be watching instead [laughs] that I'm drawn to. I just don't know. I just remember finding so many great talks when I first started getting into YouTube. This is like 2007.
There were just so many great talks, but I just wonder if I haven't grown as a person and learned from those talks. Now it seems like, you're just going over old information now.
If that same person gave that same talk today, I'd be like [laughs] , "This is old stuff. You're just rehashing the stuff everybody knows." Maybe people don't know it. That was kind of a rant. I've watched a lot of talks to do newsletter stuff. I've just found that I'm not as interested in it anymore, one of the reasons I evolved my newsletter away from that.
Daniel: Yeah. That's a interesting thought. More data probably needed.
Daniel: Is there anyone you'd like to thank or mention in closing?
Eric: Yeah. I think the Clojure community is better than it has ever been. I know that there's often drama in communities, but that's just the nature of communities. We just have interpersonal things that come up and we have to talk about them. I think that the number of people getting into Clojure, the number of books coming out, the awesome stability of Clojure, it's just amazing.
I just want to thank everyone who works on Clojure core, everyone who works on open source Clojure libraries, everyone who blogs, who answers questions in slack. All of that is just so awesome. You all rock for doing that. Thank you. Thank you so much for making it an awesome community.
Daniel: Yeah, I agree. Anything you'd like to plug?
Eric: Yeah. Actually, I have two things I would like to plug. I'd hear a lot about it if I didn't mention that there's a YouTube show I do with three fine co-hosts. It's called [inaudible 40:11] and it's just us. We talk about some news. It's a lot of opinions.
Then we get into the Repl sessions. We have a little programming problem we work on. We just dive into a Repl and try to solve it live, like we usually have not done before. We answer questions in the YouTube chat. It's just a fun time. We always joke that the number of watchers goes up when we start on the Repl.
Eric: People don't want to hear us talk. A lot of people like to join in the discussion. We don't know everything. We often ask our nice audience to help us figure out the right answer. Do find that. If you're into that, if you're into more Clojure content, I feel like there's always room for more. The next thing I want to plug is PurelyFunctional.tv.
If you want to learn Clojure, I consider it the most comprehensive thing available online. I've lost count of how many hours of video there are on there. There's, multiple-books amount of text available for free on there. You can get a membership and get access to everything. See if your job will pay for it.
If you're working in Clojure, they might have a training budget for you. Take it out. Ask me if you have any questions about it. You can find my email address. I'd love to just get in touch.
Daniel: Great. I really appreciate all you have done and are doing for the Clojure community, and helping grow the next generation of Clojure programmers.
Eric: You're welcome. I do what I can. Daniel, thank you. You're another one out there, spreading the word about Clojure. Thank you for everything you do.
Daniel: Great. Have a great day.
Eric: You too.