I've always found the world of espionage intriguing. I'd never actually want to be a spy, mind you. In fact, I'm really bad at lying, and I can't keep a secret. And I'm pretty sure those are prerequisites to get into spy school.
One of the simplest techniques that spies use to communicate intelligence is called a dead drop. In a dead drop, one spy leaves some item in an agreed-upon location, generally somewhere out in public where anyone could find it, but nobody would likely notice it.
Back to the Programming World
In dynamic languages with a global scope, such as JavaScript and ColdFusion, I've noticed a pattern that looks just like those old spy dead drops. Here's an example of what I'm talking about:
Here we have two components -- an Authentication System and a Profile Editor. When the Authentication System authenticates a user, it writes the User ID to a global scope. When the user gets around to editing his profile, the Profile Editor component needs the User ID, so it picks it up where the Authentication System left it -- in the global scope.
What's wrong with that?
I've found a number of problems with using dead drop variables.
- It obfuscates the dependency. Profile Editor depends on the User ID, but pulling it out of a global scope makes the dependency much less obvious than if the UserID were passed into the Profile Editor via a constructor or method argument. For example, if you wanted to reuse the Profile Editor class in another application, you'd have to remember to set the same global there.
- There's no guarantee that it's going to be there, or be what you expect. Any piece of code in the app can write to it. (Same problem that the spies might have with a dead drop -- the enemy could intercept it and replace it with bad intel!)
- Unit testing the Profile Editor would be awkward because you'd have to set the global before exercising the Profile Editor's methods. It's much cleaner to just pass in the User ID.
How about static languages?
Languages like Java and C# aren't insulated from this type of pattern, either. Maps and Dictionaries provide a means to store an object using a key, such as a string. Because it's a dynamic collection (i.e., the keys aren't defined statically -- you can change them out at runtime), it's possible to use Maps for dead drops. Make that Map a public static member of some class, and you've basically re-created the ability for a global dead drop variable.
Don't get me wrong -- I love me some Maps and Dictionaries, and I like dynamic languages. I've simply learned that they can be abused. The more obvious the dependencies are, the happier we all are when it's time to refactor!
No comments:
Post a Comment