Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 Command/Query Separation
Index -> General Programming
View previous topic Printable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: Wed Jun 28, 2006 11:11 am   Post subject: 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:

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

code:
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.

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

code:
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.
Sponsor
Sponsor
Sponsor
sponsor
Display posts from previous:   
   Index -> General Programming
View previous topic Tell A FriendPrintable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 1 Posts ]
Jump to:   


Style:  
Search: