I'm a bit fond of the short 5-part series here https://malisper.me/debugging-lisp-part-1-recompilation/ that covers some of the debugging aspects, it's got some animated gifs. But there are several screencasts referenced on https://lisp-journey.gitlab.io/resources/ that may be worth exploring, though the fastest method is probably to just try building something yourself with the constraint that you never restart your Lisp image. Not too long ago I ported an old 2D maze generator I made in pygame to CL with SDL2, then while I had it up I decided I should add a solver to it, so ported an old A-star implementation I wrote in C++ and hooked up drawing (with dots) a path from any point to any other point. Then I wanted to draw a nicer sprite path that connected and handled corners by curving, so I swapped those in and then one-by-one recompiled the code with new ifs to handle each corner case to select the right path tile. Having to close and relaunch and reset the test points (and save and restore the maze seed) every time I made a code change would have been rather tedious.
If you've worked in Java, download the JRebel extension for more complete hot-reloading support, and that'll give you an approximation of the interactive development experience. It's especially useful for web apps where you can change the code for an endpoint (or used by several endpoints, whatever) and can then just test it out with new requests, no need to restart the server.
That first link is the one I was trying to recall. It's a good introduction to it.
I had some fun doing "debugger driven development" with Lisp for the Synacor Challenge. Basically, you have to implement an interpreter/VM and there are some number of instructions (around 20?). Instead of trying to correctly implement all of them from the start, I had a core loop like this (not exactly, summarized):
(loop with pc = 0
for instruction = (aref memory pc)
do (ecase instruction
))
ecase will signal an error whenever there is no matching case, taking you to the debugger. I read what instruction caused the error, checked the spec, implemented it, and resumed the program. Throw in a few asserts as sanity checks to complete the process. I don't recall the instruction set, but suppose that "add a b c" means add the values in registers a and b and store in c, then maybe I'd do something like this:
(10 ;; or whatever opcode meant ADD
(... logic for addition ...)
(assert (= c (+ a b))) ;; with whatever was needed to obtain these values correctly
If I implemented something incorrectly, I just rewrote the logic, recompiled, and restarted again. It was an enjoyable way to build the system, but of course it also relied on having a fairly comprehensive notion of what the end result would be and I did have to refactor at the end. But I had some good test cases by that point so refactoring wasn't bad.
I did the same thing for another project where I had a variety of input files that exercised various parts of the system and just continuously iterated until I got the expected result for an input relying on the debugger (triggered by ecase and assert and (error 'unimplemented)) to detect where I hadn't implemented something or had implemented it incorrectly or incompletely (like maybe one input exercises a particular edge case that others didn't). Once a file was properly processed, I wrote that up as a proper test, and moved on to the next file. Which then made the refactoring easy because I had a comprehensive test suite.
If you've worked in Java, download the JRebel extension for more complete hot-reloading support, and that'll give you an approximation of the interactive development experience. It's especially useful for web apps where you can change the code for an endpoint (or used by several endpoints, whatever) and can then just test it out with new requests, no need to restart the server.