
-----------------------------------
wtd
Wed Jun 28, 2006 11:11 am

Command/Query Separation
-----------------------------------
What the heck is Command/Query Separation?

I think that to answer that, we have to think about what it isn't.  As databases are the centerpiece around which most programming takes place these days, let's consider a problem in that domain.

You want to write a method in your class that queries a database and then returns the results to you.  Assuming we know how to query the database, this is a fairly straightforward task.  In a vaguely Java-ish example:

class MyClass {
   public DBResults queryDatabase() {
      DB myDatabase = new DB("foo");
      myDatabase.select("bar");
      
      DBHandle myHandle = new DBHandle(myDatabase);
      myHandle.execute("select * from baz");
      
      DBResults myResults = new DBResults();
      
      for (Line l ; myHandle.getResultsInRows()) {
         myResults.append(l);
      }
      
      return myResults;
   }
}

And that would seem all well and good, but let's think about it.

Our method is really doing two things.  It's executing a command, by executing an SQL query on the database.  This is a side-effect of the method.  It's also returning some value.

Command/Query Separation says this is a bad thing.  It makes it more difficult to comprehend the program.  A simple symptom of this is naming.  Do we give the method a verb name, because it causes a side-effect, or a noun name because it returns a value?

Rather, we would have something like:

class MyClass {
   private DBResults theResults;

   public MyClass() {
      theResults = new DBResults();
   }
   
   public DBResults getResults() {
      return theResults;
   }

   public void queryDatabase() {
      DB myDatabase = new DB("foo");
      myDatabase.select("bar");
      
      DBHandle myHandle = new DBHandle(myDatabase);
      myHandle.execute("select * from baz");
      
      theResults.clear();
      
      for (Line l ; myHandle.getResultsInRows()) {
         theResults.append(l);
      }
   }
}

Of course, it looks a bit nicer when expressed in the language Bertrand Meyer created with this and other ideas in mind.

class 
   MY_CLASS
creation
   make
feature
   the_results : DB_RESULTS

   make is
      do
         create the_results.make
      end
      
   query_database is
      local
         my_database : DB
         my_handle : DB_HANDLE
         iter : DB_ITERATOR
      do
         create my_database.with_name("foo")
         create my_handle.with_db(my_database)
         
         my_handle.execute("select * from baz")
         the_results.clear
         
         iter := my_database.get_new_iterator
         from
            iter.start
         until
            iter.is_off
         loop
            the_results.append(iter.current_line)
            iter.next
         end
      end
end

Ignoring the difference in the length of the loop, Meyer's Eiffel is better at this.  By default, features like the the_results variable are read-only from outside the object, meaning that distinct getters do not have to be written.  

Additionally, Eiffel enforces CQS.  If we had written query_database such that it returned a value, we would not have been able to call procedures which cause side-effects from within it.

A common real example of using CQS is reading input.  A sample:

class 
   FOO
creation 
   make
feature
   make is
      do
         std_output.put_string("Your name is? ")
         std_input.read_line
         std_output.put_string("Hello, " + std_input.last_string + "%N")
      end
end

Command/Query Separation is a powerful concept, and one worth investigating if you're working with an object-oriented language.
