Hacker News new | past | comments | ask | show | jobs | submit login

My favorite thing about Clojure:

You compose libraries, instead of totally buy into framework A or B. Some people prefer the opposite.

However, Composition works in Clojure because everyone is using the staples: functions, maps and seqs. Pretty much everything in the language can work as one (or all!) of them.

While I also like static types, this is my argument for a well designed dynanic language like Clojure or its Lisp relatives: stuff just snaps together like magic lego bricks.




Composing libraries instead of buying into a framework is a wonderful thing. It allows a developer to use just the parts they want, integrate them with just what the developer needs, and get on with whatever they're doing. It's a beautiful idea, and it can enable amazing levels of productivity.

With that said, might it also be possible that there could be some drawbacks? Having worked in and with Clojure, I found the ecosystem incredibly immature. It's somewhere beyond arrogant - reckless comes to mind - for most engineers to do all their own plumbing for a web service. The odds that they'll manage to design someone easily long-term maintainable are slim. The chances of authorization, authentication, potential SQL injection, and a thousand other security things being handled well is effectively none - the Clojure ecosystem often seems wildly ignorant of such things. The core philosophy of just composing the libraries you need with Ring means that anything you don't actively think of will be likely entirely neglected. This is a dangerous way to ship code that will be facing the real internet. Clojure requires you to fit absolutely every aspect of everything you're doing into your head and be handled by you, because nothing is going to do it for you. The lovely magical LEGO feeling is, sadly, a lie.

This stands in stark contrast to the level of consideration around maintenance and security that has gone into a modern, mature framework. Or a modern language where SAST is an option.

Doing low-level stuff feels absolutely amazing! The sense of control, of having your hands in the guts and the ability to do what you need without wasting time on bullshit magic, is heady and glorious. It's just perhaps worth considering that that magic can sometimes be incredibly valuable, well worth the tradeoff against the feeling of freedom.


> I found the ecosystem incredibly immature

This does not match my experience at all.

There is a thing called sane defaults. You solve a problem by decomposing it to simple elements, and then combine them to sane defaults, while still giving full power to your users. Examples of sane defaults in areas you mention:

- authorization/authentication: buddy (https://github.com/funcool/buddy) has both core library with crypto stuff and complimentary libraries for auth etc. For example, if you want to securely hash a password, you don't have to come up with salting yourself, just use buddy-hashers: http://funcool.github.io/buddy-hashers/latest/#quickstart

- sql: clojure.java.jdbc and it's successor next-jdbc for sql queries use vector with query string containing question marks for arguments and then arguments that get escaped, see select example here https://cljdoc.org/d/seancorfield/next.jdbc/1.0.6/doc/gettin...

- "other security things": ring site defaults, see https://github.com/ring-clojure/ring-defaults/blob/master/sr...


> There is a thing called sane defaults. You solve a problem by decomposing it to simple elements, and then combine them to sane defaults, while still giving full power to your users. Examples of sane defaults in areas you mention:

You're right! Sane defaults are incredibly powerful and let developers make the right decision by not making decisions at all.

When developers have to stop and remember to integrate a library for authZ and authN, and then integrate individual modules from it for their use case, some might opine that we have gone beyond the bounds of sane defaults.

Sane defaults for Clojure in a web context are a wonderful idea. It's unfortunate, then, that buddy is less sane defaults and more a toolkit from which someone assembling a framework has the option to choose sane defaults.


I did also find the ecosystem to be not-so-mature a few years ago. Compared to something like Rails or various Java collections of tools it feels like things are less available or simply a poorly-made Clojure veneer over and underlying Java tool.

Ecosystem takes a while.

(Yes, I was using both JDBC and Ring as well as other things like Leiningen. Core.async was a notable exception as something done better in Clojure than elsewhere)


Thank you for the viewpoint. It certainly has merit, but there is also the possibility of "metapackages" like luminus [1], a curated package of libraries that work well together. It's easier to make a framework in the land of libraries than vice versa.

Some of what you perceive as immature may be that the community is small, and a lot remains to be done.

[1] http://www.luminusweb.net/


You're absolutely right, it's easier to make a framework in the land of libraries.

With that said, it may be more difficult to get one used when the culture of library-land abhors frameworks. The Clojure developers I've worked with so far mostly seem repulsed by the idea of using a framework.

This leads me to fear that the ecosystem is likely to remain in the hole it has dug for itself. Possibility is wonderful, as you say, but it is unlikely to save applications being written today.


> repulsed by the idea of using a framework

I think this is one of the memes in the community which is starting to be reconsidered. You're not alone in seeing these downsides, and people are starting to write about it more (code and words). Things like Fulcro or even Datomic Cloud are very interesting developments in this regard.

[1]: https://jacobobryant.com/post/2019/grow/ [2]: http://flyingmachinestudios.com/programming/why-programmers-... [3]: https://github.com/fulcrologic/fulcro


This is a great conceptual point that I think can be missed by folks who prefer a constellation of quality library-style code over a single framework. It's true that the *nix ecosystem is a case of the former over the latter, and I think that can work nicely for library level code that is used to build applications. But, it's hard to build protocols; or maybe, more accurately, it looks like successful ones emerge rather than are constructed.

The closer you get to the application layer, the more it looks like high quality, opinionated frameworks and ecosystems are great. You get more mileage out of a sophisticated foundation once you're at that point, so your integration risk surface is higher if you choose to roll your own framework. To some extent, this is unavoidable, but I've always gotten value out of minimizing it.

To some extent, I think Clojure has some great things going for it because it can hook into the JVM and the Java package ecosystem. But if that's ignored, then it's essentially starting from scratch.

For folks who have production experience in Clojure: how valuable is Java interop in your experience? How often are you able to get away with using the most idiomatic parts of the Clojure-land ecosystem, and how often do you have to reach for Java-land? How easy is interop in terms of traceability?


> For folks who have production experience in Clojure: how valuable is Java interop in your experience? ]

Very, there a lots of high quality Java libraries, and interop makes it easy to use them. Especially when integration with other software (databases, message queues, etc) being able to use the Java client libraries is a blessing.


> how valuable is Java interop in your experience?

Clojure is designed to be a hosted language, and so Java interop is first class and integral to it. In fact, the standard library specifically excludes anything that overlaps with Java's, and is designed to complement the existing Java standard library.

> How often are you able to get away with using the most idiomatic parts of the Clojure-land ecosystem, and how often do you have to reach for Java-land?

It's not really like that, they complement each other and work in a symbiosis. Yes, sometimes it feels like the worst part of Clojure is Java, but not reinventing the wheel and leveraging battle tested Java libraries and tooling was a very smart pragmatic decision, so it's also the best part of Clojure. Just know using Java from Clojure is very idiomatic in of itself.

> How easy is interop in terms of traceability?

Pretty much seamless.


Pedestal is a web library that ships with security enabled by default.


Really though, Clojure web apps are at the php-no-framework level security days, not joking.

The most used HTML templater(hiccup) doesn't do any secure output escaping, bad password/session management, auth*, sql injection, bad encryption methods, its all there.


Hiccup has functionality to perform escaping with `h`. It doesn't do it by default though, for performance reasons and nesting of Hiccup in Hiccup. Normally, you'd just want to sanitize right before returning your response.

Doing it that way you can also perform more selective sanitation if needed.

Hiccup2 does sanitation by default, still in beta though.

The common SQL lib is java.jdbc or next.jdbc and they use prepared statements by default. Can you explain more where you see common risks for SQL injections?

I'm not sure what you mean by bad password and session management? Normally, the common lib people use is ring-defaults https://github.com/ring-clojure/ring-defaults what about these do you feel are insufficient? Maybe do a pull request about it.

Auth and encryption I agree, but the untold reason is that people just use Java bountycastle and Apache Shiro or other for that. Buddy is the most popular Clojure one https://github.com/funcool/buddy , but honestly, for that stuff, you want something super battle tested, that means popular, and Clojure as a whole isn't popular enough for that, so really just pull in a Java lib done, it works flawlessly within Clojure.


> Hiccup has functionality to perform escaping with `h`. It doesn't do it by default though, for performance reasons and nesting of Hiccup in Hiccup. Normally, you'd just want to sanitize right before returning your response.

One of the things that Rails' templates gets completely right is that it knows when something is nested and when it's going to be returned immediately. It is thus able to do its automatic escaping right before returning a response and not before.

At this point in history, I think this is the baseline behavior all templating systems should meet. Requiring users to remember to manually escape every output every time is begging for exploitation. Such a design error only strengthens the case that hiccup is not appropriate for serious use at this time.


It seems Rails used to default to not escaping as well, but in Rails 3 they switched to escape by default. And from what I'm reading, nested helpers do suffer from the over escaping, and in fact they warn not to blindly html_safe them. But I admit, I can't find very new guides on latest versions, are you saying ERB now tracks nesting and only escape once at the end?

That's actually what hiccup2 does as well by the way. I admit, it is a nicer behavior, and I'm not sure why hiccup2 hasn't gained more traction since it released, but you are free to use it, it's part of the normal hiccup release, just require hiccup2 instead of hiccup.

But hiccup is not the only popular Clojure HTML templating lib. Selmer, Clostache and Stencil which are much more ERB or Django like, both HTML escape by default.


You're right about Hiccup, but I don't understand the rest of your post.

What common SQL solution in Clojure are people using that introduces SQL injection, for example?


HTML templater has nothing to do with password/session management, auth, sql and encription, if your does, it does the wrong things.


I think you spliced that sentence wrong. It's bad templating, /along with/ bad session management, auth, sql, and encryption tools.


Do you have any evidence to support these claims? I've never had such problems, please see my other comment about similar concerns: https://news.ycombinator.com/item?id=20848195


I don't because I'm only speaking about how one should parse the sentence, not the facts of the sentence.


Same here. Most software I like is also a set of composable objects. A bit more difficult to understand initially, but much simpler and more resilient in the long run.

Examples include Emacs, Linux (especially distributions like NixOS or Arch) or classical Unix utilities.


composing libraries is amazing but it leads to time investment to read about said libraries and find the ones that you want.

That said Hickey gave a tiny argument to lessen the pain, the cost of freedom is often lesser than the cost of being jailed by a framework that cannot evolve




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: