How is the actual work flow you use when molding your app?
How is the actual work flow you use when molding your app?
The entire state of the program, including the code and the globals in memory, is preserved, and simply spun up in a different environment. This tripped me up for some time with Smalltalk - I didn't understand this.
It's the same with many lisps - you can frequently get a REPL directly inside a running program, and query/change the objects (including code) that is running. This was used to great effect in fixing the Deep Space 1 probe while it was 100 million miles away from Earth.
Can easily add a REPL to any Clojure program though.
I'm not quite sure what you meant by the dependency question. If you need to reference other namespaces, you can add new (require) imports in the repl or live-reloaded source files. If you need to add completely new third party libraries to the project, that's rare enough that a REPL restart is fine - there's a library to do it dynamically at runtime if you want to though.
So you can interactively change the code on Emacs, Cursive, CounterClockwise,... and then update the REPL state.
While using the REPL for debugging purposes.
So at the end of the coding session, all source files have the current state of the application.
Well yes, I do it daily at my work. We develop backend SOA enterprise services like that, it works great.
Surely even in Clojure code there are lots of dependencies so you can't just change one place in isolation.
Well, there still are a few, but very little compared to most other languages. That's because everything is immutable by default, and state is passed around instead of accessed globally most of the time. So you'd be surprised how often you can actually work in isolation. Achieving this was Clojure's number one design tenet. To have a language which promotes untangling dependencies as much as possible, that makes it easy to write simple untangled code.
The other thing to realize is that the program running is not an isolated one like when doing TDD. It is the full program, with all its dependencies, connected to the file system, your databases, etc. I don't mock anything, if I'm trying to write my DB query, I try it for real on a real database.
And I also guess that changes done on the repl aren't actually saved for the next time you run your app?
So, that's why Clojure has tight integration between your editor and the REPL. Or tight integration between code files and the REPL. You normally don't type code at the command line, in fact, the Clojure REPL has no UI or command line interface, it's a network repl which listens to messages over a port using a special protocol called nREPL. Each editor that support Clojure connect to it, and send the content of the buffer to it for you. So you're editing the file and saving it as you see fit, while also asking the editor to have the file or part of it as you edit be sent to the REPL. You can also edit the file, save it, and then have the repl watch file changes and auto-reload them as they change. That way can work even with editors that don't have Clojure support. There is a CLI you can use too, for when you want an ephemeral program. Some editor also build UIs for the REPl, allowing rich media to be printed instead, like an interactive graph.
And how do you do testing?
Well, you're always testing, as you code, in parallel. Since your code is running live as you edit, you see the impact of your change right away. You're expected to also write unit and integ tests, and you do that like in all other language. These are needed for regression testing, but you don't need tests to test something works, you'll be doing that as you code fron the REPL. You need tests to make sure someone in the future doesn't revert your functionality. I actually find these are much easier to write in Clojure, again because the language pushes you to write isolated easy to test code, but also because you don't need a test framework and a mocking library, the core language is enough offers both.
How is the actual work flow you use when molding your app?
First I create a project. Then I start a repl configured from that project, then I open my editor and connect to my repl.
Then I write my main function and load it in the repl. I add more and more functions, loading them and trying them out as I do. Once I've got enough, I orchestrate calls to them from my main method, loading and reloading it all as I go, seeing the result of every step in the REPL. When I'm satisfied, I save my file. Once I've got what I want, i create a test file, write some regression tests, and then git commit, send a CR request, and then git push. Rince and repeat.