As far as possible, I think it is best to try and minimise mutable global 
state (like mutable configuration data) and implicit context (like dynamic 
vars). My preferred approach is to pass the configuration data (as a value) 
to a higher order function that constructs the configurable object / 
function appropriately. I regard this is more of a "functional" style. So 
you might do something like:

(def my-ring-application (create-application config-map))

Once constructed, the ring application is fully configured and doesn't need 
any extra parameters, i.e. it works just like a regular ring application. 
You can treat the ring application as being effectively immutable. If you 
want to reconfigure, then just create a new one!

This approach has several advantages:
- It's highly composable. Your components can easily be plugged together, 
since they aren't bound to any external configuration state.
- You can perform some significant optimisations in the construction phase 
(depending on the nature of the configuration you might be able to 
eliminate validation checks, optimise the size of buffers etc.)
- It's highly testable. Just create as many differently-configured 
instances as you like.

The main downside, of course, is that you need to be thoughtful and do a 
bit more work in designing the constructor function. But I think that's a 
worthwhile activity - it can often lead to a better design overall.

Note that this technique can apply to much more than web applications. You 
can even use it to construct objects that themselves contain mutable state. 
For example, I use this method to construct the entire GUI + running game 
instance for my little Clojure roguelike game "Alchemy". There is no 
mutable global state at all - you can launch several totally independent 
game instances from the same REPL. If you are interested, see the "launch" 
code at the bottom of this file: 
https://github.com/mikera/alchemy/blob/master/src/main/clojure/mikera/alchemy/main.clj

On Tuesday, 10 September 2013 15:19:35 UTC+8, Alexandr Kurilin wrote:
>
> I'm trying to determine how to best deal with the concept of globals in 
> Clojure. Say I have a map of configuration values for my Ring app, populate 
> at app startup from disk or env, and I need to reference the contents of 
> this map from all over the project. Assuming MVC, models and controllers 
> all would be interested in its contents. I just want to clarify that the 
> question is not so much about "configuration" as it is about dealing with 
> state that many different components in an application might be all 
> interested in. This is an issue that seems to arise very often.
>
> I'm seeing a couple of options here:
>
>    - Pass the configs map along with each Ring request with some 
>    middleware, and then down every subsequent function call that might 
>    eventually need it. It's a bit of a hassle since now you're passing more 
>    data, potentially increasing the # of parameters, or forcing you to use a 
>    parameter map everywhere where you might have passed along just 1 
>    primitive. Nonetheless, this is as pure as it gets.
>    - Def the configs map in a namespace somewhere and refer to it from 
>    wherever, just like global state. The trick is now that now you're no 
>    longer certain what e.g. your model functions are expecting there to be in 
>    the system and testing becomes trickier. Now you have to either lein test 
>    with a separate set of configurations (which doesn't actually give you 
> much 
>    per-test granularity) or use with-redefs everywhere to make sure the right 
>    test config state is being used.
>    - Something in the middle where perhaps you agree to never directly 
>    reference the configs map from your models (again, thinking MVC here) and 
>    instead only ever access it from controllers, and pass the necessary 
>    options along down to the model functions. This way you can test both 
>    controllers and models in isolation in purity.
>
> Ultimately I want to contain the chaos of having to know internal 
> implementation details of my functions at different layers and want them to 
> be easily testable in isolation. It does seem like the first option is the 
> most straightforward, but I'd be curious to find out what those of you who 
> have deal with the problem for a while would recommend. Purity all the way, 
> or are there patterns that can give you the best of both worlds? Or what 
> else?
>
>
>

-- 
-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to