2013/9/11 Softaddicts <lprefonta...@softaddicts.ca>:
> We load configuration data once from zookeeper and conceal it in a name space.
> Changing the context is quite simple, we reload resources in this name space
> using a minimal  list of properties which says where the configuration data 
> should be
> pulled from in zookeeper.
>
> This is doable from the REPL at any time. No other name space keeps
> this stuff in vars. Any external resource is pulled at runtime from the
> configuration name space where they are cached except for some very short 
> lived
> structures (requests to storage, locks, queues, channels, ... for the 
> duration of
> the request).
>
> Test configuration data is also contained in zookeeper. Tests
> pull from this configuration tree the configuration they need.
>
> Part of the test stubbing is kept in this configuration.
>
> No mutations occur in the configuration data from zookeeper during the 
> "normal"
> app life  cycle. We allow config changes while the app is running but in a 
> special
> context of its life cycle. Namely the app has to enter a state that allows it 
> to
> reconfigured itself. This means that workers have been stopped, ....
>
> We can test a new configuration without mutating the previous one in zookeeper
> using a versioning scheme.
>
> This requires some discipline enforced by the configuration name space API.
> So far it's been a charm to work with.

Sure, and adding a binding call providing the same config as the one
found in root would allow for the whole thread to consistently read
the same value.

>
> Luc P.
>
>> 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.
>>
> --
> Softaddicts<lprefonta...@softaddicts.ca> sent by ibisMail from my ipad!
>
> --
> --
> 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.

-- 
-- 
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