A 'Shield' is a phrase in a program that lets you protect some change decision behind it. There are all sorts of shields in programming - that's what programming for robustness is all about, which is why Shield is a pattern that gets invented over and over in different forms. DontDistinguishBetweenClassesAndInterfaces
is the latest example. Other examples include subroutines, classes, patterns, frameworks, and the fact that in Eiffel and Self an attribute access reads the same as a function call.
All the discussion here makes me wonder if ShieldPattern is really a MetaPattern - a PatternAboutPatterns, since so many of the patterns seem to fit
The point of the Shield pattern is that you write something in one place, and you are permitted to change your mind about the implementation without changing the reference.
In the cases I have found so far, a Shield takes the form of an interface definition. I think that is because programming is behavioral.
If there were a pattern whose title takes the form of advice, it would be SmallestShield
(I don't really care for patterns whose title takes the form of advice, these days; I am experimenting with naming them for their end result). SmallestShield
says you will do well for your program if you use the smallest possible shield at any moment. Shields are, from smaller to larger:
- function name (put Eiffel/Self attributes here also)
- class name (put interface vs class name here also)
- Bridge pattern
- framework name
I guess that I or we finally have enough data to write up Shield as an official pattern (I have been teaching it for several years, but never thought to write it up before seeing this new use).
Can you explain SmallestShield
a bit more? Is it a combination of ShieldPattern
I've recently found myself using big Shields - that is, abstract base classes or interfaces when there is only one implementation behind them. I'm not sure you can convince me this is a bad idea :-)
Isn't this just modularity done right; that is, for information hiding? How is Shield different from what DavidParnas
wrote in his famous paper OnDecomposingSystems
? I'm certainly not complaining about the idea, which is very important, but why give it a new name?
Okay, so this either is not as obvious as I thought, or else it is really trivial and I just haven't seen it yet. Modularity has to do with splitting a program into modules, as in files or classes or something... creating an interface to a module is one form of shield. The fact that in Eiffel an attribute access is "object.value" and a function is "object.value" is a careful part of the language design and can't be explained by modularity. Nonetheless, it is a shield.
There are different size shields, with different costs for maintenance and different protections. DavidParnas
' paper does not talk about the different shields, their costs and values. He more or less picks one size shield, the ambiguous thing called a module. In those days it might have meant a file within a C program. With some stretching you can read it to mean class, or really stretch it to mean framework. I don't think his 'module' can be stretched to cover Java's interfaces. I listed six shields above.
The first time I talked about protecting design decisions behind an interface, I got a classroom full of designs containing interfaces to interfaces to interfaces to interfaces, and nothing carrying out the function. That's when I learned there is possibly too much of a good thing. So I started caring about the weight of a shield.
So let me ask you a question -
Q1. when is it sufficient to use a function or method, and when must you create a class (for example, DaveHarris
's abstract base class, above)?
Q2. When would you use the double interface provided by Bridge or Facade instead of just the single interface provided by a class?
(If you know of a prior name that carries this discussion, please let me know so I can start translating my slides to use it.)
Dave, I am guessing you have found over time that when you didn't program an abstract base class, you got bitten a number of times having to create substitutable peer classes, and so ended up breaking your class into an ABC with subclasses. If that hasn't been the case, I can't really imagine why you bother with an ABC and look forward to telling about it. I further guess you count on the fact of the C++ compiler compiling out the overhead of the ABC, and if there were a real performance penalty for using one, you'd rethink your habit.
Regarding Java, I guessed a while back that there would evolve two schools of programming, those who create interface-class pairs as a matter of habit and those who create interfaces when their class needs the protection. I have been seeing that evolution on Wiki here. (I think I am too lazy to make it a matter of habit, and will probably join the latter school, but I haven't fully decided yet).
Probably the topic Dave is picking up is, What is the penalty for using a heavier shield?
I guess I'm a bit dull this afternoon. Probably that chicken sandwich. How is Shield different from Encapsulation? I thought that was the property of an object that hid implementation while publishing interface?
Well, maybe I'm the dull one. Help me out. Answer a couple questions:
Q3. What exactly does a Java interface encapsulate? (Makes me wonder, Java has interfaces, Smalltalk doesn't - does that make Smalltalk less encapsulated than Java?)
Q4. In PrematureGeneralization
there is talk against making abstract base classes too early. What is the problem? (it sounds like that is "just encapsulation")
Q5. Is there such a thing as too much encapsulation?
Q6. What exactly does the syntax of Eiffel encapsulate?
What I learn from this conversation so far is that Shield is used in a sentence differently than Encapsulation. You say, Let's put a Shield here! You don't say, Let's put an encapsulation here!
I also learn that there are degrees of encapsulation, or what I call strengths of shields. And there is a cost to this (see PrematureGeneralization
I also learn that you are being very polite and blaming your chicken sandwich for my silly questions, but you are not answering my questions. So I now wait for someone's attempt to answer the questions, to learn whose lunch was too heavy.
The gist of PrematureGeneralization
is that one doesn't know how to reuse
until it has been successfully used
and that time spent building elegant class hierarchies before it has been proven that they're needed is time that could be more profitably spent elsewhere.
It's not a critique of encapsulation per se.
Q3. What exactly does a Java interface encapsulate? (Makes me wonder, Java has interfaces, Smalltalk doesn't - does that make Smalltalk less encapsulated than Java?)
I think a Java interface doesn't encapsulate anything. It records, in a separate document, a language for talking to a certain (abstract) kind of object.
The object (any conforming class you might provide) encapsulates everything
about how that particular class implements the interface.
Interface = specification, class = implementation? Could that be it?
I'm ready to assert a couple of things, and one is that doing things differently is a stable part of humanity, ergo programmers also - - with the direct consequence that I hesitate to write a pattern called SmallestShield
. (Now time me and see how many months it takes before I write it anyway.)
Under the same circumstances, some people will say Turn Left, others will say Turn Right, others will say Think Before You Program, others will say Program Before You Think, some will say SmallestShield
, some will say Middle Sized Shield, some will say, Use Accessors, some will say Avoid Accessors, some will say Abstract Base Class First, some will say Concrete Classes Until Forced, and on the list goes, to include process and measurement and ...
The next thing I am willing to assert is that the design shield, or ShieldPattern
gets reinvented in every part of software technology. It is core to our industry. RonJeffries
suggested that SQL is designed as a shield - similarly, high level languages are, also. And Ron's answer to Q3 above helps me think that not every design shield takes the form of encapsulation - encapsulation is the shield that matches the module-centric portion of our technology.
A nice illustration of ShieldPattern
thinking is the fact that both C++ and Eiffel allow the programmer to expose an object's state variable to the programming public. In C++, the syntax for accessing a variable is different than for accessing a function. In Eiffel, quite deliberately, they are the same - this is the shield. A programmer can create a class using a public variable, perhaps erroneously or perhaps for prototyping, and then change it over time to a function, *without the client ever having to change the accessing code*. In C++, on the other hand, the change is a major change, and all clients must be rewritten and recompiled.
Where do I go with this? Well I might write SmallestShield
just to expose the arguments (start measuring in hours instead of months!). I teach design, and one of the things I am interested in is this business about HeavierShields?
. Why not use Bridge everywhere? You know the answer - too much complexity for the benefit given (p.32 of the PatternLanguagesOfProgramDesign
-3 book, RalphJohnson
, "Type Object" contains a lovely example of TruthInAdvertising?
: "The disadvantages of the Type Object pattern are: Design complexity..."). In other words, great shield but heavy - make sure you have a problem needing this weight of shield. DaveHarris
likes ABCs, editing them doesn't bother him. RonJeffries
converted from that to creating them only on demand. Beside raw individual preference, how do you teach someone to develop a sense of feel for the heaviness factor of a shield?
I agree that shields have a cost (and we're not usually talking about machine efficiency here - incidentally, I'm using Java, not C++). I don't always
use ABCs. On this recent occasion I wanted to separate in my mind those parts of the interface which were fundamental, from those which were incidental. As it happened, I found that I needed an alternative implementation within the week, but that was a surprise. As the ExtremeProgramming
people say, it wouldn't have been hard to refactor retrospectively.
Maybe my shield was the "smallest possible" under the circumstances. It strikes me as a rather vague criteria. A smaller one (that is, no ABC) would not have been "possible" because it would not have expressed what I wanted to express.
I feel a lot of these things are really forces, not patterns. We have here a drive against premature generalization. There are opposing drives for necessary generalization. A pattern is needed to bring these forces into dynamic balance. "SmallestShield
" is not a pattern, it's a vacuous restatement of the problem, leaving the real problem (how small is that?) untouched.
I used to think I was pretty smart, but I'm just not getting this. Please see BridgePatternIsJustGoodFactoring
. -- RonJeffries
A parable might help:
Once upon a time, there was a vegetarian tribe in the Amazon called the Expees. A Catholic missionary arrived in their village one day. Curious, the Expees decided to listen to him, and asked him questions about his religion. During this discussion, the missionary revealed that, if they converted to Catholicism, the Expees could not eat meat on Fridays.
Ronj, War Chief of the Expees, nodded slowly and said, "We already abstain from meat on Fridays. But what's special about Fridays? I'm just not getting this."
Whereupon a wide-eyed child of the tribe piped up: "Yuck! He means Catholics do
eat meat the other six days!"
Deciphering the parable:
* eating meat --> putting in something you don't need right now
* vegetarianism --> following YouArentGonnaNeedIt
* Expees --> [isn't this heavy-handed enough already?]
Here is a crack at finding out what is essential about the ShieldPattern
, please tell me if I'm mangling this in any way, but I from what I've read it seems like a very general thing.
A shield is any construct which changes less rapidly than what it protects. In a sense, abstractions can be shields because they are often assumed to change less rapidly (being partial descriptions) than what could be fully described. In this sense, a base class is a shield for a derived class, and an interface is a shield for a anything that implements it. In addition, an operation signature is a shield for inline code.
I would suppose that we could see SystemsAsLivingThings
and consider the shields in the system to be the harder parts (endoskeleton).
I'll suggest another direction to take ShieldPattern
. I think it needs to be a bunch of more specific patterns.
One of everybody's favorite patterns is LightOnTwoSidesOfEveryRoom?
. It describes a specific physical arrangement of space to solve a general and abstract problem.
seems to me to be an abstract solution of an abstract problem. "Things change, therefore separate the parts that change from the parts that don't."
One of my rules for a pattern is the Ingenious Fool Rule- to what degree can someone think they are following a pattern and really be missing it altogether. ShieldPattern
leaves entirely too much room for misunderstanding. I have often heard people say the equivalent of "well, that's there because I needed a shield," when they didn't. Shield has a wide field of effect with a large margin for error.
However, there is clearly something in Shield that we all recognize and resonate with. We've all done things that we can express as "shields". Ward's IntentionRevealingSelector
is a shield. Bridge is a shield, as are all the creational DesignPatterns
. The AnalysisPatterns
book has many shields at a business level, like TypeObject
Alexander says "safety" is not a pattern, it is encoded in and emerges from a family of concrete patterns- BannisterHeight?
, and so on. Information hiding and encapsulation are not patterns, they are principles embedded to greater or lesser degree in the things we create and the patterns we use to create them.
Kent, I think you are right. -- AlistairCockburn
Well, I'm not sure I know what you mean by ShieldPattern
, but when I read it here it resonated with a problem I've been thinking about. Consider a large legacy system, written in (say) mostly C, still very alive and being modified,
with newer stuff being done in C++. Now say I want to port that to Java. What's the best approach?
First thought is to wrap the existing structure of modules behind a set of Facade classes. Then the more dynamic modules can be immediately ported, and the more stable ones can be left alone for a while. This is what I think of Shield as being: a wrapper for the PublicInterface
of a module (package).
This is only a small part of the problem, though, because those modules don't just sit there in isolation; they've got to communicate somehow. The way this happens will depend on the system, but at the least there'll be Messages, or Events, or some similar means of communication; also, there will be some type of data or application-object that gets passed around as the various modules perform work on it.
(If the metaphor casts the Facade as a Shield, then these are the Swords and Arrows, I guess. That's probably not a useful characterization.)
These inter-module objects are kind of outside the system; they don't really have a home. Or rather, they have more than one home, and it isn't necessarily clear where they should actually live. I guess it's reasonable to hide their creation behind a Factory method or some similar object-creational method in one of the Facades. But they still need to be public, not hidden, and therefore don't actually fit in with the idea of hiding everything behind a Shield or Facade.
The standard approach, I guess, would create a new module for 'common' interfaces, and put the definition of these objects there. But that idea sure fails to impress me with its elegance; it's what we did in the first place, when writing the original C version. There ought to be more modern ways of dealing with it.
What's a good way of dealing with this kind of stuff? There's a need for the travelling objects to be able to mutate into new states; there's likely a class hierarchy defining the types of the objects; there's also a set of rules defining the allowable transformations that can be applied along the way; it's necessary that any given module have access to the information it needs in order to determine if an operation is legal, and if so how to apply it. This begins to sound like a pretty large bundle of information that must be available to all modules, and that therefore all modules depend on.
So there's a pressure to do some kind of State pattern, and encode the allowable transformations and operations in the objects.
There's also the pressure to maintain some consistency with the legacy system;
I can't immediately rework the whole thing to handle a new strategy.
uhhh, geez, I started out talking about the ShieldPattern
; it looks like I got a bit distracted there. :-) Anyway: is this the kind of problem ShieldPattern
is intended to deal with? And, am I missing something obvious that deals with the travelling-objects problem I'm trying to describe?
Are we discovering various shields over in ComponentDesignPatterns
? We have different things like ContextIndependence
, and InterfaceDiscovery
. Would some of the above add to these, and can all of them be thought of as ShieldPattern
I always thought of ShieldPattern
as one of the highest-level patterns a person can learn - if they don't get it, then a lot of good software engineering just doesn't make sense to them. A lot of patterns are ShieldPattern
s, but at the same time I don't think that that is the only
category that they belong in. As Ralph and Kent point out way up at the top, the ShieldPattern
is the patternizing of a principle that good software engineers have known about and used for years (which, by the way, is what makes it such a good pattern). IMHO I think we should reference it, and mention the connection other patterns have to it, but I don't feel a need to make it a "foundation pattern" of the CBD language.
I think Kent named the trouble. It is an abstract solution to an abstract problem. It is a pattern in the sense that various good people have settled on it at various times in various technologies, and it is difficult to get immediate value out of because it is abstract. I'll just let the abstractness of it suffer until someone gets a better handle on it.
Where I am going with my thoughts about shields in general is to try to assess the cost of a shield. More shielding often means greater cost in cognitive load or performance. So it is not simply a pattern that says "do this". The counterforces, or overdose effects, are noticeable and are to be accounted for. The Truth In Advertising for a shield, indeed, any pattern or recommendation, ought to include its costs. (are you it doing with the ComponentDesignPatterns
?) -- AlistairCockburn
Doing cost? - sort of. In some places we've addressed cost, but what you're describing is somewhat deeper. As Kyle says, we should fully embrace since some of them can be classified that way, but not explicitly give it a home among the other MiniPatternLanguage?
s. I think components in their nature are all about shielding. They can make it easier for you to eventually strike the right balance between forces associated with too much and too little shielding. Conceptual chunking, or as said above, an abstract solution to an abstract problem. -- PhilipEskelin
I think that is a hopeful (wishful?) approach. I don't think components are so much about shielding as they are about development cost. I don't buy a component to protect the right of the implementer to change the implementation (gack! rather the opposite!) but mostly because I can buy it and stick it into the system cheaper. If the implementer changes the implementation, I am likely to get hurt. Also, components are more likely to be big than small (small components I would develop myself) - hence would drift toward fat interfaces encapsulating lots of stuff. The Truth in Advertising, cost, counterforce, or overdose business provides a) a chance for me or you, the author, to stare at our stuff and better detect its true placement in the scheme of things, as opposed to our initial optimistic blushful wish; b) a way for the reader to assess the engineering tradeoff of using the idea (as opposed to, say, using it and then cursing you for not mentioning the downside). -- AlistairCockburn
A shield should be big enough to cover all the functionality required by clients who are not also creators.
Creators can have a reference to the implementation, so nothing is shielded from them.
If they hand the shielded object to others, the shield should be big enough for the purposes of those others.
The cost of the shield is how much effort it takes to change all the implementations if the shield is changed.
I can see two rules here:
* if the only client is the creator, you don't need a shield
* if there is only one implementation, you don't need a shield
The above is also found at SmallestShield.
The cost of the shield is how much effort it takes to change all the implementations if the shield is changed.
That's one useful measure (let's call it "ShieldChangeCost?
") of how good a given instance of Shield is: If my Shield (e.g. interface) changes, how much do I have to change what's behind it (e.g. implementations).
For example, if I have a Tool interface, and later want to add disabled/enabled behavior, how large will the ShieldChangeCost?
be? In this case, not very large: if I have a single AbstractBaseClass
that implements the interface (what Swing would call an Adapter), I should be able to add setEnabled()/getEnabled() there and there alone.
But Alistair is talking about something much broader when he asks about "cost". He's trying to answer this question:
What things about a given Shield would make me
not want to use it?
A partial answer, then, is: the Shield is rigid (has a ShieldChangeCost?
), and can be hard to change; don't put at Shield at a place in the design that is likely to change.
But you should also consider:
* ShieldInstallationCost?: how much do you have to change the existing code to put the Shield in?
* ShieldPerformanceCost?: does this Shield make the system slower or more memory-intensive?
* ShieldCognitiveCost?: does this Shield make the system more confusing for people to understand?
* ShieldMaintenanceCost?: how much harder does this Shield make it to change the system? (This should always be negative!)
As for Interfaces and AbstractBaseClass
es (ABCs): I can't see a situation where you wouldn't want to use them together. Any time you have an interface, you presumably have a couple of classes that share some abstract behavior (e.g. draw(), addListener(), for UI components). There will always be some implementation of that behavior that they both have, as well. So refactor it into an AbstractBaseClass
that implements the Interface, and have the concrete classes subclass from it.
The other direction: say you're adding an AbstractBaseClass
. Clearly, it implements some Interface. Why not put that explicitly into the program right now? The cost is virtually zero: a tiny bit more typing to create the Interface code; you'd be changing concrete class references to ABC references anyway, so changing them to Interface references instead is free.
And the benefit is that if, later, you want to add something that has all the abstract behavior of your AbstractBaseClass
, but none of the implementation, you can just directly implement Interface; you don't have to touch any of the calling code, and you don't have to convert it from using AbstractBaseClass
to using Interface.
The only objection I can think of is the ShieldCognitiveCost?
; but that seems very small to me. Explaining it to a teammate would go something like this: "Well, you have an interface, and you also have this adapter that you can subclass so you don't have to reimplement all the basic parts of the implementation. Just like in Swing."
Good reply. I wouldn't underestimate the ShieldCognitiveCost?
, though. I have seen beginners given the ShieldPattern
put so many things behind so many interfaces (protecting so many potential design changes) that I couldn't find where the function
was being performed. Huge cognitive cost. As far as I'm concerned, one of the things that sank Taligent was too many itty bitty classes and too high associated cognitive costs - no one could learn how to use the system. -- AlistairCockburn
Yes, but that was a symptom, not the disease. One way to keep shields from being too heavy is to have a group of people work with them every day. It is hard to get an abstraction right, but if a group of people work with it and keep trying to get it better, they will usually complain about bad abstractions and make sure that the abstractions are good enough. Taligent had no users, hence nobody to complain about bad design. Well, I'm sure that some people complained about it, but most people were too busy building their own part of the system to worry about someone else's. Frameworks without users are never any good. -- RalphJohnson
Alistair: I think your problem wasn't with the cognitive cost of each
shield, but with the cumulative
cognitive cost of all
the shields. Note that I didn't say "total" cost: costs of adding things to a system aren't necessarily just a function of the thing being added. You can't just say, "Well, if we add five shields, our cognitive cost will increase by 5 MilliEinstein
s." It depends a lot on what the rest of the system is like, and whether the shield is actually used.
I think if each shield were really pulling its weight, the system would have been easier to understand. Using a structure provides the reader with a concrete example of why it's useful, thus decreasing
the associated CognitiveCost?
, usually by enough to offset the cost of the client code itself.
The important thing here, I think, is that some of the shields were added, increasing the CognitiveCost?
of the system, without actually conferring any benefit. If we want to assimilate this to your concept of SmallestShield
, I guess we'd say (some of) the instances of Shield could have been replaced with a smaller possible instance: no shield.
(This also illuminates a good meaning for "possible", to wit,:"possible while still gaining the needed benefit". In the case of unused shields, the benefit is ipso facto nothing, which means just plain leaving them out would still gain the (nonexistent) benefit.)
is not dollars-and-sense accounting; get used to looking at costs marginally, and mocking things up to estimate them. Also look squarely at what the marginal benefits are, and whether they outweigh the costs. And if you can't estimate the cost of something, it's a risk, and it may be that YouArentGonnaNeedIt
I was surprised nobody has used the word indirection
here (unless I missed it). Is seems to be that much of what the above discussions on the ShieldPattern
seem to be talking about is the often-quoted observation that just about every problem can be solved by adding another level of indirection. -- AnthonyLauder
Except for the other part often stuck on that quote, "...except for too many levels of indirection.", which seems to fit Alistair's concerns about "heaviness". -- AnAspirant
Outside of this page, is "shield" a common term used to describe this pattern/principle? I found the term confusing, and didn't understand what it meant until I read the page a few times. To me, the term "shield" implies protection against unwanted access, or an intentional attack, not protection against the consequences of a decision. I think a better term would be something like "Commitment Minimization" (but shorter), or maybe "hedge". -- KrisJohnson
"Hedge" might be a good choice; beyond the physical referent of a barrier, it also is used in the context of minimizing risk, as in "hedging your bets". Large companies frequently use all sorts of financial instruments to hedge their losses in case of bad weather or high oil prices or whatever else.
"Hedge" doesn't work for me. You hedge against bad consequences of action A by taking the very different and in some ways opposite action B as well, like buying a certain stock and, at the same time, put options on the same stock. That's IMHO too specific an idea to match what ShieldPattern describes.
If we need a different term, I would like to humbly suggest DesignHinge. -- FalkBruegmann
Hmmm, a shield is surely just a concrete, immutable point of extensibility no? And has two things going for it... it means a piece can articulate and hence adapt without having to be a limp bendy mess in order to adapt.
Or looking at it another way, a shield is a node on a graph... you have choices you can make at a node as to which edge you can take.
I personally am not sure that "shield" is a good choice of term, and think it focuses to much on defensive programming...which isn't to say such focus is bad, simply that it doesn't convey what the pattern offers, and instead focuses on what it avoids.
Either that or I'm missing the point entirely.
The key difference is (from the top of the page), "the fact that in Eiffel and Self an attribute access reads the same as a function call." In Eiffel, one writes, "myClass.service" . . . and cannot, from that, tell if 'service' is a data element being directly referenced, or a zero-argument function call. . . . and Bertrand Meyer did that on purpose, explicitly to allow the author of myClass to change his/her mind about that very choice.
If this fits what you mean by "extensibility", they the answer to your question is "yes." Otherwise it is "often but not always."
I find two values in metaphoric word "shield". The first is that behind a shield (force field, barrier) one can do things hidden and protected from the world in "front". In software, that is, change one's implementation. The second is that shields get heavier as they get bigger, so there is a cost as well as a benefit. That aspect doesn't get enough discussion to suit my taste. -- AlistairCockburn
What do you mean by 'heavier'? An interface doesn't seem too heavy to me, albeit redundant. Compared to, say, an abstract class hierarchy.
Indeed - exactly as you write, "heavier" is relative. An interface is relatively heavy or not, depending on what you're comparing it to. A framework's API is heavier than a class's interface is heavier than a function's interface is heavier than a variable name is heavier than a constant. The heavier, the more flexible - but that comes at a cost, of efficiency and cognitive complexity. -- AlistairCockburn
Well, I'm new here, but on a read of GoF and a few of the patterns linked here, I'm of the opinion that ShieldPattern
is far too broad. This strikes me rather as making a "vehicle" pattern, and then asserting simplest possible vehicle is desirable, then laying down considerations - fuel efficiency, speed, comfort, prestige, cost - in order to select between RollerBlades
, a Lear Jet, a Rolls Royce, a submarine, and the various points inbetween. Whereas it is a useful abstraction, this "vehicle," good for describing utility or intent, is it a useful pattern? When designing something whose intent is to make a device to transport people or commodities from point(s) to point(s), does first considering it as a vehicle and then applying the commonalities of a vehicle grant you any insight? Before you point out that the luxury of the Rolls Royce was explicitly imitated by Lear, do remember that we're also talking about surf boards, skateboards, military interceptor fighters, and roller coasters. There aren't many particularly useful general observations.
What I believe is happening here is that an attempt is being made to codify a more general thing than a pattern as a pattern. The metapattern suggestion that Pete Hardie made at the outset of the discussion seemed about dead-on to me at first, but I've now changed my mind. When you create a new sporting transport device - let's say you're the guy that invented windsurfing - your approach is to identify something you'd like to achieve, generally by analogy with a similar act in an alternate medium. "Surfing is fun," one imagines he might have said, "but it would be more fun in the air instead of the ocean. Or at least it's worth a try." At that point, there are a bunch of considerations about where you get the velocity, the lift, how you prevent frequent neck breakery, et cetera. However, the observation that it's a vehicle, and that therefore that you will cover distance, that it will take a nonzero amount of time to complete transit, that it involves equipment external to the body, and so on - don't do you a hell of a lot of good. Also, this points out again that some things which seem to be superficially related to a pattern in fact are not, but are common only to the more obvious applications of the pattern - my Rolls Royce example again shows some promise when you make the observation that most windsurfers don't need a wetbar or corinthian leather seating en route.
Thing is, if you've got a sarcastic enough mind, it's very easy to create useless (or so seeming) patterns. For example, it could be suggested that the bulk of programming languages would do well to be expressible with symbols available on a keyboard, which has few counterexamples unless you have experience with digraphs and trigraphs, or APL. I'd argue that that's the case with the vehicle pattern - it is indeed a pattern, but it's so broad and so vague that it doesn't provide any useful rules or observations as a result. By the time you've identified the need for it you've already gotten all of its ramifications by earlier mechanisms. You never say "oh wow, you know, I should make this thing a vehicle." I also think that that's the case with ShieldPattern
. It's overly broad. Some patterns really do descend from one another (I often get into arguments over my belief that singleton is effectively an ancestor of flyweight.) Yes, if you wanted to categorize the various ways to protect outside code from change, then you could refer to them all as shields. Does it buy you any utility? Maybe in discussion. GoF notes that one of the uses of patterns is to provide a common vocabulary for discussion. In that way, maybe Shield Pattern could be useful.
But do I think it's a good pattern? I don't, really. I don't see what it gains us. I'm from the C++ mindset, and I prefer minimalism. I believe that the smallest interface which can represent a set of tasks without introducing extra complexity (yay vagueness) is best. I haven't been here long enough to know whether that's considered common wisdom (or a common misconception,) but it's the platform I choose to argue from. I tend to see patterns as a tool for displaying complex and interlocked concepts in a semiconcrete and usable fashion, mostly as a way to exchange experience. I also see them as a "heavy tool." I wouldn't use a pattern to describe functions, or variables - the concepts are too simple to warrant such attention. There is a point of diminishing returns here; if you used a pattern to try to explain variables to a novice, it would be harmful; it'd take forever, it'd be distracting, it'd be confusing. I see explanations much in the same way that I see interfaces; the shortest that effectively communicates the whole is best. In more classic terms, "Brevity is the essence of wit."
GoF presents three categories of pattern. Would it be appropriate to make a pattern called "Creational Pattern?" Well, sort of. There are commonalities to creational patterns. They have a similar aim, they have a similar goal, they share some common methods by necessity - they need to pass a created object out, they need to provide mechanisms (be they internal or external) to specify what will be created, et cetera. I would argue that yes, there is a pattern called "Creational Pattern," and that it's a dead pattern. By the time you've realized that what you have on your hands is a creational pattern, there's nothing that Creational Pattern can teach you, no way in which it can advise you, no alternatives or considerations it can provide you.
To use a phrase without defining it is the ev1l. A dead pattern is a pattern which satisfies the requirements for a pattern but whose existence cannot provide any useful information for judgement. Therefore, a dead pattern requires that you've identified all of its considerations in order to identify it in action. Therefore, I feel satisfied generalizing it into the rule of thumb that a dead pattern is simply a uselessly overbroad pattern.
What does the Shield Pattern advise? The shield pattern advises that you protect something changeable behind something less changeable - Michael Feather's description seems elegant. Then, a few people have made mention that they'd like it kept minimal given circumstances. I had thought that nominal. I fail to see any other real insight here; people are observing that one or another pattern descend from this, that encapsulation is a formalization of this observation, that some languages provide literal implementations of this at the language level (privacy and scoping, namespaces, interfaces, and various things which haven't been mentioned - aspects, call by contract, call by name, or less literal things.) In many ways, you might observe that the C++ standard serves as a shield of sorts. It specifies what will be available, how long it will take, what its complexity and resource requirements are allowed to be, how limitations are to be reported, and so on. I would suggest that it is in fact an incredibly strict shield for the domain it covers; much unlike Alastair Cockburn, I don't feel that switching implementations should ever hurt the user. I am (usually) not hurt moving my code between compilers; because I understand the C++ Standard shield well, I know what things I may rely on as requirements, and the things which are important to me, such as algorithmic complexity, are maintained. I would argue that if switching implementations is dangerous, you have an insufficient shield.
All that aside, I can't really see any utility to the ShieldPattern
. I think of patterns essentially solely as a teaching mechanism, and teaching is what I've paid the most attention to of all my hobbies over the last few years. I've come to the conclusion that the most difficult thing to find is a Really Good Example (tm). People tend to choose their examples according to what they know, or what's germane to the topic at hand, rather than for their expressive ability. To give a concrete example, in a recent class I taught (no, I'm not the professor who has my name) I gave chess as a midterm assignment. I feel it's a good learning experience - the rules are absolutely concrete and have no vagueness, the game isn't overly complex, there are some simple easy approaches that give results which aren't outwardly disappointing (by comparison, Go is astonishingly difficult,) has a few interesting caveats but not many (there is a situation in which more than one piece may move, there are times at which you can have more of one piece type than you start with, but never the king or a pawn, et cetera. By contrast, checkers is not a good example; it's too simple to be interesting. Similarly, Magic: the Gathering and other collectable card games, or Knihtmare Chess, or contract bridge, or baccarat, or dungeons and dragons would all make bad examples; though they're fun games, they're far too complex and plagued with far too many special cases to make a good teaching mechanism. To that end, patterns must also be carefully chosen. There are, to my sarcastic eyes, a forest of bad patterns to be identified. Dead patterns are only one class of bad pattern, and they're a particularly dangerous one - they're easy to mistake, they cause the consideration of dangerously different substitutions, they don't provide any utility, they absorb useful brain time.
I'm not very confident that a ShieldPattern
is a dead pattern. I'm really just trying to establish the notion of dead patterns, to get criticism, and maybe in the path to identify the problem with Shield. Still, that's my diagnosis. I do think it is a pattern. I just don't see what it's good for.
To me, Shielding is about abstraction entirely. One of the tenets of OOP that caught my attention from the beginning was that abstraction could go all the way up to the point that source-code could almost read like the abstract description of that very same code.
For instance (pun intended), if you are programming some special math or engineering routine that deals with vector algebra, the abstract description for adding two vectors into a third vector would look like:
w = u + v
Assuming that operator overloading could be considered some type of shielding, my (client) code could read like this:
Vector w, u, v;
. . .
. . .
. . .
w = u + v;
Lets see another example. Lets suppose that for some reason, I have some class that holds XML data on a certain attribute (field). To have a design as abstract as it can get, I would like that the look and feel of the get accessor in my (client) code to be just like the set accessor. So far, so good.
But, what if I want to make sure that my set accessor only accepts well-formed XML expressions?
Well, once again, shielding comes to the rescue. I could hide the (well-formed) validation routine within the innards of my set accessor code. If some XML expression doesn't look good enough, my routine could throw the right kind of exception, and, again, abstraction wins.
Does it sound like I am too C# oriented?
Well, you can only use as much shielding as the language of choice supports. I just chose a language versant enough in shielding to make the point.
IMHO, Shielding is a very elegant technique, capable of producing beautiful abstraction. I do not see it as a classic DesignPattern
, since you cant apply a unique collaboration of classes to express it.
A language has syntactic (notation), semantic (meaning) and pragmatic (usage) rules. To me, Shielding could fall within the pragmatic rules of a PatternLanguage
. It is a way of using abstraction. You could attain abstraction through other means.
Maybe the problem resides in the fact that we are using a loose definition of what a pattern is. When you are on a phase of WorkInProgress
, looseness is an asset.
Sufficiency is king. We have some illustrious participants in this conversation that form part of the original AgileAlliance
group, so I am using Sufficiency in that very sense of the word. But at some point in time, you need to shift to precision for closure.
In relation to a previous discussion on Interfaces, an Interface (as a separate software construct) has nothing to do with encapsulation, at least that is the way I see it.
The public interface of any given component establishes the language that must be used by client code to obtain services from that component.
The public interface of any component coded on any OOP language is the one software construct responsible for encapsulation. Components developed in Smalltalk have a public interface just like any component developed in any other OOP language, so Smalltalk is on an equal standing with any other OOP language when it comes to encapsulation.
Since the public interface of a component establishes the language used by client code to obtain services from the component, there is a de facto contract between the client code and that component.
An Interface as a separate software construct serves as the realization of that contract. The capability of any OOP language to have a specific software construct to realize contracts is a very powerful tool.
Why is this a good thing? Any other component that implements the same contract (Interface) becomes interchangeable with the original component, at least for the services that relate to that given contract. Language designers can create additional productivity tools around the Interface construct (like Interface inheritance).
In this respect, Smalltalk is not on an equal standing with other OOP languages, like C# or Java.
What Alistair and John's comments suggest to me is that ShieldPattern
is of the some order as CreationPattern?
. I never write code and think "I need a CreationPattern?
here." Such patterns are useful for understanding the goals and tradeoffs of programming; they allow us to group a number of related patterns together and say "these are similar." It's a cognitive aid for learning about the art of programming, not for implementation of a specific problem.