I'm sure you've seen code like this:
/**
* Loads HTML files from given URL-s.
* @param {String[]} urls The URL-s to load.
* @param {Object[]} alreadyLoaded For internal use only!
*/
function loadPages(urls, alreadyLoaded) {
alreadyLoaded = alreadyLoaded || [];
if (urls.length == 0) return alreadyLoaded;
var url = urls.pop();
var page = load(url);
alreadyLoaded.push(page);
return loadPages(urls, alreadyLoaded);
}
What I'd like to draw your attention to, is this second parameter - the parameter that you're not supposed to use, a private parameter.
Everybody knows about private methods - they are well respected citisens of OOP landscape. Similarly we have private instance variables. All good means of encapsulation.
But what about private parameters? Nobody talks about such things, but in my day-to-day work I see them popping up every now and then in various different codebases. How should I treat them. Are they a pattern or an anti-pattern?
We can definitely rewrite the above example, so that it doesn't use any private variables:
/**
* Loads HTML files from given URL-s.
* @param {String[]} urls The URL-s to load.
*/
function loadPages(urls) {
return loadPagesRecursive(urls, []);
}
function loadPagesRecursive(urls, alreadyLoaded) {
if (urls.length == 0) return alreadyLoaded;
var url = urls.pop();
var page = load(url);
alreadyLoaded.push(page);
return loadPagesRecursive(urls, alreadyLoaded);
}
Now the public loadPages
acts as a simpler interface in front of a
private and more complex loadPagesRecursive
method. We have
effectively transformed our private parameter into a private method.
That's actually how we would have written it in the first place in a language like Java that doesn't directly support optional parameters - forcing you to define a separate method when you need a different number of parameters.
Of course Java is mainly a great example of a very verbose language. Optional parameters are such a useful language feature, nobody ever argues against them. And private parameters sure are a very convenient thing too - the first code examples was shorter, there was just one method, no need to think up a name for our silly helper method.
But what kind of convenience are we talking about in here? It's the convenience of the library author - his convenience of writing less code.
With optional parameters, there's also the convenience of a library user - without optional parameters he would need to pass in the default values by himself, introducing lots of hairy duplication.
But private parameters provide absolutely no help for the user. Quite the contrary - he is forced to learn about this parameter that he is forbidden from using. Basically the private parameter is an implementation detail which we are revealing to the user.
Also, because not a single language that I know of supports the concept of private parameters, one has to rely on documentation to convey the meaning of these parameters being private. In the simplest case one could just skip documenting these parameters - when the documentation says there's just two parameters (although the method actually takes three) the user never needs to bother his head with our secret third parameter. But that logic breaks down as soon as somebody looks at the source code - then he will see the undocumented third parameters and wonder wether this was just forgotten to be documented.
At that point one might want to turn to his documentation tool for help on documenting these private paramters, but at this point I will say: STOP.
I feel like we've seen enough evidence already to conclude that private parameters are an anti-pattern. And JSDuck, which is an opinionated little duck, simply won't support such a nasty thing.
Instead JSDuck will provide you a warning when he sees you haven't documented all your parameters, to help in keeping your code and comments in sync.
Quack.
Kirjutatud 15. veebruaril 2013. Kommentaarid (5009)
Every once in a while I get asked why doesn't JSDuck support a
certain character in the names of various entities. The character is
usually some punctuation like the dot (.
) or dash (-
). The names
in question are the names of classes and class members (methods,
properties, events, etc).
So why doesn't JSDuck allow you to document a class named
My.Special-Class
or method named my+method
? Why doesn't the
freaking tool just get out of the way and allow you to do what you
want? Supporting just one more character can't be so hard - why not
simply do it?
Three reasons:
The problem here is that JavaScript, unlike most other object-oriented languages, doesn't require the names of object properties and methods to be proper identifier names. Objects are just hash tables - any string is a valid key, and therefore also a valid method/property name.
So when I implement support for dash and dot, the next user comes along and asks why doesn't JSDuck support colon? Then the third one comes and asks to support spaces. Soon we're talking about supporting the whole Unicode including Egyptian hieroglyphs.
We need to practice some moderation. Thankfully JavaScript itself gives us some guidance on this: although we can name methods with any imaginable string, like so:
window["My class"]["ho-ho-hoo!"]();
only when using proper identifier names will they be convenient to use:
MyClass.hoHoHoo();
So, by only allowing proper identifier names, JSDuck is asking you to take the sensible route.
The main thing here is that JSDuck is opinionated. It wants you to write your code in a certain way. And if you want to do things differently it's going to be painful. In that case you might have chosen the wrong tool.
In addition to the above, supporting the whole range of possible characters is far from easy to implement. Even adding support for just one more punctuation character is a considerable amount of work.
There's a lot of convenience that derives from the assumption that class and member names are always proper identifier names. It allows us to use the same names in URL-s, HTML id-s and other generated code without a need to do additional escaping.
For example when supporting dot in member names, we need to ensure we encode the dot somehow when using the name inside HTML id attribute, because the following is not valid:
<p id="ho.ho.hoo">
JSDuck is already doing this kind of escaping to support the $
character which is valid in JavaScript identifiers but invalid as HTML
id. So an identifier $foo
becomes S-foo
in HTML. Not a prettiest
solution, but it's a mandatory thing for a JavaScript documentation
tool to support.
But supporting all kinds of other characters is just complicating the code base while helping only a rary minority of users who want to do some weird things.
Finally, using non-identifier names for classes and members is just
asking for trouble. Even if JSDuck implements a support for it, you
will soon face some other tool which also chokes on your
unconventional code. Sure, you can have a slash (/
) in your class
names, but good luck with your filesystem if you want to save it into
a file with the same name.
But in the end there's nothing to stop you. Go ahead, write the craziest JavaScript possible. I do encourage you. It's the land of the wild and brave. But it's not the land of great tooling support.
Photo credits: Het Leven, 1927, Copying Egyptian hieroglyphs; Lewis W. Hine, 1920, Woman with Machine; George Jackman, Ten lords a' leaping.
Kirjutatud 17. septembril 2012. Püsilink.
Ruby provides a nice builtin module that lets easily turn your class into a singleton:
require 'singleton'
class MyClass
include Singleton
def say
puts "Hello"
end
end
MyClass.instance.say # ---> "hello"
But I'm not quite happy with that. I'm not talking about the general
wide overuse of the singleton pattern. What bothers me, is that the
fact of MyClass
being a singleton is just an implementation detail
and it shouldn't change how I'm interfacing with this class.
For example, I might decide that instead of having a singleton I'd just like to have a class with static methods:
class MyClass
def self.say
puts "Hello"
end
end
Nice. But now I have to go through all of my code and replace all the
uses of MyClass.instance.say
with MyClass.say
.
That's not good. The rest of my code shouldn't care if MyClass
is
implemented as a singleton or not.
Additionally I like my lines short. For me MyClass.say
looks much
cleaner and simpler to understand than MyClass.instance.say
.
Maybe in Java and friends that's the best you can do, but in Ruby there sure is some better way.
So, after fiddling around a bit with some ruby meta-programming, I came up with my own improved version of the Singleton module:
require 'singleton'
module MySingleton
def self.included(base)
base.class_eval do
# Include the builtin Singleton module
include ::Singleton
# Redirect calls from MyClass.method to MyClass.instance.method
def self.method_missing(meth, *args, &block)
self.instance.send(meth, *args, &block)
end
end
end
end
You use it just like the standard Singleton:
require 'my_singleton'
class MyClass
include MySingleton
def say
puts "Hello"
end
end
With the important difference of how you call the methods on your instance:
MyClass.say # ---> "hello"
Oh, and if you need it, you can still use the old way of calling out the singleton. This will still work:
MyClass.instance.say # ---> "hello"
I have always found static methods in ruby to be too painful to
define. You need to prefix all the static methods with self.
:
class MyClass
def self.foo
end
def self.bar
end
def self.baz
end
end
And then, when you decide to change them all into instance methods,
you'll need to remove all the self.
prefixes. Not good at all.
But with our new Singleton implementation we can just turn this same class into a singleton and make it behave as a class with static methods:
class MyClass
include MySingleton
def foo
end
def bar
end
def baz
end
end
And when you change your mind, you just remove that one line and you've got a nice instantiable class again.
A win-win I would say.
Kirjutatud 10. septembril 2012. Püsilink.
RSS, RSS kommentaarid, XHTML, CSS, AA