Earlier quoted context omitted.
> If the object is created without exceptions I can be sure it is valid. Without some kind of custom validation system in place (JSON schema, property attributes, etc), that doesn't tell you much. With most serialization libraries I've used the default settings would let you deserialize {} into any class without an exception and all the properties would just have the default value for their type. Using stricter setti…
At the end of the day, when we're working with external data, no language is a silver bullet. But you can get pretty far by doing https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... and yelling at your colleagues when they don't. FWIW, this sort of thing can be done with a dynamic language, too. It's true that some static languages happen to be really far ahead of the curve with this sort of thing. But it…
Tour of our 250k line Clojure codebase
141–150 of 237 posts
Re: Tour of our 250k line Clojure codebase
#142Re: Tour of our 250k line Clojure codebase
#143Is there more info about the tool itself that claims 100X decrease in application development cost? Quite the claim.
It does seem odd. Stealth product. Bold claims. 3 blog posts one of which is a funding announcement and the other two having nothing to do with the product. I am intrigued but also a bit skeptical.
$10M, the new cost will be $100k, or $10k, or less.
$1M, the new cost will be $10k, or $1k, or less.
Re: Tour of our 250k line Clojure codebase
#144For the sake of the less experienced, I'd point them to these substitutions in particular:
Compojure: Reitit (which they used in the front end too, so migration maybe in progress) would be my preference for backend routing.
Component: Integrant takes Component's ideas, but prefers the flexibility of multimethods operating on plain data to the typed records approach for defining systems.
Schema: Once very popular, but superseded by clojure.spec (bigger in scope) and to a lesser degree Malli for data schemas.
Potemkin: Avoid, handy for some internal code organisation purposes but hostile to tooling and debugging IMO.
Re: Tour of our 250k line Clojure codebase
#145> 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…
A class full of strings feels like a code smell - but that is the proper representation of serving the request. And the alternative is needlessly restrictive. Ultimately it feels like pointless ceremony.
Re: Tour of our 250k line Clojure codebase
#146I was honestly skeptical, reading all of this clojure-macro criticism (constructive for the most part), but trust was restored when I saw the author. Well done, sir! Excited to see the details.
Re: Tour of our 250k line Clojure codebase
#147we have a clojure codebase that's about 100k lines. Honestly I'm kinda fed up with it. Certain 3rd party libs we've used have been abandoned. We wrote our own libs for a major framework and it is failing behind. Too many "I'm very clever" functions that are hard to understand and also have subtle bugs.
Obligatory evangalism: Considered Kotlin as a JVM-lang-of-choice? We use it on all our backends and we really love it.
Re: Tour of our 250k line Clojure codebase
#148Earlier quoted context omitted.
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…
I like this design for making requests, but I don't like it for serving requests. Because if you don't just make every field a String in CreateTaskRequest, and you want to examine it in some way, then you're losing information. E.g. if you make a field an int, and they provide a non-int value, your CreateTaskRequest can't hold that value so its just gonna have a 0. A class full of strings feels like a code smell - bu…
You shouldn't get to the point of having a CreateTaskRequest with a 0 that shouldn't be there.
Re: Tour of our 250k line Clojure codebase
#149we have a clojure codebase that's about 100k lines. Honestly I'm kinda fed up with it. Certain 3rd party libs we've used have been abandoned. We wrote our own libs for a major framework and it is failing behind. Too many "I'm very clever" functions that are hard to understand and also have subtle bugs.
Seconded. I work in a clojure codebase that were trying to get out of. There's just dead libraries everywhere and stuff that maintained by one person that gets no updates at all. That or we just end up making functional "wrappers" around Java libraries and at that point we might as well just write straight Java. Also yea everyone wants to be so damn smart having macros within macros within macros that no one knows wh…
One thing to keep in mind is that Clojure has excellent interop with Java, and it is trivial to write a small Clojure wrapper that just does critical thing for your dependency injection system e.g. startup and shutdown, and just pass through a reference to the Java object when you need to make function calls.
Another thing to keep in mind is that Clojure code is extremely stable, so pure Clojure libraries often require minimal maintenance, and code written for Clojure 1.3 runs on 1.10 99.99% of the time with no modifications.
Re: Tour of our 250k line Clojure codebase
#150Earlier quoted context omitted.
You implement your own custom validation. The point is to encode the fact that you've validated a value in its type. So you have e.g. DeserializeJSON (String) -> Foo, and then ValidateFoo(Foo) -> ValidatedFoo. And then all the business code works on ValidatedFoo.
I know the point, I'm a C# dev by trade, but if I'm going to implement validation that goes beyond static type checking, which is most of the time, I'd rather put it all in a single place and not have to deal with the type nuisance in every single line of code I write.