According to Command-Query Separation principle, as well as Thinking in Data and DDD with Clojure presentations one should separate side effects (modifying the world) from computations and decisions, so that it would be easier to understand and test both parts.

This leaves an unanswered question: where relatively to the boundary should we put "asking the world"? On the one hand, requesting data from external systems (like database, extental services' APIs etc) is not referentially transparent and thus should not sit together with pure computational and decision making code. On the other hand, it's problematic, or maybe impossible to tease them apart from computational part and pass it as an argument as because we may not know in advance which data we may need to request.

  • 1
    That's where the concepts of callbacks comes in. If you don't know in advance what data may be needed, provide a callback to the computational code where it can specify what data it needs, and have the other layers do the actual fetching and providing. If it needs to be asynchronous, the callback could even specify another function to call with the fetched data when it has become available. Nov 2, 2013 at 16:37
  • 1
    @MarjanVenema, this is the only option that comes to my mind as well. Just from the theoretical point of view: if the method, otherwise side-effect-free, invokes side-effectful callback it becomes side-effectful. Probably my issue here is that I assume that separation computation from side effects requires the computation to be referentially transparent. Though it's not necessary true.
    – Alexey
    Nov 2, 2013 at 17:02
  • 1
    If that is your worry, your computation simply is not finegrained enough. You need to abstract out the decision making as to what other data/steps are needed. So split the full computation in steps based on where decisions are made as to what data is needed. Then have some kind of "director" that manages the workflow for the full computation: starting each step, getting back information from each step, using that to decide the next step and the data needed, starting a fetching process to get it and then passing the fetched data to the next step in the computation. Nov 2, 2013 at 18:20

2 Answers 2


On the other hand, it's problematic, or maybe impossible to tease them apart from computational part and pass it as an argument as because we may not know in advance which data we may need to request.

This is an instance where, as noted in the comments, passing in the ability to retrieve data (e.g., first-class function, an object that implements an interface, etc.) provides a convenient mechanism for isolating side effects.

A higher-order function whose body is pure has unfixed purity: http://books.google.com/books?id=Yb8azEfnDYgC&pg=PA143#v=onepage&q&f=false

I've written about this, calling this type of function a potentially-pure function: http://adamjonrichardson.com/2014/01/13/potentially-pure-functions/

If you combine a potentially-pure function with fall-through functions (which lack branching constructs and do as little as possible), a combination I call isolation sets, you can isolate side effects quite effectively and create very testable code: http://adamjonrichardson.com/2014/01/15/isolating-side-effects-using-isolation-sets/


You store the result in the class, this seems a bit strange at first, but does result in simpler code. e.g. no temporary variables in caller.

class database_querier
    feature -- queries
        was_previous_query_ok : boolean is
                Result = …

        previous_query_result : string is 
                Result = query_result

    feature -- commands
        query_db (…) is
                query_result = bla

    feature {none} --data
        query_result : string
  • 1
    Love seeing eiffel out in the wild.
    – SBI
    Jan 14, 2014 at 11:00
  • @sbi it is just pseudo code. :-) Jan 14, 2014 at 21:24
  • Close enough to make me happy ;)
    – SBI
    Jan 14, 2014 at 22:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.