My Clojure environment consists of an editor, 3 shell scrips, and
various jars. In general I strive for very simple setup that minimizes
that amount of state that I have to maintain during a development
session.

The editor I use is TextMate. This works well for me because it has
native Mac keybindings, is simple and unobtrusive, and works well for
the other languages in which I work. I use the editor just for editing
- there is no integration with live Clojure processes.

The three scripts are "clj", "clji" and "cljd".

clj is the basic Clojure invocation script. It works by setting up the
classpath to include the local src, test, and classes directories as
well as a shared jar directory, and then invoking clojure.main with
any given command line arguments.

clji is very similar to clj but augments the classpath to include the
user.clj file and boots into a repl instead of exiting.

cljd is a simple Ruby script to manage Clojure dependencies (hence the
trailing d). It supports:
- cljd install <jar-file>: copies a jar file to the shared jar directory
- cljd qi: (quick install) runs ant, installs the resulting jar, then
runs ant clean
- cljd uninstall <jar-file>: deletes a jar file from the shared jar directory
- cljd extract <jar-file> <dir>: copies a jar file form the shard jar
directory to the given dir, e.g. to get a frozen copy of that jar.
- cljd list: lists all jars in the shared jar directory

I use unit tests fairly extensively. Most projects have a run.clj file
in the test directory, so I run tests frequently with $ clj
test/run.clj. I try to avoid testing in the repl, instead preferring
to commit tests to a unit test file so that they are repeatable in the
future. I don't adhere religiously to either the "test first" or "test
everything" ideals - sometimes I find those approaches appropriate but
others times I don't. However, designing an API for testability does
tend to improve its modularity and minimize its statefulness.

I have not found the need for a debugger; when I run into a tricky
problem I usually try writing more unit tests against important pieces
of code to check my assumptions. If I'm in a situation where unit
tests don't make as much sense - such as improving a UI in a webapp -
the key becomes being able to iterate as quickly as possible. Ring
with its backtrace and reloading middleware are often helpful here.

If there was one thing I hoped to communicate to other Clojure users -
especially newcomers to Clojure and Lisp in general - it would be that
you don't need to a sophisticated Emacs+Slime type setup to get
started or even to work seriously with Clojure. I've written a lot of
Clojure code and a simple text editor + shell scripts + vanilla repl
worked well for me.

- Mark McGranaghan

On Fri, Mar 6, 2009 at 11:35 AM, levand <luke.vanderh...@gmail.com> wrote:
>
> As my Clojure application is now getting quite complex, I was curious
> as to what "workflow" people are using for design, development,
> testing and debugging.
>
> I'll get started with what I've found, so far, though I am definitely
> open to suggestion. There are a few parts I'm not quite satisfied
> with.
>
> I use Emacs+Slime in windows (I'd prefer a Mac if I could afford one)
> as my primary development environment. I start Emacs with a project-
> specific batch file that adds all the libraries I use to the CLASSPATH
> environment variable and then invokes Emacs, so all I have to do to
> add a new library to the project is to dump it in the "lib" folder in
> my project, and add a line in the bat file.
>
> For high-level design, I usually just spend time thinking about it and
> jot down my ideas in a physical notebook. When I have a decent idea of
> where I'm going, I start banging out code - usually I do my mid- and
> low-level design as I code. Typically I just do the first thing that
> comes to mind that will work, and then refactor wherever I see an
> opportunity for improvement. I find that this works better than trying
> to do more detailed planning up front - no matter how much time I
> spent, there was always some variable or use case that escaped me and
> I'd end up making significant changes anyway. It also really tends to
> keep code size to a minimum.
>
> I try to write each expression in the REPL, first, to make sure it
> works, though this is becoming less and less necessary as I get more
> confident with Clojure.
>
> Currently I am in an effort to put my existing code, except for the UI
> portions, under complete test coverage using the test-is library. To
> keep things clean, I am putting all the tests for each file in a
> separate file.
>
> This is actually my first experience with unit tests. The motivator
> for it is a problem I am still struggling with - my time spent
> debugging is increasing exponentially relative to the amount of code I
> have. Hopefully unit tests, in conjunction with writing smaller, more
> atomic functions will allow me to have more confidence in individual
> functions which will ease the debugging process.
>
> Debugging itself is probably my biggest headache, and I think it's
> really the only point where Clojure's lack of maturity presents a real
> problem.
>
> When I encounter unexpected results, I typically follow this pattern:
> 1. If there is a stack trace, inspect it to see if it tells me the
> problem (usually it doesn't - it really only helps for syntax errors)
> 2. Inspect the code to make sure its nothing obvious.
> 3. Use the REPL to construct a data structure like the one in
> question, and pass it to the function that seems to be the problem
> (This can be a real PITA with a more complex structure - in my case,
> more often than not, it's a zip of an xml file.
> 4. Decompose the data structure and function from step 3 into their
> component expressions and apply them, one by one, until I find one
> that doesn't work.
> 5. Loop back to step 3, only one function further down the call stack,
> until I find the problem.
> 6. If I'm desperate or the problem is heavily recursive and too
> complicated to use the procedure above, I add trace statements. I hate
> doing this, though, since it requires adding lots of ugly (do
> (println...) ...) blocks and juggling s-expressions.
>
> This can take hours even for an extremely simple bug, if it's buried
> deeply enough.
>
> I have tried using JSwat - in some cases it can be of help, but I
> can't get it to work smoothly and reliably. If just inspecting a
> variable helps to solve the problem, then it's a help, but I can't
> make it reliably step through and inspect at each step of the way.
> Sometimes, it also will refuse to hit a breakpoint, for no apparent
> reason.
>
> My dream debugger would be to pause execution on a certain line, be
> able to step through function calls, and have a REPL with all local
> vars available so I could explore the problem. But I'm pretty sure
> that doesn't exist.
>
> Anyway, that's my process, and my frustrations. How do you all do it?
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to