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.
3
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
do
Result = …
end
previous_query_result : string is
requires
was_previous_query_ok
do
Result = query_result
end
feature -- commands
query_db (…) is
do
…
query_result = bla
end
feature {none} --data
query_result : string
3