Amazon.com Widgets Okay, So When Should You Call Create?

Okay, So When Should You Call Create?

By Nick at January 30, 2012 23:27
Filed Under: Delphi, Software Development

Okay, I want you all to notice that in my previous post about the use of Create,  I was pretty careful not to say “Never call Create”. And near the start I said “For the most part”. So let’s be clear – just as I didn’t say “Never ever call FreeAndNil”, I’m not saying “Never call Create”.  And while I am at it, I didn’t say “Use interfaces everywhere” either.  Those of you who are accusing me of saying so are wrong.  Incorrect. Inaccurate.  You should be ashamed and you should correct yourselves. You should also read more carefully and think more precisely.

Enough about what I didn’t say.  What am I saying?  I’m saying “Architect your code so that you avoid calling Create, because doing so causes problems”.

Problem number one is that your code becomes difficult to test.   This is a fact:  When you call Create – when you create more than just an instance of a specific instance of a specific class – you are tightly coupled to that class and it’s entire dependency graph. (If you don’t know what a dependency graph is, you can find out more here.)  Some classes have huge dependency graphs.  That is, the creation of that class cause a cascading of creation of other classes which can initiate any number of things:  Connections to databases, locking of files, attachment of limited resources like turnstiles or cash registers – who knows what? 

Classes that have dependency graphs are classes that should not be manually created, but instead should be created by a class that can control if and when that class is created.  The creation of such classes should be definable and controllable.  They should be referenced by an abstraction and they should be created in a configurable way.  If you want to test the dependent class, then you can have your system create a mock instead of the real thing.  If you call Create on that class, you can’t do that. 

How should we refer to these types of classes – classes that have dependency graphs of any sort?  Let’s refer to them as “complex classes”.  (I looked for the commonly accepted term here, and couldn’t seem to find one.  I haven’t the slightest doubt that one of you will tell me what the “right” term here is. I’ve seen the term “volatile” used, but I don’t like that because of the keyword volatile that some languages use.) So for the purpose of our discussion, a complex class is one that has a dependency graph; it’s a class that, when created, brings in other external dependencies.  Sometimes those external dependencies are easy to define, and sometimes the dependency graph gets so complex it is hard to know what is happening exactly when that class is instantiated.  For instance, think of TForm.  When you create TForm, holy mackerel – a long, complex host of other things are being allocated – Windows handles, other VCL classes, fonts and this and that and the TKitchenSinkTForm is most definitely a complex class.

But, what about something like TStringListTStringList has, as far as I can tell, no real dependency graph.  Create one of those, and you really aren’t creating a host of external dependencies.  TStringListis basically self contained.  It is a known, limited entity. (Look at it’s constructor and the constructor of TStrings.  It basically doesn’t create anything, so it really can’t have any dependency graph.)  It can be created without worrying that you are going to end up calling some charge-money-every-time-you-use-it web service.  It’s simple, clean, and limited.  It’s not a complex class.  It’s a simple class.

So, to answer the question posed in the title of this post – you can (and should) call Create on what I’m calling simple classes.  Generally, these will be classes defined in the RTL that clearly are stable or simple in that they don’t have dependencies that are non-deterministic, unknown, or complex.  Classes like TStringList, TStringBuilder, TList, the classes in Generics.Collections.pas, and many others are examples of classes that you should feel fine about creating.  These classes are know and proven by virtue of being part of the RTL.  You probably have many similar classes in your own library – classes that you have bathed in unit tests so you know that they are isolated, stable, and simple.  You can determine the complexity of such classes by looking at the constructor of a given class.  (And note: The use or lack of use of Create in those classes indicates whether they are complex or simple.  Hmmm.)

You should feel safe creating such simple classes because you know that you aren’t dragging in the TKitchenSink when you create them.

So that should answer the question, eh?

Comments (38) -

1/31/2012 3:11:37 AM #

C Johnson

Lazy testing like you are suggesting has REAL, actual world consequences.  A system is not fully tested unless all its parts are tested TOGETHER.

Unless, of course, you don't mind mars landers missing the planet entirely, I mean, after all - metric and imperial are just IMPLEMENTATION details.  All the independant systems tested just fine seperately.

Nick, most of the consequences may not be as visual, but given enough exposure to the real world, some of them are likely to be just as expensive and potentially more damaging close to home.  You wouldn't slap cardboard on a car and call it crashworth just because it might be airodynamic.  

The reality is that implementation is EVERYTHING, because the interactions that cause crashes can easily be second and third level relationships.

I can come up with an endless list of cases where if you leave parts out, you open yourself to OBVIOUS points of failure inspite of passing a mockup test.

But if you want to keep giving up ground to refine your argument, I suspect you will eventually hit a specific enough case we can agree on.

C Johnson Canada |

1/31/2012 3:26:19 AM #

Stefan Glienke

You are again missing the point. Did Nick say: Never do integration testing? No, he didn't. He is just pointing out that with certain coding styles you CANNOT test pieces in isolation and ONLY integration testing is left which should always be the second step after testing every possible piece in isolation. Because testing in isolation already may reveal bugs that are harder to find and fix if multiple pieces are working together.

Stefan Glienke Germany |

1/31/2012 10:00:05 AM #

Tapper

Cars are a perfect example of what Nick has been talking about. A well designed system that has common interfaces and its parts can be tested in isolation. All kinds of parts can be interchanged on a car, and the car still works. How can this be? The aftermarket parts manufacturers don't test on every car, they test to an interface. Think of a wheel, you don't attach the lug bolts as part of the wheel hub, you could never replace the bolts. (And testing the bolts would require an entire hub.) But if I want to increase the the durability of my the bolts on my car I can, just by replacing the bolts, not the hub.

Tapper United States |

1/31/2012 11:01:48 AM #

Mason Wheeler

...and somehow, with all those tested parts, we still ended up with the Toyota uncontrolled acceleration debacle.  A good analogy indeed.

Mason Wheeler United States |

1/31/2012 1:02:42 PM #

Nick Hodges

Mason --

Seriously?  What point are you trying to make?  That testing is a waste of time?

Nick Hodges United States |

1/31/2012 3:46:41 PM #

C Johnson

No Nick, his point is that testing mock objects only tests mock objects.  

C Johnson Canada |

1/31/2012 3:55:18 PM #

Nick Hodges

Uh, what?  

Who said anything about "testing mock objects"?

Nick Hodges United States |

2/1/2012 12:11:34 PM #

Mason Wheeler

That unit testing is a waste of time.  Especially on a static, strongly-typed, compiled language, it's cargo-cult programming.

Are you aware of where the idea came from?  It originated with Smalltalk, and its primary benefit was to make up for several of the deficiencies of dynamic languages by manually performing correctness tests that we can get the compiler to do for us.  That's why unit testing has taken off so much with dynamic languages.

When you do it under a strongly-typed language, what you get is a mess.  You end up with your code strongly coupled to a bunch of tests, which is even worse than having it strongly coupled to actual code, because the actual code has real functionality.

Under an enforced unit testing regime, your code is just as "brittle" as it is without it: if you make implementation changes because your requirements have changed or new features are needed, it will break a bunch of tests, and then you have to manually sort out which ones are failing because you broke something and which ones are failing because they're obsolete now.  So what's the net benefit?

As I've said before, there's no better way to reach a bad conclusion than starting from a false premise.  You've always assumed the premise that "unit testing is always good, and coupling is always bad" as a given, an assertion.  I'm calling Assertion Failure on that concept.  Do you have any objective facts?  Is there any hard data to back up your premise?

Mason Wheeler United States |

2/1/2012 12:19:30 PM #

Stefan Glienke

My recommendation - read this:
misko.hevery.com/.../...ting%20Testable%20Code.pdf

And don't come back telling me this guy is talking about Java code and that you cannot compare that to Delphi

Stefan Glienke Germany |

2/1/2012 2:10:20 PM #

Nick Hodges

Mason --

Sorry, but I have to conclude that you don't really understand what I'm talking about at all.  I suppose it is possible I'm just explaining really badly, but since you seemed to have missed the mark so badly, I'm going with the former idea.

When done properly, and as I'm advocating, your code is utterly and completely decoupled from the unit tests.

"I'm calling Assertion Failure on that concept.

Yep, I get where you are coming from.  Good luck with that.

Nick Hodges United States |

2/1/2012 2:15:03 PM #

Mason Wheeler

>When done properly, and as I'm advocating, your code is utterly and completely decoupled from the unit tests.

If by "your code" you mean "individual pieces of code," then yes.  That's not what I'm talking about.  Your *overall project* is very tightly coupled to your unit tests, by the methodology if not necessarily by the compiler.  There's more than one form of coupling.

Mason Wheeler United States |

2/1/2012 2:40:49 PM #

Nick Hodges

Hey, Mason -- if you don't want to unit test your code, that's your call.  I think that's crazy, but to each his own.

Nick Hodges United States |

1/31/2012 1:01:43 PM #

Nick Hodges

Clinton --

Remember that part where I said to read more carefully?  Well, you aren't reading carefully.

"A system is not fully tested unless all its parts are tested TOGETHER."

Does anyone disagree with this? Have I ever said, or even remotely *hinted* that I don't agree?  No, and No.  

Unit testing the basis for testing your *code*.  Integration testing is for testing your system and how it's parts work together.  System testing is for testing the system as a whole.  The latter two are generally the purview of QA.  The former -- unit testing -- is the purview of the developer.  I'm a developer, this is a developer blog.  Hence, I talk about developer things.  

Again, please, read more carefully, think more clearly, and stop making things up.

Nick Hodges United States |

1/31/2012 3:22:22 AM #

Eric

You should probably mention the IMHO "game changer" that Object Pascal has wrt classes and factory: meta-classes ("class of"), and a *working* meta-class model (complete with virtual constructors, virtual class functions, etc.).

What other languages have to clumsy their way around with factories, RTTI-based instantiation, RTTI attributes, and other overly-complex DI schemes can typically be solved more elegantly in Pascal if you use meta-classes (and you get compiler support).

You don't see those approach mentioned much in the Java literature (where your design sources come from), because Java doesn't have that concept, or more precisely, Java has it, but it's tied to RTTI, which means runtime-type checks, and those are bad practice in Java. But with Object Pascal's meta-classes, you can do it with compile-time type checks, so the limitations of Java don't apply.

Eric France |

1/31/2012 3:35:31 AM #

Arnaud Bouchez

This is a very good point.
I'm always impressed by the power of "class of" kind of types, as arguments e.g.
I used some of the "class of" potential in our ORM, to handle class-specific data, and never call "Create" directly, but call T..Class.Create to initialize a proper class as expected. Very powerful. And a good entry point to store some cached RTTI information, which is very useful for an ORM.
AFAIK .Net allows "class of" kind of variables, but I'm not sure it's so powerful than in Delphi. And in all cases, when speaking with .Net people, "class of" is not widely used in their applications. Perhaps for the same reason as Java, or perhaps most architectural .Net patterns come from Java.

Arnaud Bouchez France |

1/31/2012 3:44:07 AM #

Stefan Glienke

Isn't that similar to the before mentioned abstract class? In your case you would have that class of on the abstract class with a virtual constructor (and most certainly also virtual abstract methods). To me "always code against interfaces and not implementation" does not necessarily mean delphi interfaces. It can also be an abstract class. And in that case using class of is just perfect.

Stefan Glienke Germany |

1/31/2012 3:49:49 AM #

Arnaud Bouchez

Exactly. This is our point, I guess. Smile

Arnaud Bouchez France |

1/31/2012 4:02:03 AM #

Stefan Glienke

The only problem with DI in a non GC language is just the freeing (no, I am not saying the evil procedure name here ;) ) of the objects that got constructed by some container or factory. That is why interfaces seem to be the better choice (until you run into the implementation specific problems like circular references and such)

Stefan Glienke Germany |

1/31/2012 5:00:23 AM #

Eric

It leverages abstract classes in a different way, in that there is one additional level of separation as far as construction goes

Where a regular abstract class would have you carry around an instance of that abstract class, a meta-class allows to carry around a non-instantiated service (whatever is offered by the class).

As far as construction goes, you can have:

type TMyMetaClass = class of TMyClass;
...
var meta : TMyMetaClass;
...
meta := whatever function, method, etc. returning meta-class of TMyClass
...
myInstance := meta.CreateIt;

You code will have never made any reference to the class your creating and manipulating. The meta class can be obtained in a wide variety of way, and carried around.
And where I called "CreateIt" to get an instance, I could have called a "GetIt" or whatever, and this could be a constructor, a class function, a class property, etc.

So you can have code that instantiates and manipulates class it has never seen, without ever referencing them. You get the advantages of DI, along with the advantages of strong-typing & compiler support.

Also meta-classes are aware of the class hierarchy (in an abstract fashion), so you can do in one safe step what would have required a framework in another languages (and would have to be safeguarded by runtime checks).

Eric France |

1/31/2012 5:07:53 AM #

Eric

Using a meta-class as a service is where you break away from other languages btw, and enter a near-magical realm: you can do virtual, dynamic, pluggable, DI-able things without instantiating anything.

They mean you only need to instantiate when you really need to (ie. when there is state), and don't have to instantiate some stateless object just to be able to provide an interface f.i.

Eric France |

1/31/2012 7:11:32 AM #

Stefan Glienke

I think you just moved the problem of static dependencies to another level but not addressed the problem. In simple cases, yes you can pass around the class and instantiate it at will. But doesn't that bring back the problem of messing around with controlling the lifetime of these objects? How about more complex scenarios where you have to pass another thing into your object? You will need to carry around all kinds of classes and put them together when needed.

Also it requires virtual methods for everything, otherwise you cannot create mocks for these classes.

Stefan Glienke Germany |

1/31/2012 8:21:52 AM #

Eric

No the static dependency problem is gone: the metaclass can be provided by a plugin, streamed and identified by FindClass(), or even be purely "out of delphi" (when mapping to a scripted implementation f.i.).
The code that uses a metaclass needs not know about the class it manipulates, it doesn't have to appear in the source code, and it may not even have to instantiate the class it's using.

The lifetime problem *when* you instantiate isn't solved, but then in Delphi, there are no good solutions for that (interface-based reference-counting don't support weak references, cycles, graphs, parented trees, doubly-linked lists, etc.), though as long as you're stateless, you don't need to instantiate anything.

When instantiating, I usually just provide Release() virtual class methods, which can in practice map to a refcount, a Free, a pool, or anything else.

Unless you meant something else, the requirement for mockups & virtual methods for everything is a non-issue IMO: it's the same when using regular Delphi classes, and an implicit one when you use interfaces in Delphi (which are VMTs, just with a different syntax).

Eric France |

1/31/2012 8:43:43 AM #

Stefan Glienke

Yes, you just have to remember to make all methods virtual that need to be "mockable" even if you are not overriding them in non test code.

How about the non existence of multiple inheritance? With interfaces its not problem to let my TDog implement ICanBark and ICanEat (stupid example alarm) according to the interface segregation principle (ISP) while without them it is a bit more complicated. I think some people would use callbacks or something like that.

Stefan Glienke Germany |

1/31/2012 9:42:49 AM #

Mason Wheeler

>Problem number one is that your code becomes difficult to test.   This is a fact:  When you call Create – when you create more than just an instance of a specific instance of a specific class – you are tightly coupled to that class and it’s entire dependency graph.
>...
>If you want to test the dependent class, then you can have your system create a mock instead of the real thing.  If you call Create on that class, you can’t do that.  

There is no easier way to reach a bad conclusion than beginning from a false premise.  Delphi can do this trivially if the dependency is in a different unit.  Just set up a new unit with the mock class that you use in your test, or if you want to get really fancy, use Unit Aliases.  Hey! Where'd my huge dependency graph go? Laughing

This stuff has all been discussed before, on blogs that were on DelphiFeeds, so I'm surprised you don't seem to know about them.

Mason Wheeler United States |

1/31/2012 10:08:31 AM #

Stefan Glienke

So you are seriously suggesting to modify the uses clause for unit testing purpose or using conditional compiling?

Because I cannot think about another way of removing the dependency between TMyWidget and TSprocket (i.e. having the Sprocket.pas in the uses of the MyWidget.pas).

Stefan Glienke Germany |

1/31/2012 11:00:29 AM #

Mason Wheeler

No, I'm not seriously suggesting either.  I'm suggesting having your mocks in a different unit with the same name in a different folder.  (Or even a unit with a different name, and using Unit Aliases in the test project.)

Since you don't put your tests in the main project, this won't cause any conflicts, and it neatly avoids the "problems" mentioned here without turning your entire codebase into a messy pile of interfaces.

Mason Wheeler United States |

1/31/2012 1:27:26 PM #

Nick Hodges

Mason --

Forgive me, but it is hard to believe that you are serious about this idea.

Nick Hodges United States |

2/1/2012 12:39:33 AM #

Lachlan Gemmell

I don't share your incredulity at Mason's suggestions. Obviously his suggestions don't help you make your code more truly reusable, but if your goal is just to make your code more easily unit testable they're quite valid in my view.

There's not much difference between a folder of identically named units containing class based mock objects and a folder of differently named units containing interface based mock objects. Either way you have to include the units in your DUnit project. Both methods are transparent and easily understandable by those who come after you.

Using the Unit Aliases feature to get the compiler to replace one unit with another is a bit hackier but as long as the practice doesn't make it's way into your actual application build processes I don't really have a problem with it as a testing technique.

And of course interface based mocks are an excellent way of unit testing also, with the added advantage of producing more easily reusable code to boot.

Lachlan Gemmell Australia |

2/1/2012 12:04:54 PM #

Mason Wheeler

*shrug* It's just a logical extension of the basic concept.  It's no sillier than having unit tests everywhere in the first place.

Mason Wheeler United States |

2/1/2012 12:22:00 PM #

Stefan Glienke

Have fun maintaining such test code when developers are adding new units to the uses clause breaking several design principles.

Stefan Glienke Germany |

2/1/2012 2:30:47 AM #

Stefan Glienke

This sounds more like a workaround to make legacy code unit testable but not like a way to do it right from the start when you design your architecture.

Stefan Glienke Germany |

2/1/2012 2:05:45 PM #

Nick Hodges

I need to get a +1 feature for my comment engine.  Wink

Nick Hodges United States |

1/31/2012 11:06:44 AM #

Alexandre Machado

Hi Nick. I'm really liking your FreeAndNil and use of interfaces articles. I use interfaces (not always) and I'm not purist about FreeAndNil usage (or not). Well, let's think about an practical example:

I have two classes, let's say TClassA and TClassB. TClassA holds a connection to some resource (DB/WebService/AppServer/Whatever). TClassB needs this connection to work properly. Let's say I will follow your guidelines, using interfaces and factories. So I will have:
TClassA, implementing interface IClassA; TClassB, implementing interface IClassB; and two class factories TClassAFactory and TClassBFactory, right?

But, TClassBFactory needs to know the connection resource from TClassA, because it will have to initialize TClassB, so TClassBFactory has to know not only IClassB, but IClassA also, right?

In the end, I will have 6 different units (I don't like to use the same unit for completely different classes/interfaces). The units containing TClassBFactory and TClassB both reference units containing IClassB and IClassA.
Well... after all this work, don't you think that you get a much more complicated model? Do you think that it pays? Or would you use a different approach?

Regards

Alexandre Machado Brazil |

1/31/2012 1:29:17 PM #

Nick Hodges

Alexandre --

I myself don't mind having a lot of units if my code is decoupled and well designed.

If a given class has a dependency, then you can pass that dependency in the class constructor.  

You don't need a Factory for every class if you leverage a Dependency Injection Framework.

Nick Hodges United States |

1/31/2012 4:08:44 PM #

Captain Jake

One thing that reading these kinds of discussions on Delphi blogs and newsgroups and fora tells me is that the Delphi user base is old. It reminds me of the old C holdouts that rebelled against C++ and OO (like Linus Torvalds) for all the wrong reasons.

People, the world evolves and sometimes even improves. In this case it has improved greatly. Reference counted interfaces are superior. Period. I don't want to hear any neanderthallic claptrap to the contrary, save it for someone more gullible than I.

Delphi was one of the first (if not the first) languages to offer reference counted interfaces as part of the language, way back in Delphi 3, yet already by then, habits were established that apparently now still enthrall much of the Delphi faithful and keep them from using superior language features. It is truly sad to behold.

Hopefully, Firemonkey will come into it's own and bring in a much-needed flood of young blood, devs who understand the superiority of reference-counted interfaces. Otherwise, "Delphi" will still be associated with the state of the art of languages in 1995 when it doesn't need to be.

Captain Jake United States |

1/31/2012 6:06:21 PM #

Nick Hodges

Point well made, Jake.

The resistance I get to these development patterns and ideas is both sad and surprising.

It boggles my mind that someone would argue against a coding methodology that makes unit testing easy.  

Nick Hodges United States |

2/1/2012 1:15:44 AM #

Lachlan Gemmell

I see two main arguments against increased interface usage in Delphi. Neither is a reason never to use interfaces, but they are issues to stop and think about before jumping straight into writing interface based code.

The first is that despite being one of the first to introduce interfaces their implementation hasn't improved much over the years and they do have a few quirks. There's been some recent work done around casting but as a few people have mentioned the circular reference issue is a biggie that in other languages is handled automatically by the GC.

The second is the lack of interface usage within the VCL application model and the style of application the VCL encourages. For example if I want to abstract my database access behind an interface I have to sacrifice the advantages Delphi gives me at designtime via it's concrete references to TDataSets and instead settle for a more C# or Java like approach of manually setting up my database links. You may argue that this is a better way and you may be right, but it's not the Delphi way and I don't think it's surprising that many Delphi programmers favour the Delphi way moreso than the C# or Java way.

Perhaps the Delphi Spring framework provides ways to mitigate these issues, I don't know, but I'm interested to find out. Maybe it's the missing link that would assist programmers like myself who tend to use interfaces at the periphery but are open to learning these issues can be overcome and potentially make interfaces a larger part of their core toolset.

Keep up the good work Nick.

Lachlan Gemmell Australia |

2/2/2012 9:07:33 AM #

Dag Hovden

Some good stuff in here for Verity Stob's next 'Sons of Khan' column I reckon ...

Dag Hovden Netherlands |

Comments are closed

A Little About Me

Hey, I'm Nick.  I'm interested in Software Development, Leadership, and Basketball.  I'm a big fan of Delphi, but love all cool programming languages.

A Pithy Quote for You

"Just the knowledge that a good book is awaiting one at the end of a long day makes that day happier."    –  Kathleen Norris

Little Buttons and Stuff

Nick Hodges

Create Your Badge
View Nick Hodges's profile on LinkedIn
profile for Nick Hodges on Stack Exchange, a network of free, community-driven Q&A sites
Powered by DiscountASP.net
Join Dropbox

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.

Book Stuff

Earn Free Stuff

Search & Win