Live data from Hacker News

Six Years of Professional Clojure

engineering.nanit.com

41–50 of 254 posts

Re: Six Years of Professional Clojure

#41
post #30

Earlier quoted context omitted.

You've seen a case where someone wrote something in Python that later devs could not understand and then rewrote it in . . . what? And you've seen that with Java? There's a big difference between a developer going off and writing something in one of the top five most used languages in the world and doing so in Scala.

Both are strange and alien to Javascript developers, who can be full stack. Python may seem simple once you know it, but going in blind there's plenty of traps to bite you. Significant whitespace for one.

I think there's two different issues:

1. picking a language/tool that a company doesn't have personnel with experience using it

2. picking a language/tool that is esoteric, which generally implies #1 as well.

#1 on its own isn't great, but generally when sticking in the java/python/ruby/javascript/php/etc...mainstream languages, there's a lot more documentation, and there's a higher chance that _someone_ in the company will have some familiarity. If nothing else, it'd be easier to hire a replacement for.

Re: Six Years of Professional Clojure

#42

> An incoming HTTP request? it is a plain Clojure dictionary. I learned to code in Python. Loved it. Dynamically typed dicts up the wazoo! Then I learned why I prefer actual types. Because then when I read code, I don't have to read the code that populates the dicts to understand what fields exist.

Question: 1. Can a GET request have a non-empty request body? 2. Assuming you don’t know the answer to that question, will the type system you use be able to tell you the answer to that question? This is a pretty simple constraint one might want (a constraint that only certain requests have a body) but already a lot of static type systems (e.g. the C type system) cannot express and check it. If you can express that c…

Any statically-typed language with generics can express that by parameterising the request type with the body type. A bodiless request is then just Request[Nothing] (or Request[Unit] if your type system doesn't have a bottom type). Accessing the headers just requires an interface which all static languages should be able to express.

Re: Six Years of Professional Clojure

#43
post #41

Earlier quoted context omitted.

Both are strange and alien to Javascript developers, who can be full stack. Python may seem simple once you know it, but going in blind there's plenty of traps to bite you. Significant whitespace for one.

I think there's two different issues: 1. picking a language/tool that a company doesn't have personnel with experience using it 2. picking a language/tool that is esoteric, which generally implies #1 as well. #1 on its own isn't great, but generally when sticking in the java/python/ruby/javascript/php/etc...mainstream languages, there's a lot more documentation, and there's a higher chance that _someone_ in the compa…

A higher chance, yes, but it doesn't matter much; what is tricky with most applications is the domain. Certainly, it's faster to go learn a language than to learn a new domain. To that end, you can get the whole team trained faster in a language than you can hire someone with experience and train them to the domain.

Re: Six Years of Professional Clojure

#44
post #29
post #22

Earlier quoted context omitted.

I've admittedly not played with spec, but can't you solve documenting interfaces by defining `defrecord`s ? You rarely really care about the actual types involved. You just want to know which fields you either need to provide or will recieve

Spec will give you stronger feedback than a docstring or function signature. It can tell you (in code terms, with a testable predicate) if a call to an interface wouldn't make sense. Eg, spec can warn you when an argument doesn't make sense relative to the value of a second argument. Eg, with something like (modify-inventory {:shoes 2} :shoes -3) spec could pick up that you are about to subtract 3 from 2 and have neg…

Does the spec logic typically live inside the modify-inventory function, or elsewhere? If elsewhere, what triggers it before the function is called?

Re: Six Years of Professional Clojure

#45
post #6

One thing I don't like about all articles on clojure is that basically all of them say: ah, it's just like lisp with lists `(an (example of) (a list))` with vectors `[1 2 3]` thrown in. So easy! But then you get to Clojure proper, and you run into additional syntax that either convention or functions/macros that look like additional syntax. Ok, granted, -> and ->> are easy to reason about (though they look like addit…

    {:pre [(de/entity? entity)]}
is "syntactic sugar" for

    (hash-map (keyword "pre") (vector (de/entity? entity)))
while

    (.getAttribute mount "data")
is calling the method `.getAttribute` on the `mount` object – since it's a Lisp, it's in prefix notation. It also highlights how methods are not special and just functions that receive the object as first argument.

Finally,

    @*post
is the same as

    (deref *post)
and the `*` means nothing to the language – any character is valid on symbol names, the author just chose an asterisk.

Most of what you believe to be syntax are convenience "reader macros" (https://clojure.org/reference/reader), and you can extend with your own. You can write the same code without any of it, but then you'll have more "redundant" parenthesis.

Re: Six Years of Professional Clojure

#46

Earlier quoted context omitted.

Question: 1. Can a GET request have a non-empty request body? 2. Assuming you don’t know the answer to that question, will the type system you use be able to tell you the answer to that question? This is a pretty simple constraint one might want (a constraint that only certain requests have a body) but already a lot of static type systems (e.g. the C type system) cannot express and check it. If you can express that c…

Any statically-typed language with generics can express that by parameterising the request type with the body type. A bodiless request is then just Request[Nothing] (or Request[Unit] if your type system doesn't have a bottom type). Accessing the headers just requires an interface which all static languages should be able to express.

How about values restricted to identifiers currently in the database table? There's always something the type system can't do.

Re: Six Years of Professional Clojure

#47
post #33
post #3

I found one of the perceived weaknesses of Clojure (in this article), it being dynamically typed, is a tradeoff rather than a pure negative. But it applies that tradeoff differently than dynamic languages I know otherwise and that difference is qualitative: It enables a truly interactive way of development that keeps your mind in the code, while it is running. This is why people get addicted to Lisp, Smalltalk and si…

I think, the big issue with dynamic typing in popular languages like PHP and JavaScript are the automatic conversions.

You mean implicit type conversions? That's a thing you can get somewhat used to. But it throws off beginners and can introduce super weird bugs, because they hide bugs in weird ways, even if you are more experienced. Yes, I find strong typing strictly better than weak typing.

An even better example of this would be Excel, the horror stories are almost incredible.

So even if your environment is dynamic, you want clarity when you made a mistake. Handling errors gracefully and hiding them are very different things. The optimal in a dynamic world is to facilitate reasoning while not restricting expression.

Re: Six Years of Professional Clojure

#48
> Pure functions make code design easier: In fact, there’s very little design to be done when your codebase consists mostly of pure functions.

Ummm... I am a little bit fearful about your codebase.

If you don't see the need for designing your FP system it probably mostly means it is being designed ad hoc rather than explicitly.

If you are trying to compare to OOP system done right, you will notice that this includes a lot of work in identifying domain model of your problem, discovering names for various things your application operates on, and so on. Just because you elect to not do all of this doesn't mean the problem vanishes, it most likely is just shifted to some form of technical debt.

> Clojure is a dynamic language which has its advantages but not once I stumbled upon a function that received a dictionary argument and I found myself spending a lot of time to find out what keys it holds.

Dynamic typing is a tradeoff which you have to be very keenly aware of if you want to design a non-trivial system in a dynamically typed language.

It is not a problem with Clojure, it is just a property of all dynamically-typed languages.

Re: Six Years of Professional Clojure

#49
post #30
post #16

Earlier quoted context omitted.

That is possible with all languages. I've seen java, scala, clojure, perl, python, etc. Usually this is made worse by bespoke build tools and optimizations that make the system punishing to pick up.

You've seen a case where someone wrote something in Python that later devs could not understand and then rewrote it in . . . what? And you've seen that with Java? There's a big difference between a developer going off and writing something in one of the top five most used languages in the world and doing so in Scala.

Yes. I've seen and contributed to dumpster fires in all of those languages. I would love to say it was all some rogue developer that crapped on things, but it is often just new developers. The more, the more damage.

Re: Six Years of Professional Clojure

#50
post #31
post #15

Earlier quoted context omitted.

To be fair, an incoming request is, almost by definition, dynamic. It makes sense to have that as a map, since the main sensible thing to do on receipt is validation/inspection. Granted, you may have a framework do a fair bit of that. Depends how much you want between receipt of the request and code you directly control.

Usually the approach in a statically-typed language is to transform your dynamic request into something that you know through parsing instead of validation. Here's a great article about this: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... .

That is a valid approach in any language. Static or not. Doesn't change my point that heavily. And it is all too possible to pick a bad parsing/binding language such that protocol changes in the request are now foot guns.
Post reply on HN