Live data from Hacker News

Tour of our 250k line Clojure codebase

tech.redplanetlabs.com

61–70 of 237 posts

Re: Tour of our 250k line Clojure codebase

#61

Earlier quoted context omitted.

What I heard from colleagues that work with Clojure is that it is a horrible language where the default way of writing code is an imperative programming style where contexts are passed around and updated. Far from the concepts of functional programming.

What is this? Are you being serious? I've worked in multiple Clojure shops and it has always been amazing. All the core code and business logic etc. (kernel) is implemented functionally, and the interface with the outside world (shell) is implemented imperatively. Clojure being a horrible language is a really hot take and it being based on hearsay makes your coomment look like it's not in good faith.

As with all functional programming languages, if you limit the use to some specific areas you can get a lot done with a few easily understood lines of code.

Re: Tour of our 250k line Clojure codebase

#62

Earlier quoted context omitted.

Yeah, it's nice to see such thoughtful adoption of language facilities clearly oriented towards creating a successful and maintainable codebase. The Clojure team has always done a nice job expressing the rationale for specific language features, and these rationales often lean towards solving problems that system designers historically faced. Oftentimes, I think folks think of modern languages in regard to their synt…

Clojure doesn't solve the expression problem and the expression problem tends to be trivial in dynamically typed languages. Strictly speaking the expression problem is only defined for _static_ type systems because its concerned with _static_ type safety and extensions without recompilation.

It does solve it and doing so was a key design goal of protocols. It's right there in the docs:

There are several motivations for protocols:

Avoid the 'expression problem' by allowing independent extension of the set of types, protocols, and implementations of protocols on types, by different parties

I agree that it's a concern in static type systems, but the same issue rears its head when defining methods which operate on specific types of strongly typed data, so no, it's not always trivial, nor is it a problem exclusive to statically typed languages, and if it was, there wouldn't be a need to introduce a new abstraction for which addressing the problem is a key goal.

Re: Tour of our 250k line Clojure codebase

#63
post #28
post #5

Earlier quoted context omitted.

Interesting take since Clojure and Java are two very different languages. And unlike for example Kotlin, Clojure does not try to be a better Java than Java. But true though Clojure leverages the power of the jvm.

Interop from Clojure -> Java is still incredibly easy, though. I often will just wrap a Java library rather than look for a pre-existing Clojure implementation because it's so easy. Of course, most Java libs don't value immutability and functional patterns, but you can still push this kind of interop to the edges of your system and keep everything else in pure Clojure.

Depends on the style the Java library you are trying to use is written in. I have had mixed results. Especially the Java 8 functional style had some challenges. I might have the relevant SO question somewhere.

Re: Tour of our 250k line Clojure codebase

#64

> And doing things dynamically means we can enforce stronger constraints than possible with static type systems. Can someone please explain this to a novice like me?

IMO the sentence is incorrect. Static type systems would "enforce the stronger constraint" at run time... same as the dynamic type system. Perhaps the dynamic type system can have a fancy linter that does something crazy like running your code... but I'm not aware of any such linter.

Most static type systems that can do what clojure.spec can do tend to include runtime assertion and type checks and do not erase type data from runtime (what some static type zealots call "uni-type" approach).

For example Ada's type system, which has equivalent of Common Lisp's SATISFIES construct, which implements a runtime type assert that can use all the power of the language.

Re: Tour of our 250k line Clojure codebase

#65

> Detecting an error when creating a record is much better than when using it later on, as during creation you have the context needed to debug the problem. This is a great insight no matter what language or framework you're operating in. Laziness has its virtues, but invariants, validity checks, run-time type checks, etc. should all be performed as early (and often) as possible - it's much easier to debug issues whe…

Yes, and this is where statically typed languages shine (in my opinion). I like programming in a style that makes heavy use of the type system to enforce this. For example when writing an api endpoint to create a task I would typically deserialise the json into a CreateTaskRequest. If the object is created without exceptions I can be sure it is valid. CreateTaskRequest implements the ToTask interface. The service lay…

> Lots of classes and interfaces but they are all small and with a single purpose.

That's the side effect. You ultimately end up with more code and not less even though it saves you from type checks.

There are trade offs for both.

Re: Tour of our 250k line Clojure codebase

#66
post #11

Is there more info about the tool itself that claims 100X decrease in application development cost? Quite the claim.

It's still in stealth mode. They raised $5M in 2019: https://news.ycombinator.com/item?id=19565267

how exactly is it stealth if they have a blog and announced funding?

Re: Tour of our 250k line Clojure codebase

#67

Earlier quoted context omitted.

What is this? Are you being serious? I've worked in multiple Clojure shops and it has always been amazing. All the core code and business logic etc. (kernel) is implemented functionally, and the interface with the outside world (shell) is implemented imperatively. Clojure being a horrible language is a really hot take and it being based on hearsay makes your coomment look like it's not in good faith.

As with all functional programming languages, if you limit the use to some specific areas you can get a lot done with a few easily understood lines of code.

Quite the opposite. Functional style is especially useful in larger codebases. However, I think a functional strongly typed language is often easier to get right than a weakly typed one. I mostly write F# and Clojure and based on my experience I would go for F# any day over Clojure but at the same time I would also go for Clojure over Java as well.

I do not know where your views are coming from, sounds like 2nd hand experience rather than 1st one.

Re: Tour of our 250k line Clojure codebase

#69

> And doing things dynamically means we can enforce stronger constraints than possible with static type systems. Can someone please explain this to a novice like me?

Most static time type systems can enforce that a voting age is an Integer, say, but can't validate that any value is at least 18, for example.

This is not really true if you include ML languages. Most of the time you create a specific type for a type that is constrained. Ada has pretty good support for this and ML languages too. Once you have a specific type you make all your functions accept only VoterAge instead of Int.

Re: Tour of our 250k line Clojure codebase

#70

> Detecting an error when creating a record is much better than when using it later on, as during creation you have the context needed to debug the problem. This is a great insight no matter what language or framework you're operating in. Laziness has its virtues, but invariants, validity checks, run-time type checks, etc. should all be performed as early (and often) as possible - it's much easier to debug issues whe…

Yes, and this is where statically typed languages shine (in my opinion). I like programming in a style that makes heavy use of the type system to enforce this. For example when writing an api endpoint to create a task I would typically deserialise the json into a CreateTaskRequest. If the object is created without exceptions I can be sure it is valid. CreateTaskRequest implements the ToTask interface. The service lay…

You're writing more code than you have to though. More code = more bugs.
Post reply on HN