Hello everyone! I have been learning clojure for a few weeks now, coming from a NodeJS/Python/PHP background, I’ve read the “https://pragprog.com/titles/roclojure/getting-clojure/” book and it was a nice introduction to the language After the book I started exploring the ecosystem and popular libs, I’ve also learned that in this community the philosophy is “libraries over frameworks”, which I totally understand, even though it feels strange at first So my question is: Would you consider Clojure a language for “specialists”? or is it just the ecosystem that requires deep exploration/learning before one can say “I can build professional projects in clojure”? The reason I ask is because from my perspective as a beginner it’s quite hard to wrap my head around all the libraries and tools that are generally used to build enterprise-grade systems, and how those are wired together, one particular pain point has been setting up a new project, I know there are templates to speed up the process but I’d like to learn how to do the wiring myself, and so far I haven’t found a good guide on how to connect the pieces together in a cohesive way
I havent updated it in awhile, but maybe this will help you https://caveman.mccue.dev
is it just the ecosystem that requires deep exploration/learning before one can say “I can build professional projects in clojure”?I would say it requires proper education. In the absence of education one must resort to exploration
I would not consider Clojure a language for specialists. If you go the framework route, you become much more of a specialist than on the library route. Libraries can be composed much more freely and may apply to a wider range of problems than frameworks. But you have to gain experience with the available libraries of course.
> Would you consider Clojure a language for “specialists”? or is it just the ecosystem that requires deep exploration/learning before one can say “I can build professional projects in clojure”? I would say that in this regard it's not that different from framework-adoring language ecosystems. In Clojure, before being able to build a somewhat professional project, you have to: • Figure out what a specific project's needs are • Find which libraries might satisfy those needs • Learn about each library just enough so you can compare them with the desired degree of accuracy and choose one for each need In other places, you have to: • Also figure out what the needs are • Find which frameworks and libraries might satisfy those needs • Learn the relevant pieces of each framework and library so you can compare them So all in all it's more or less the same amount of work. But the end result, in terms of your ability to repeat the same process in other projects, is much, much better. It's much easier to select things in an a la carte manner, follow the development of each thing, fix some issue yourself, replace it with something else. Good luck using just a single thing from e.g. Django, or using something else instead of its ORM, or fixing something. shudder
(if you have issues or questions with the link i sent above there is #caveman)
This all makes sense, thanks for the answers and the caveman guide @emccue! I appreciate it a lot > I would say it requires proper education What kind of education are you referring to? like, you mean having a computer science degree? I did go to college, though I was already working with development before, it was mostly for the degree, I wouldn’t say it taught me a lot that I didn’t knew already, and yes, most of what I learned prior to it was based on self-directed exploration
I would say very specifically someone teaching you what all the parts needed for a project are and showing you how they fit together - which is what i was trying to do with the caveman guide
I totally understand your argument @p-himik, one thing that I’d like to highlight is that the freedom you describe is good for people who are already familiar with the ecosystem and tools, but for someone new to the language it’s good to have a common starting point (e.g Django/Laravel) that one can use to explore and learn the features as they become needed After you already know what you’re doing, sure, you have freedom, but when you’re just starting out it’s quite overwhelming to even know what is needed and what’s available Instead of having to select one among many libraries available, sometimes it’s useful to have a ready-made structure made by someone who knows how to do it properly, that you can learn at your own pace Like, you may be given a DB connector/ query client in django/laravel, and you’ll learn it at your own pace, rather than having to figure out first how to connect everything until you finally can make your first query
because the hard parts about picking libraries are 1. Knowing what you even need to get 2. Picking between alternatives Once you have an idea of (1) then (2) is easier
> Instead of having to select one among many libraries available, sometimes it’s useful to have a ready-made structure made by someone who knows how to do it properly, that you can learn at your own pace I'd say thats true, but my thesis is that the "ready made" part is less important than the "structure" part. Give caveman a try - I think you'll see what I mean
I definitely will read it in full! Thanks a lot for sharing
> for someone new to the language it’s good to have a common starting point (e.g Django/Laravel) that one can use to explore and learn the features as they become needed
It comes at a cost though. It is indeed good, but only from the perspective of not having to search around and not having to do the plumbing yourself. And everything else suffers for it.
It's a rather skewed trade-off, I'd say. At least when it comes to fully fledged frameworks - I have next to nothing against thing that are just collection of libraries with a ready-made simple plumbing.
> Like, you may be given a DB connector/ query client in django/laravel, and you’ll learn it at your own pace, rather than having to figure out first how to connect everything until you finally can make your first query
I encourage you to just try it. It's much, much simpler than what you're describing.
You never learn framework-related stuff at your own pace - you learn it according to your needs. If you need to do X and doing X requires you to learn how to connect to the DB, how to compose queries, how to execute them, how to process the results, all of which in its entirety is an absolute bare minimum for anything DB-related, then you have to learn all that.
It is the same with some libraries, just simpler. And sometimes it's actually less than in the case of frameworks.
So suppose you have spent 5 minutes searching around and asking some LLM and you came up with a few things:
• clojure.java.jdbc and next.jdbc for DB connections, query execution, results processing
• HugSQL and HoneySQL for query composition
If you, when learning Python, decided that you don't want to compare anything and just want to use the first thing, be it Django or something else - well, you're free to do it here as well. Just choose any library and learn how to use it. Apart from those 5 minutes, it's the same amount of work, roughly 0.
Then you need to learn the bare minimums for each library - the same exact thing you have to do with any framework. But with a framework, you also have to learn about its specific way to plumb things. And with libraries, you can just pass the values around. Need to config a DB connection? Just chuck a map in there - it can come from anywhere. Need to pass a query? It's just a value, just pass it down the line. Need to get the results? The results are just a value (well, could be an iterator in the case of next.jdbc) - do with it as you please.
Zero ceremony to get started. Optional ceremony as you get going, when and if you need it.
I've been there. I've been a novice in significantly more than one language. With time, I came to regret each and every past choice in favor of a framework, without exception.
Those 5 minutes of finding out about the existing libraries that might cover your needs might feel like an eternal slog because it's just search and no fun, but it's literally 5 minutes, I am not exaggerating here. You don't need to find all of the libraries, you don't need to learn them in those 5 minutes - you just need to get a list that covers all that you have to do and that has some choices, that's it.
And since you're here, those 5 minutes of work could become 30 seconds of conversation. :) Outline what you need and post a question about suitable libraries, and read through the replies.
I appreciate you taking the time to explain your perspective > With time, I came to regret each and every past choice in favor of a framework, without exception. This in particular is an interesting experience, I can definitely see how over time the mindset shifts from “frameworks give me batteries / structure” to “frameworks get in my way of doing things” I guess I just need to embrace this mindset shift and learn how to roll my own structure around the libraries available Lastly, I’m sorry if I came across as someone who asked a question before doing a proper research, that’s not the case, I am slightly familiar with the tools you mentioned, one of the first things I did after reading the “Getting clojure” book was a simple https://github.com/RegiByte/todo-app-clojure that leveraged these most common libraries, based on the https://stack.bogoyavlensky.com/docs/lite from @abogoyavlensky it was a fun experience, though I was still unsure if I had built something “the right way”, just because it works, doesn’t mean it’s right. That’s why I’m trying to learn how to wire it myself from scratch, hopefully in the right way Anyway thanks again for sharing your thoughts sir! it will help me in my journey
@reginaldo.junior696 btw, thanks for using Clojure Stack Lite! If you need some support or clarification on the project setup, please, just drop a message on slack or create an issue on github. I’m happy to help.
I am the one to thank you sir! You’ve built something great, specially for someone like me who’s just getting started
> I’m sorry if I came across as someone who asked a question before doing a proper research Doing that in this specific channel is more than fine, it's somewhat expected. :) At least when that proper research would be longer than a few minutes.
I'd say yes, it's not that Clojure requires to be a specialist, but that there just isn't the handholding and "decision-already-made" for you that you can often find in other languages. Frameworks are one form of this. When there is one most popular framework. You just use it. And there will be tons of tutorials or Q&As of how to do X with it, and they'll all answer the same thing because the framework has already decided how each thing is to be done. Other such things are just really strong conventions, for which no one even has an opinion about or knows why it's like that anymore. Java has this for example, all books end up describing the same code structure and patterns, nobody asks themselves why they have a data access layer, and so on, it's just how most people do it. They don't know why, it's how they were told, and no one questions it. Clojure doesn't have any of that yet. It's more the wild west, land of opportunity, you could be the one to make that big framework, to invent the standard code patterns, etc. Generally it takes expertise already though to have the knowledge to put those together, and to opinion on it. In that sense I do feel it is easier for specialist. That said, this is a great way to learn and become a specialist.
Clojure has less ceremony than other languages, so there is less room for patterns and frameworks. It's often easier to express the ideas with just data and functions.
I'd say it's actually quite hard to realize that you can do things that simply 🤣 The amount of time people ask how do you say model a car? And I'm like:
(defn make-car [make, year, color]
#:car{:make make,
:year year,
:color color})@emccue I completed the caveman guide, and now I understand what you meant here > I’d say thats true, but my thesis is that the “ready made” part is less important than the “structure” part. This was exactly what I needed, there is a lot of value from building the structure from scratch, the learnings stick to you and you can reproduce the same in other projects I had a bit of a friction with mybatis when it was time to run tests using testcontainers, because I changed the default changelog table name to “migrations_changelog”, that broke a lot of things, so after 2 hours debugging I reverted back to the default config and things started working again, this being said, I’ll definitely checkout other migration tools next 😅 I took my time to document the end result here, will definitely use it as a reference for future projects https://github.com/RegiByte/clojure-caveman I cannot thank you all enough!!! This was a great experience ❤️ 👏
@reginaldo.junior696 glad to hear it - i should set up a testimonials page
> But the special thanks go to https://github.com/mccue
On github I am @bowbahdoe btw, i have no clue who that guy is
Oh my bad 😅 will fix it
Hello friends!!! Can anyone help me use Schemas in Clojure? I want to create a conditional similar to an if, for example:
(if (= true (when (s/validate user-model new-user)))
(println "1")
(println "2"))
Can anyone tell me how I can build something like this?(if (malli.core/validate :int 1) :yep :nope)
Apart from not needing (= true ...) and (when ...), it's ambiguous what you want.
If it's verbatim "if the value satisfies the spec, print 1, else print 2" then yeah, it's just a plain if.
But if you want something like "if the value satisfies the spec, also apply spec2 to it, else apply spec3, and all that must be done in the form of a spec", it's something else entirely.
@dpsutton I don't know this "malli.core", but I'll take a look, thanks!
Malli is a different library. Not applicable here if you want to stick to clojure.spec.alpha.
But clojure.spec.alpha has a similar function, validate?.
(if (s/valid? some-spec some-data)
(println "valid")
(println "invalid"))@p-himik my initial idea was something like: if it returns true - do x otherwise, if it returns null or false - do y But when I don't have a key or the correct value for a specific key, I can't validate because I stop to "read" the code:
oh sorry. what is s/validate. it shoudl all work the same. it’s a boolean function taking a spec and a value
In this printout, I change the value of :age to :ages to do this test
Ah, so it's Plumatic Schema, not core.spec, alright.
But doesn't change much.
So seems that s/validate throws when the value is invalid, instead of returning a boolean.
And given the API docs, seems like you should be using s/check.
@p-himik I don't know the clojure.spec.alpha too haha
@p-himik I'm willing to learn more about s/check, but my current problem is that I want to treat a message returned as "invalid data" or something similar, but when the data is invalid, it simply returns an error and I can't process it. Is there a function in Schema to validate this, or do I need to do it another way?
Not sure what you mean to be honest, or how s/check is not suitable.
Can you provide some code that would use a hypothetical s/perfect-check that does what you want?
@p-himik I don't know how to explain it better, so I'll try to rephrase it: I want to perform a validation to check if the keyword :age is present in some passed data. But right now, this is happening: If it has :age -> return true and continue If it doesn't have :age -> display the error and stop the code In this part, I want to perform a validation because I want to use this in an API, so I want to use two different messages for two different responses, for example: If it has :age -> (println "Okay, you are old enough!") If it doesn't have :age -> (println "Sorry, I'm not old enough!")
> I want to perform a validation to check if the keyword :age is present in some passed data.
That sounds like s/check is exactly what you need then. It returns nil if the value is valid and some data about what's invalid otherwise.
Have you tried using that function?
@p-himik I'll try this, I'll be back soon to let you know if I got it to work haha
@p-himik It worked here, man, I did this:
(if (= (s/check user-model new-user) nil)
(println "1")
(println "2"))
Thanksss bro, you're amazing!!!Great! BTW instead of (= ... nil) you should use (nil? ...).
Or, if it makes sense at that particular location, just use ... by itself and swap the if branches.
a larger point that might be needed here: (= true ...) and (= nil ...) are not used in normal code. if accepts all values other than nil or false for the first branch.
(ins)user=> (if nil 1 2)
2
(ins)user=> (if 0 1 2)
1