Live data from Hacker News

Six Years of Professional Clojure

engineering.nanit.com

171–180 of 254 posts

Re: Six Years of Professional Clojure

#171

Earlier quoted context omitted.

> If we don’t get some big companies to take on this roll - Cisco - has built their entire integrated security platform on Clojure - Walmart Labs and Sam's club - have some big projects in Clojure - Apple - something related to the payment system - Netflix and Amazon, afaik they use Clojure as well even NASA uses Clojure. I think the language "is going somewhere"...

role* lol we made the same mistake. There is some adoption to be sure. But look at Google Trends for clojure.

What does Google Trends have to do with a programming language? PHP is trending, and Clojure is not, perhaps because Clojure gives you a lot fewer reasons to google stuff up?

I myself rarely use Google to find a solution to a problem, and certainly almost never have to google shit like: "how to open a file in Clojure"...

Re: Six Years of Professional Clojure

#172
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…

Maybe I've just never given it a chance, but I've never understood the appeal of being able to modify code in-memory while it's running.

I like a REPL for testing things out, or for doing quick one-off computations, but that's it. I would never want to, say, redefine a function in memory "while the code is running". Not just because of ergonomics, but because if I decide to keep that change, I now have to track down the code I typed in and manually copy it back over into my source files (assuming I can still find it at all). And if I make a series of changes over a session, the environment potentially gets more and more diverged from what's in sourced if I forget to copy any changes over. So I'd often want to re-load from scratch anyway, at least before I commit.

Am I missing something? Am I misunderstanding what people mean when they talk about coding from a REPL?

Re: Six Years of Professional Clojure

#173
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…

Maybe I've just never given it a chance, but I've never understood the appeal of being able to modify code in-memory while it's running. I like a REPL for testing things out, or for doing quick one-off computations, but that's it. I would never want to, say, redefine a function in memory "while the code is running". Not just because of ergonomics, but because if I decide to keep that change, I now have to track down…

Yes, what you are missing is that usually you are using an editor like emacs where you can modify a specific form and send it to the repl. That way there is no chasing back through repl history for a form to paste back into a file.

Re: Six Years of Professional Clojure

#174
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…

>You simply do not have that in a static world.

I keep seeing lisp people bandy about all of this design by contract/arbitrary predicate validation stuff. Can you give an example of an instance in which static types + runtime checks don't completely subsume this?

My intuition is that almost all of these methods people are talking about would have to be enforced at run-time, in which case I don't see how it's providing anything fundamentally more than writing an assertion or a conditional.

Re: Six Years of Professional Clojure

#175
post #19

> ... and the question regarding choosing Clojure as our main programming language rose over and over again If I find myself having to repeat myself justifying a certain decision time and time again, it's an indicator that the decision needs to be revised to be something which is a more intuitive fit for the organization.

I donno why you're being downvoted, it's a questionable decision and probably the company would have been better off with Python/PHP/Node. Hiring and onboarding are extremely important for a startup. You know what else? Finding answers to common questions on Google/Stackoverflow; I am now working with Ember and can tell you guys you take a 50% productivity hit by using a tool that's obscure on Google. Sure once you b…

> Hiring and onboarding are extremely important for a startup.

If you're a small company, you usually cannot afford to hire "mediocre" talent. It is much more expensive to undo the crapola they'd implement. Trying to hire those who are at least interested in learning and using languages like Clojure, Rust, Haskell, Elixir, Elm, etc., is a very good quality filter. ROI from hiring a smaller number of Clojure devs, rather than a few more "regular" engineers - is much higher.

> Finding answers to common questions on Google/Stackoverflow;

Clojure gives you far fewer reasons for Googling things than other language ecosystems. It is dense language and inspires you to write smaller functions, decreasing the surface area for the problem. Most of the time, asking questions in Clojurians Slack sends you halfway through the solution.

> I salute these brave companies for sticking to these obscure languages

They do not choose Clojure for the shtick; Clojure is a highly pragmatic and immensely productive instrument. There are many "success stories" with small and medium-sized companies. A few large companies like Cisco, Apple, Walmart, et al., actively develop in Clojure.

The same can be said about the engineers. They don't choose Clojure because "they hate Java". You can check any Clojure surveys of the past. Most Clojure engineers are experienced and "tired" developers. Seasoned hackers who have seen the action. For most of them - Clojure is a deliberate choice. Many of them landed in it after trying various other alternatives.

Re: Six Years of Professional Clojure

#176
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…

Maybe I've just never given it a chance, but I've never understood the appeal of being able to modify code in-memory while it's running. I like a REPL for testing things out, or for doing quick one-off computations, but that's it. I would never want to, say, redefine a function in memory "while the code is running". Not just because of ergonomics, but because if I decide to keep that change, I now have to track down…

Instead of typing things into a repl and copying back into source, imagine stepping through your source in a debugger.

Re: Six Years of Professional Clojure

#177

Earlier quoted context omitted.

Hey, so my my career path has been C# (many years) -> F# (couple years) -> Clojure (3 months). I understand multithreading primarily through the lens of async/await, and have been having trouble fully grokking the Clojure's multithreading. One of the commandments of async/await is don't block: https://blog.stephencleary.com/2012/07/dont-block-on-async-c... Which is why the async monad tends to infect everything. Cloj…

Not even. It was opening it, looking, realizing it would take a couple weeks, and going back to F#. I did this a couple times before fully giving up. IIRC/IIUC, Clojure's async support is closer to Go's (I've never used go), in the form of explicit channels. Though you can wrap that in a monad pretty easily, which I did for fun one day ( https://gist.github.com/daxfohl/5ca4da331901596ae376 ). But neither option was e…

Sounds more like you ran into a conflict of mental model and language feature, not necessarily that the language couldn’t achieve your goal simply.

Re: Six Years of Professional Clojure

#178

Earlier quoted context omitted.

There are numerous ways to redesign the function signatures, but I would imagine the simplest would be (again, idk Haskell syntax): getConfigurationDirectories: unit -> Maybe [FilePath] nonEmpty: [a] -> Maybe [a] head: [a] -> Maybe a initializeCache: FilePath -> unit Notice `nonEmpty` isn't really necessary because `head` could to the work. The above could be chained into a single, cohesive stack of calls where the r…

On the contrary the The NonEmpty type is fundamental to the approach in that example since it contains in the type the property being checked dynamically (that the list is non-empty). The nonEmpty function is a simple example of the 'parse don't validate' approach since it goes from a broader to a more restricted type, along with the possibility of failure if the constraint was not satisfied. The restriction on the N…

You are misunderstanding the system. You can organize the logic into whatever containers you want, but the essence of the system cannot be changed.

You are already handling a `Maybe` type because it's possible for your input to not exist. Because the first implementation of `head` also returns a `Maybe`, it is possible to "bind" them together (I'm leaving out `IO` because I am both unsure of the syntax[0] and it is immaterial to the example):

    head :: [a] -> Maybe a
    head (x:_) = Just x
    head []    = Nothing

    getConfDirs :: Maybe [FilePath]

    initializeCache :: FilePath -> Cache
    
    useCache:: Cache -> Value 

    main :: ()
    main = do

      // you don't need concrete values here
      maybeCache >= head >> initializeCache) // Maybe Cache
      
      // one option
      case maybeCache of
        Just c -> useCache c
        Nothing -> error "CONFIG_DIRS cannot be empty"

      // another option
      maybeValue > useCache) // Maybe Value
      
[0] I have never written Haskell, so the above is my best-guess at the syntax given the snippets available (and no extra research)

The two functions `head` and `getConfDirs` are "parsers" because they both return `Maybe`. Contrary to

> Returning Maybe is undoubtably convenient when we’re implementing head. However, it becomes significantly less convenient when we want to actually use it!

It is trivial to use a reference to `Maybe` because it is a monad that it is specifically designed to be used more conveniently than the alternative approaches in the case when a value may (or may not) exist.

Re: Six Years of Professional Clojure

#179
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…

Maybe I've just never given it a chance, but I've never understood the appeal of being able to modify code in-memory while it's running. I like a REPL for testing things out, or for doing quick one-off computations, but that's it. I would never want to, say, redefine a function in memory "while the code is running". Not just because of ergonomics, but because if I decide to keep that change, I now have to track down…

As others have mentioned - you’re probably talking about something like a python or node repl. Lisp repl development is not like python or node - you _work_ in the repl. The closer comparison might be between bash+node as a repl - up+enter and the like to rerun tests has an equivalent in clojure+IntelliJ. There’s no copy pasting but there are different key bindings.

One of the best parts about lisp style repl development is that you end up doing TDD automatically. You just redefine a function until it does what you want from sample data you pass in - without changing files or remembering how your test framework works. You can save the output of some http call in a top level variable and iterate on the code to process it into something useful. The code you evaluate lives in the file that will eventually house it anyway so it’s pretty common to just eval the entire file instead of just one function.

Since you don’t ever shut the repl down, developing huge apps is also quite pleasant. You only reload the code that you’re changing - not the rest of the infra so things like “memoize” can work in local development. That’s why it’s a bit closer to your bash shell in other languages.

If you’ve never tried it, I highly recommend trying the Clojure reloaded workflow [1] to build a web app with a db connection. You can really get into a flow building stuff instead of waiting for your migrations to run on every test boot.

[1] https://cognitect.com/blog/2013/06/04/clojure-workflow-reloa...

Re: Six Years of Professional Clojure

#180
post #53

Earlier quoted context omitted.

F# has a feature called type providers that make this sort of bookkeeping between the database and the code less tedious, but even if you mess it up, static typing still gives you more safety than dynamic. If your code blew up because it should have accepted an identifier it didn’t, you know that the code has not been written to handle that case and can fix it. Alternatively, you can just choose to ignore this, and d…

A demo of a SQL type provider in action: https://youtu.be/RK3IGYNZDPA?t=2539 It requires a bit of elbow grease to make it work with a CICD system... but it works :D

That's nifty.
Post reply on HN