8 ms·
Clojure is Capable
- lopatin 8y agoSo Clojure and CLJS are amazing. If I were to pick a Lisp for a real world project, Clojure is the obvious pick. The thing is, I'm curious to hear from people who DO use Lisp in the real world. I would characterize my experience with it as 1: Really fun. 2: Productive on a small scale due to the tooling, interop, libraries, and community being innovative and awesome, and 3: Infinitely flexible, because you know .. it's a Lisp. Development becomes like doodling on a piece of paper, like a stream of consciousness. But I ended up choosing Scala for a recent, fairly large, project of mine and I'm convinced it was the right decision. Without a static type system I would have simply lost a handle on the complexity of the project. And this is while working alone (the case where Lisp traditionally has the upper hand). A few questions for people who use Lisp in production. No need to answer all, just things I'm curious about: * During refactoring, do you feel more flexible, or less? I can see both sides to the argument. On one hand, static types are more rigid, and getting something to compile during a refactoring can be a pain. Often for the right reasons, but often it's due to some annoying technicality in the type system. But once you get there, "if it compiles, it runs" is a cliche that is pretty accurate in my experience. On the other hand, with a dynamic type system, you can slowly evolve a code base and see incremental progress during a refactoring, but I can never get over the dreadful feeling of "what did I forget?". Has clojure.spec worked out in terms finding bugs during refactoring/maintenance and general QA? * Do you make use of the Lispy-ness (Homoionicity, macros, code is data, etc ...) or is it generally an anti-pattern to use these language features in daily development? * Do you wish you had static types? If so, have you tried gradual typing like Typed Clojure? And if you don't miss types, why? I remember someone saying of Typed Clojure "We went to Clojure to get away from types!". And I'm still trying to understand the mindset. I often have the feeling that I'm not smart enough to use Lisp. If I had 2x the brain power, I would be able to use macros to conjure up some black magic in 100 lines what would take a mortal 5k in a lesser language. But even if I manage such a feat, I couldn't imagine bringing on another developer to that codebase.
- wooby 8y agoAt a Clojure meetup I attended a couple years ago, a long-time Java programmer asked "how do you manage huge projects without static types?" The best answer I could think of was, "don't manage huge projects." Instead, divide projects as early as possible in development into supporting libraries, each capable of being independently tested and maintained. In my experience, applications developed with this attitude coalesce themselves into a small ecosystem of mostly generic library code with a domain-specific apex "application" entrypoint to bind them. In an application factored like this, type checking isn't something you want as much anymore, since the constituent libraries interface with one another at a level above. They present and consume "public" (intra-application) APIs, the behavior of which are defined not just by types but by at least documentation and tests. The thing that static types let you do -- have huge amounts of code, woven together with structural dependencies -- is no longer a thing you need or want. It would seem bad, actually, since what you'd have is an inscrutable mass only a machine can understand. I haven't worked enough with large non-Clojure codebases to say whether or not this approach is superior, but I can say that it scales. Another nice thing about it in a business setting is that supporting libraries lend themselves to open-sourcing, and a relationship with an open source community is a good thing for a company's development efforts/hiring/contracting in my experience. To answer your specific questions: * I don't think I write more unit tests (I should probably write more tests in every language I use) * I don't have any experience with clojure.spec * All of the features of Lisp work together to make it awesome, including macros. In particular, in the context of an "ecosystem of libraries" approach, macros are a fantastic tool for exporting a DSL from a supporting library. They're also use for DSLs in the apex code, where application-specific behavior can be defined in terms of a DSL. * I don't really wish I had static types - I love Lisp the way it is. But I have found various languages for structural checking useful with certain kinds of sub-program, like receiving data from the outside world, and for writing compilers. If you write a compiler as a series of transformations, it's nice if the shape of the code between transformations is well-defined somehow. You're definitely smart enough to use Lisp. I think the key to success is not necessarily smarts, but attentiveness to modularity or cognizance of the difference between "library" and "application" types of code. * There's a Paul Graham essay related to this idea: http://www.paulgraham.com/progbot.html http://www.paulgraham.com/progbot.html * I think this approach is applicable not just to Lisp, but maybe to any dynamic language with a sufficiently rich set of generic collections and with the concepts of a "module" or "package".
- akhilcacharya 8y agoThis is wonderful! Just what I was looking for in terms of real world Clojure.
- shadowmint 8y ago> Interactive REPL based workflow (think of programming in Clojure like playing a difficult video game based on trial and error with emulator save states vs without). What? I'm not sure I understand what that's even trying to say? Is it trying to say, think of programming as playing a difficult computer game, and using a REPL like having save states? ...because it sounds like you are saying programming in Clojure is like playing a difficult video game based on trial and error, which is a really rubbish endorsement. > To touch on the video game analogy - imagine playing one of the old Mega Man games, Dark Souls, or Battletoads. Now, imagine that instead of getting feedback (a death) that results in a hard restart at the beginning, you instead just get taken back one action / event that caused an error (a single failed function call in REPL). That's like loading a save state, and if you like easy mode, you'll love the Clojure REPL. ? mmm... but if your analogy is 'this is like doing something really hard, but you can timestep back to save state so it's not so bad', then you're still basically saying writing Clojure is really hard. I don't think that's really a fair thing to say about Clojure, it's just a terrible analogy. Expressing things in Clojure is what it excels at; if you want an anology the REPL is more like a minecraft sandbox that you just continually keep building in, rather, than planning out your structure on paper before you start playing.
- tosh 8y agoAs I understand the analogy: the (difficulty of the) video game is the problem domain. Clojure + REPL is save states / time travel (could be clearer though)
- giornogiovanna 8y agoIt's saying programming is really hard, but Clojure gives you save states.
- StreamBright 8y agoWell most of the people write code in small chunks that yields to the following workflow: - write code - compile & run, see if it works Just keep repeating this until you achieved what you want. In REPL this is exactly the same you just have a much faster way of trying out a concept. I think this is pretty simple to conceptualise.
- cube2222 8y agoI really like clojure as a language, but it seems like the bus factor is very problematic. Observing the community I see rich hickey, as well as cognitect as a whole SPOFs, which hold me back from devoting more time to it.
- kgwxd 8y agoIt's open source so, if things go awry, anyone with a dictionary and a passion for pulling things apart can take over ;)
- yogthos 8y agoThere are many companies that have invested their core business in Clojure, and the language has been around for a decade. There is absolutely no risk here. If Rich disappeared tomorrow, there would be no lack of people ready to step in and continue working on Clojure. In fact you can already see that happening with ClojureScript where there is a lot of community involvement in the development.
- agumonkey 8y agoInteresting blend of raw clojure, java interop, os integration... very very nice
- sidcool 8y agoFor any project bigger than a certain threshold, I always prefer Scala over Clojure or even Java. For smaller projects, Clojure fits well.
- yogthos 8y agoEvery large project can, and should, be broken down into small isolated projects that are developed and maintained independently. Furthermore, I think that writing software using monolithic design is bad practice. It creates coupling within the project, and it makes it harder to reuse code. It's harder to onboard new people, and so on. However, the biggest problem is that it creates a lot of communication overhead for the team. The more people you have working directly with each other, the more emails, meetings, and other kind of communication you end up incurring. Splitting things up into small components that are each maintained by separate teams of 5~6 people is a far more productive way to maintain large software projects than to create monoliths.
- sidcool 8y agoYour arguments hold true for a regular run of the mill software project. Many real world projects are hardly ideal.
- yogthos 8y agoUsing static typing as a crutch to work around poor project architecture doesn't actually solve the problem. Also, there is a question whether static typing is what contributes to projects being written in a monolithic style in the first place. I often see this to be the case for projects written in statically typed languages, while ones written in dynamic ones tend to be broken up much more aggressively from the start.
- StreamBright 8y agoI still miss the proper Java interop. Calling SAMs is not fun and I could not figure out the proper way of make it work from Clojure. We ended up needing to write a Java wrapper.
- unlogic 8y agoDo you mean having to reify java.util.function.* classes?
- StreamBright 8y agoLike this for example: https://stackoverflow.com/questions/53731940/using-static-methods-from-clojure https://stackoverflow.com/questions/53731940/using-static-me...