Delphi Development Pretty Good Practices #4 – Do Work in Classes
The next principle for the “Pretty Good Practices” we’ll discuss is this notion: Whenever possible and as much as possible, put functionality in a class – preferably a class that can be easily unit tested, reused, and separated from any user interface.
TextScrubber demonstrates this via the use of the TTextScrubber class in the uTextScrubber.pas unit. TTextScrubber is a simple TObject descendant that does all the work for the whole application, really. It is a standalone class – you could take the uTextScrubber.pas unit and use it in most any project you cared to. Because of this, it is also very easy to write unit tests for this class. (We covered unit testing in my previous series “Fun with Testing DateUtils.pas”, but I’ll discuss Unit Testing in a later post in this series as well.) The class attempts to follow the “Law of Demeter”, which says that classes should know as little as possible about outside entities. The three principles of the Law of Demeter are as follows:
- Each class should have only limited or hopefully no knowledge of other classes.
- If a class must have knowledge of other classes, it should only have connections to classes that know about it as well.
- Classes should never “reach through” one class to talk to a third class
In the case of TTextScrubber, it only knows about and utilizes the TClipboard class and nothing else. It doesn’t try to grab things out of TClipboard or attach to or require any other class. It pretty much minds its own business, utilizes the services of the clipboard, and provide an easy way to get at its functionality. It endeavors to do one thing: scrub text, by both straightening and “un-formatting” it. It has short, sweet method bodies, and ensures that it doesn’t try to do too much beyond exactly what it is supposed to do. Following the Law of Demeter tends to make your code more maintainable and reusable. By reducing dependencies, you ensure that a class is as flexible as possible and that changes to it don’t tend to have far reaching consequences.
So, to as large a degree as possible, you should endeavor to put the functionality of your program into classes. One way to tell you are not doing this is if you tend to do “OnClick” programming, or relying on event handlers to do the work of your application. The Pretty Good Practices way of programming would dictate that your event handlers would contain code that merely instantiated and used other classes instead of having the actual code in them to do the work of your application.
So for instance, most of the work in TextScrubber gets done in an OnClick event of the TTrayIcon component. That code looks like this:
procedure TStraightTextMainForm.MainTrayIconClick(Sender: TObject);
begin
MainTrayIcon.Animate := True;
case TextScrubberOptions.ClickChoice of
ccStraightenText:
begin
DoStraightenText;
end;
ccScrubClipboard:
begin
DoPurifyText;
end;
end;
end;
It merely calls one of two functions, DoStraigthenText or DoPurifyText, that scrub the text on the clipboard. Those two methods look pretty much the same – they merely create a TTextScrubber, use it, and then free it. DoStraightenText looks like this:
procedure TStraightTextMainForm.DoStraightenText;
var
TS: TTextScrubber;
begin
TS := TTextScrubber.Create(TextScrubberOptions.ShouldTrim);
try
TS.StraightenTextOnClipboard;
finally
TS.Free;
end;
end;
This method is very simple and to the point — it utilizes the TTextScrubber class to do the work. It’s not always entirely possible, but I try to make as many of my event handlers and methods follow this pattern of merely utilizing the functionality of external classes. Doing so enables a few things:
- It means that functionality is much easier to unit test. Isolated classes with specific functionality make unit testing really easy.
- Functionality is easier to share and reuse. An isolated, decoupled class can easily be moved to new applications as it has few or no dependencies.
- Lean event handlers mean that your user interface isn’t tightly coupled to the work code. This means that adjusting or altering your UI is easier to do, and adjusting and altering the work code doesn’t mean a change in the way the UI works.
So, to sum up – always try to build standalone classes to do the work or your application.



Nick, what kind of functionality do you recommend to put in classes? Or do you try to put everything?
May 5th, 2010 at 12:08 pmFor instance, whould you put things like IntToStr() into classes?
There are people which put literaly everything into classes, so they end up with lots of classes that only have lots untility functions wrapped into class methods.
I agree with Magno, could you please explain the best way for "utility" functions. Every programmer on the planet as a toolkit developed over many years which are shared between projects. Is it best to wrap these in classes or leave as global functions in generic units? To me, some things do not "belong" to a class and it makes no sense to construct/destruct an object just to encapsulate the functionality.
May 5th, 2010 at 1:39 pmGotta agree with Rick. I’ve seen a lot of code, and even some in the Delphi RTL, that tries to put utility functions in classes simply for the sake of having it in a class. Delphi’s Generics implementation even encourages this, since you can’t have a standalone generic function.
But this is really ugly, and anyone who writes "classes" like that ought to be ashamed of themselves.. An object is a collection of variables bound to a set of methods. A set of functions with no shared state is not an object, it’s a collection of functions.
Just because Java and .NET got it wrong and created an ugly object model full of abstraction inversions doesn’t mean Delphi (or Delphi developers) need to follow their bad example.
May 5th, 2010 at 2:08 pmJava and .NET are/were simply too idealistic. They, as with a lot of "new/modern language features" are designed in a rarified intellectual atmosphere, largely devoid of practical considerations. People sit around and talk in highly theoretical and idealistic terms about how code should be written in the "purest" form.
Many modern additions to those language have been artifical attempts to address pragmatic concerns without compromising the "OO purity" of the languages… anonymous methods are very useful when your language doesn’t support first class functions, for example.
Pascal always struck the right balance between pragmatism and helpfulness and it’s depressing to see Embarcadero directing their efforts into polluting the language with concepts from other languages simply to "keep up" whilst true and more pressing needs are neglected.
May 5th, 2010 at 3:05 pm@Joylon: Exactly. OOP is good because it helps you write code that’s easier to understand, and because it provides inheritance and polymorphism. If what you’re doing doesn’t require inheritance and polymorphism, and wouldn’t gain any advantages to code readability from putting it in a class, then OOP is not good for it.
It’s a tool, not a Gospel principle.
May 5th, 2010 at 4:25 pm[...] Nick Hodges » Blog Archive » Delphi Development Pretty Gοοԁ Practices #4 &n… [...]
May 6th, 2010 at 2:23 amI Agree With Nick… in principle. (wink to anyone following the UK elections)…but also Joylon/Mason.
One of the unique strengths of Delphi is that you can still have units with simple routines, and have them globally accessible. Languages that enforce the object model often lead to juggling static/creation order problems and granularity and You-Aint-Gonna-Need-It issues. Until you see a class suggesting itself in your routines, there is no need to overdo it. Classes can become Tamagotchis.
May 6th, 2010 at 2:32 amI couldn’t agree more with you guys! Not everything must be wrapped by a class. This tendency to imitate "mainstream" languages is really worry me. (However, I do understand that mainstream = $ ). Delphi is in the process of becoming less Delphi and more something like D# this days…
May 6th, 2010 at 3:53 amI agree with the others that "not everything must be in a class."
I’m curious what many of you think about the records in IOUtils. They’re basically collections of static functions/procedures put into a record basically to act as a namespace. Worthwhile, or should that unit have been split into IOUtils.Directory, IOUtils.Path, and IOUtils.File?
May 6th, 2010 at 5:26 amI agree with a lot in this post except the use of the word "always".
I think the biggest take away should be the comment about OnClick programming. It doesn’t matter so much if you put non-UI code in classes or methods as long as it’s not in your form events.
May 6th, 2010 at 5:46 amI agree with all of you (Nick included). In order to understand what Nick really thinks about utility methods you only have to look as far as his NixUtils.pas included in his project. Certainly utility methods are fine outside of classes but when you have a class that is supposed to exhibit some behavior it is good form to encapsulate that behavior within methods of the class. Some of the utility functions the class needs can be located outside the class however it is not a good idea to make the class to heavily dependent on other classes in order to complete its intended behavior.
Thanks for the articles Nick I am reading them all intently.
May 6th, 2010 at 9:10 amI agree with Nick opition too, because i moving in a similiar diretection. If possible solving programming problems in classes and small things in functions or procedures. By doing so in the beginning it is bit time consuming - brinning everything in "class style", but then i can easly use objects of this classes in multiple programms without getting a headache breaking code anywhere.
So i want to go on with this type ob progrmming, but how i can use classes, functions and procedures, like "NixUtils.pas"
May 6th, 2010 at 11:23 pm[...] Normally, I keep this file in a separate directory. [...] together with Subversion? SVN:External is option, but you can not check out files in a separate directory but you can only get a copy in a (sub)project path!
In the end you have copys of the same file in every project and have to merge everthing somehow, if you have to do a change even if it is in proper "OOP Sytle".
If you want to always use classes, you are much better of dropping Delphi and switching to Java or C#.
One of the great strengths of Delphi is that the programmer has a choice to use classes where they help and skip them where they don’t.
May 7th, 2010 at 4:19 amHi, you have provided a detailed and nice information on how to proceed with delphi development
May 11th, 2010 at 9:08 pmSlightly OT, but Nick, can you reconsider the template of your site. Light-ish text on a dark basckground is hard to read.
May 12th, 2010 at 12:31 pmDelphi allows nested functions/procedures. A nice and helpfull feature.
I think everybody has seen functions with more than 3 nested functions/procedures like this:
function CalculateSomething(arg1:integer;arg2:string):string;
function AddSomething;
begin …. end;
// more nested functions/procedures here
…
var
…
begin
…
end;
In my opinion this is a **very strong** indicator that you should refactor this code to a class.
June 9th, 2010 at 2:14 pmSo look out for nested functions and change the litte monsters to a class.
sx2008 –
I agree. That is good advice.
Nick
June 9th, 2010 at 2:56 pmI personally prefer putting utility methods into a static class, for Nicks’s reasons and also -
1) Decreases namespace pullution - Code insight list is shorter when you have less global methods
2) Compatability with Delphi Prism, where everything is a class (excluding Prism’s global namespace hack)
3) Elegance - I find TFile.Exists(FileName) nicer than FileExists(FileName).
But as others have said the ability to have global procedures and static classes is a strength of Delphi.
June 9th, 2010 at 8:31 pm