- The inestimable Malcolm Groves has a nice series going on the new Delphi Parallel Library. Recommended reading.
- I put a tag cloud over there on the left. Now I just have to remember to put tags on all my posts.
- I welcome feedback on the new blog. As I said, my goal is to keep the blog as simple and clean as possible and the content as interesting and useful as possible.
- I guess I should have realized that such a thing would exist, but I just found the Delphi Reddit. Thanks to folks that post my blog entries there.
- Another entry in the “How did I miss this?” department: A guy named Branko Stojakovic has built a blog covering most of the Gang of Four patterns. Maybe I did mentioned this before – I have a dim memory of it – but anyway, worth looking at and learning from either way.
An important step to writing Clean Code is the notion of separating “commands” and “queries” by using the Command Query Separation Principle. The notion was first discussed by Bertrand Meyer in his book Object Oriented Software Construction. This means that the idea is not new. In its basic form, it means we should separate the things that read data from the system and things that write data to the system.
The Command/Query Separation Principle means that there should be a clear separation between the updating of information and status in your program and the way that you read information from the program. Commands and queries should be separately declared (though you’ll find that commands can call queries but not vice-versa.) It can be a complex as ensuring that reading and writing take place in completely separate object, or as simple as ensuring that commands and queries are simply done in different methods of your objects.
Of course, the first question you’ll have is “What do you mean by ‘command’ and ‘query’?” Well, I’ll tell you.
A query is an operation that returns a result without effecting the state of the class or application. In Object Pascal, this is typically a
function. Queries should not mutate the state of a class. They should be idempotent. That means “denoting an element of a set that is unchanged in value when multiplied or otherwise operated on by itself.” (I had to look that up, by the way….)
As a general rule, queries should return a single value, and “asking a question should not change the answer”. They should be referentially transparent; that is, they should be perfectly replaceable with their literal result without changing the meaning of the system.
What this means practically is that your functions shouldn’t change the status of the system you are working on, whether that be a class, a framework, or an application. You should be able to run a query, i.e. a function, a hundred times in a row and get the same answer back each time. The function, because it doesn’t change the status of the system, can be safely called at any time without repercussions.
Now this should be a general rule — there are certainly cases where your query will change the state of the system (a dataset’s
Next call comes to mind). But generally, it’s a good idea to have your queries not change state.
A command is any operation that has an observable side-effect. It is any code that changes something in your class or application. Typically, in Object Pascal, a command will be a
procedure — that is, code that takes actions without returning a value. Commands can call queries (but queries should never call commands, because commands change the status of the system).
Commands should not in general return values. Thus, the use of
var parameters should be discouraged if not down-right banned.
Don’t Mix the Two
All your methods and routines should be easily identifiable as either a command or a query. Commands and queries should be separate entities in your code — with the exception that a command can call a query if need be. The use of
out parameters in a
procedure will confuse this issue, and thus should be discouraged. If you follow this rule, your code should be more “reasonable” — it should be easier to understand and easier to modify.
CQRS also encourages you not to violate what I consider to be a bedrock of sound development technique: Don’t try to make one thing do two things. For instance, here is some code that does exactly that:
procedure ProcessWidgets(aCollectionOfWidgets: TWidgetCollection; var aNumberOfProcessedWidgets: integer);
This method is a clear violation of CQS [NOTE: I orginally had this as CQRS] as it obviously is trying to be a command and altering the state of the system by processing widgets, but also tries to be a query by “returning” through a
var parameter the number of processed widgets. Instead, the system should have a simple command to process widgets and a separate query to return the number of widgets that were processed. The procedure is trying to be two things at once, and all kinds of mischief comes from making one thing do two things.
Following the CQRS principle in the design of your code will help to ensure the proper separation of concerns, resulting in cleaner, easier to read and easier to maintain code.
Jon Postel was a guy that wrote an early specification for the Transmission Control Protocol (TCP), one of the core protocols of the Internet protocol suite. You use it every day to surf the web, send emails, etc. One of the guiding principles that he used when writing it was this:
Be conservative in what you do, be liberal in what you accept from others.
This idea is also call the Robustness Principle, and is sometimes rephrased as “Be conservative in what you send, be liberal in what you accept.” When applied to TCP, it means that the sender of data should be strict in what is sent, ensuring that it is accurate and precise. It also means that the receiver of data should be forgiving and understanding of data to as large a degree as possible. If you send data, be as clear as possible in what you send. If you can accept the data sent, then you should.
Any application programming interface (API) should follow this principle. Thus, the same principle should apply to your code. The public interface of your class should be viewed as an API, and it should be conservative in what it sends, and forgiving in what it receives. When calling another API, your code should send out data in a completely conformant way, following the rules laid down by the receiving API. But it should be willing to receive input in a non-conformant way as long as the input can be understood.
For instance, if passed a string, you might be happy to accept strings with blank spaces on the beginning and end, and use the Trim function to clean things up for the sender. Your classes might provide overloads for input methods, accepting both and integer and a string as input, providing a way for your class to be as forgiving as possible.
But when you call another API, your code should be strict and always send data in the correct, expected form. You should trim your strings before they get sent along to the API you are calling. If the system expects integers, you are going to send integers. You should meet the specification completely.
Another example is the use of nil. First, your code should never pass nil to a method that you are calling. Always provide a valid instance if the API calls for one. Second, your code should accept nil, but “fail fast” if passed nil and raise an exception. You should never let your internals get into the state of nil, and while you should accept nil, you should immediately raise an exception at any attempt to set one of your internal references to nil.
Postel’s Law – a small but important way to write better code.
- Yet again, I’d like to thank all of you who have bought my book or received it as an upgrade incentive. Once again I’ll say that the book has been more successful than I ever imagined. So successful, in fact, that I’m going to work on another one along the same lines. By that I mean that it will be a book focused on code and not the building of UI’s or other such applications. Keep your eye on this space for more information. And thanks again – I’ve really very grateful for all the support.
- Blog Update: I’ve added Disqus as the default commenting system here. Seems really popular and cool, and I love to be popular and cool. However, it may have screwed up some of the early comments. I’ve also added a barrage of share options on each post, so share away.
- I hope you all can see this – it’s a Facebook link and I have no idea what their rules are – but this post led to an interesting conversation. The link about MS tools that spawned the conversation is interesting as well.
- Malcolm Groves does a great job explaining one of the more difficult things to understand in System.Threading.pas:
- I have thoroughly enjoyed having Castalia as a free part of my IDE as a promotion with Delphi XE7. Good news – an update is coming. And this new feature looks, well, amazing.
- Delphi XE7 Update 1 is available. Nice. The release notes have the link to where you can get it.
- I’d like to thank the great staff at EKON 18 for a great conference and a great trip. It was fun (despite the fact that I lost my phone and felt like a lost puppy without it). The conference was interesting, and I got to see old friends like Ray Konopka, Cary Jensen and Loy Anderson, Marco Cantu, and Sebastian Gingter. It was a great conference, and I was honored to be a speaker. Thanks to everyone who came to my talks.
- I also presented at another great CodeRage. I talked on enumerators and IEnumerable<T> from the Delphi Spring Framework. The replays are available online – or at least many of them are as they post them. I see that currently mine isn’t – I think that’s because I have to redo the Q&A portion. Stay tuned.
- Book Update: An e-book version of Coding in Delphi is available to you free – all you have to do is activate the trial of XE7. Good deal, eh?
- Apparently Delphi had a small but important role in the ESA Rosetta Project – you know, that spacecraft that actually landed on a comet. Pretty cool.
I am using the Crayon Code Highlighter. Let’s see how it works:
Option : IOptionDefintion;
Option := TOptionsRegistry.RegisterUnNamedOption<string>('The file to be processed',
procedure(value : string)
Option.Required := true;
Option := TOptionsRegistry.RegisterOption<Boolean>('OutputInUpperCase','o', 'The output should be in upper case',
procedure(value : Boolean)
Option.Required := true; Option.HasValue := False;
Option := TOptionsRegistry.RegisterOption<integer>('NumberOfIterations','n','The number of times the file should be processed',
procedure(value : integer)
TSampleOptions.NumberofIterations := value;
Option.Required := False;
Option.HasValue := True;
Looks pretty good I think.
Hello World from my new blog!
This is my new blog. My goal for it is to keep the design simple and the content interesting.
Interesting linksHere are some interesting links for you! Enjoy your stay :)
- May 2017
- April 2017
- March 2017
- February 2017
- January 2017
- November 2016
- October 2016
- September 2016
- August 2016
- July 2016
- June 2016
- May 2016
- March 2016
- January 2016
- December 2015
- November 2015
- September 2015
- August 2015
- June 2015
- May 2015
- April 2015
- March 2015
- February 2015
- January 2015
- December 2014
- November 2014