My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Friday, March 16, 2012

On Obtrusive Polyfills

I'll try to make the point short and simple, starting with the tl;dr version: if you create a polyfill and during features detection you realize this cannot work, drop it and let other libs deal with it.

Broken Object.defineProperty

This is just one case really annoying. Bear in mind I am not talking about "making perfect polyfills", this is almost impossible most of the case, I am talking about broken runtime even if you did not really do anything that special.
It was the case of Object.defineProperty shimmed through es5-shim code ... this library is good but that method, as many others, are simply broken.
I was trying to add a setter/getter in IE < 9 and shit happened, more specifically a thrown exception happened ... the repository itself explains that this method and others should fail silently ... so it's OK for the developer to know about it and avoid trusting these methods ...

This Is Not OK

If I check if Object.defineProperty is there and this is all I need to know, I don't want to double check which version of IE, if IE, it is, neither I want to check anything extra.
I simply trust the fact the browser, or some library, fixed the problem for me and I can use this method as it is.

if ("defineProperty" in Object) {
// I want to use it, wouldn't check for it otherwise

A broken shim doesn't make anyone life easy while that simple condition in my code could redirect my logic in a completely different approach.
Since in IE < 9 that method simply does not make sense to exist, then it should not exist, period.

Remove The Broken Shim

I hope, and expect, that es5-guys will simply delete Object.defineProperty afterward, once realized it's not usable.
I would not compromise entirely theObject.create but again, if defineProperty() is not there there is no bloody point on using create() too.
Let other libraries deal with the fact this is missing in their own way since every single case could be different: someone simply need to inherit another object, someone else might need the method as it should be.

As Summary

A shim/polyfill that works 90% is OK, specially if the API is covered 100% and even if behind the scene things are not identical, but a polyfill that let a piece of code think everything is fine and the whole app breaks who knows when and why should not be exposed at all or, if you really want to bring similar functionality, it should be exposed prefixed, i.e. Object.$defineProperty() so that the rest of the code is aware that such method exists but it's limited.

Thanks for understanding


John-David said...

I agree. Shims that can't be functionally reproduced shouldn't be added to the native objects and instead should be separated into smaller utility/private methods like a simple `beget()` instead of `Object.create`. Like you I'm not so much a stickler for the method.length or similar non-functional parts of shims as few devs check/rely on them.

Raynos said...

What if I want to use defineProperty but not use getter/setters.

The current es5-shim is useful if your code sticks to the shimmable subset of ES5:

and besides, why do you care. Either defineProperty is shimmed and you choose to shim it, or it's not and it's not shimmed.

There is zero need for your library/code to be compliant with the es5 shim

Andrea Giammarchi said...

Raynos ... defineProperty without getters/setters and, as shim, without enumerable, writable, and configurable is the most pointless thing you can do to set a property.

The shim is breaking my code and this is bad so your point is .... which one, exactly?