I Promise this was a bad idea

Promises are being added to everything. Browser API’s, the latest cool frameworks and libraries, browsers, and soon, maybe even node core.

In theory, I’m all for it. In theory, if we had a clean, simple way to describe asynchronous interactions, it’d be a great idea. In reality, Promises fall short of the mark, and their relationship with async-await is one for concern.

In theory…

The best parts of JavaScript have been the result of goat tracks, a path beaten by thorough usage. Promises started getting used in some form of anger in libraries like jQuery, and in the cases for which they were being used, they pretty much did everything developers needed. Want to load a file and then parse it? Easy. Want to load a file, then load a few files based on the first? No problem. Throw an error? Cool, just show an alert(). For trivial use cases, Promises look great.

But there are downsides that make promises not very pleasant to use.

Bother.

They catch thrown errors and handle them the same way as rejections. This is a massive pain if you want your server to crash when you’ve made a coding mistake, as you have to try and detect ‘good’ errors, like 404s to external services, or DB lookup misses, from ‘bad’ errors like “TypeError: 555t5tt55555555 is not a function” – something that occurs frequently when you own cats. There is discussion around modifying how try-catch works in JavaScript to work around this issue, but that should be a massive red-flag in its own right.

Promises also don’t interop with existing API’s nicely, you have to write boilerplate to interact with the normal ‘error, result’ pattern.

Promises run eagerly. By its self this isn’t an issue, there are cases where this is good, but often, lazily requesting asynchronous dependencies is preferable. Creating a lazy dependency graph also allows for easier debugging and description.

What then?

There is nothing special about Promises, they were just big first. There are many alternatives that do a better job. righto and pull-streams do everything Promises do, with fewer pitfalls. Righto interacts with err-backs, and promises, with no boilerplate, won’t catch thrown errors, and can even print a trace that shows the dependency graph for a flow, and which exact task rejected.

debug

But Mah Async-Await!

The biggest issue with not using Promises that get’s raised is that they are functionally required for async-await, but they aren’t. There is nothing specific about promises that makes them necessary for async-await to work; any async task wrapper could be used just as well. Async-await supporting Promises exclusively is a conflation of concerns.

If async-await was more generic, it would be possible to use it with a wide array of third party libraries that expose the right API. pull-streams, righto my-cool-lib could ALL be used with async-await.

GOAT TRACKS

This restriction is a major concern for me, as it lays down an iron path that restricts the formation of goat tracks. It enforces the usage of Promises, even though there may be better options out there. It restricts experimentation with alternatives.

I’m personally not a fan of the async-await pattern, as it attempts to hide asynchronicity with synchronous looking code, deterring understanding. If it is going to be used widely, it should be at least given the opportunity to be used in a variety of ways, to see what works best.

I’m anxious of the day we all look back and think “Oh no, that was a huge mistake.”

– Contains opinions.

The frustrations of opensource

I spend a lot of time “re-inventing the wheel”, usually due to being blocked or frustrated by the wheel I’m trying to use.

Frustrations and roadblocks that occur when dealing with opensource software can often get in the way of writing software, and when that’s your job, you can’t just wait a few months for an issue to be resolved.

A great example of how something minor can become a major frustration has been happening for a while now. clone, a nice little lib that lets you pass pretty much anything in, and get a cloned version of it out. I use it in many of my modules, but it has an issue:

https://github.com/pvorb/node-clone/pull/46

clone checks if the input is a Buffer, and if it is, it will clone the buffer. This is required functionality of the module. The issue is, even if you never mention Buffer anywhere else in any of your code, or your dependencies, the fact that clone *can* deal with Buffer, means browserify *will* include it.

Programmatically, this  is fine, but the browserify Buffer implementation is reasonably large (40kB!), and adds a significant weight to any browserify bundle that contains it.

I realised that trying to obscure Buffer from browserify wasn’t going to cut it, and decided that a better solution would be to solve this in browserify.

The actual problem

The root of the issue is that browserify should NOT add Buffer on clone’s behalf. Clone does NOT need Buffer unless some OTHER module is using it.

I opened an issue in browserify explaining the issue, and suggesting a flag be added to solve the issue:

https://github.com/substack/node-browserify/issues/1228

The solution proposed involved adding a field to the “browserify” object in a modules package.json, that would tell browserify what builtins this module uses, but should not be bundled because of it.

The discussion finally petered out with basically “That sounds hard”. I had a dig through browserify, looking to add this myself. I was able to figure  out that it was actaully going to be insert-module-globals that needed some work, but it didn’t have access to the package.json, so the option would need to be passed, and the code was so unreadable that I eventually just gave up.

The TL;DR:

some modules, like clone need Buffer to create Buffers, but only if another module passes it in.

  • if no other module in the bundle references Buffer, clone does not need it, so it should be omitted.
  • if another module in the bundle references Buffer, clone may need it, and it will be available, because the other module will have caused it to be added.
  • Browserify needs a way to be told when a module shouldn’t cause a builtin to be bundled, just like peerDependencies.

 

Make stylus more nodey

Today I wanted to break some stylus files out into their own module, and I wanted to be able to require a stylus module in the same way I would require a node module.

I tryed:

npm i my-styles-module

And then:

@require my my-styles-module

Which of course didn’t work, but there is a way.

As explained here, you can tell stylus other directories to look in for imports and requires, if it can’t find it in its working directory.

I’m using gulp to build my stylus, so all that was required was to add:

...
.pipe(stylus({
include: ['../node_modules']
})
...

And now stylus works just like node.

How to check if something is an array.

Every once in a while, I see someone talking about how to check if a thing is an array. I’ve been through a few stages of how to write an array detection utility myself.

Stage 1; “instanceof is the best!”

I’ll just check if object instanceof Array! Woohoo!

And then I came across this: http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

Huh, arrays from other frames are not instances of the Array constructor in this frame. I guess that makes sense, since it isn’t an instance of this frames Array.

Stage 2; “instanceof is the worst!”

Righto, guess I’ll use the solution provided.

One problem:

The suggested solution relies on checking a string that gets spit out from Object.prototype.toString.call().

That’s great, except for this:

Object.prototype.toString.call(Array.prototype);
// -> [object Array]

Cool so now your array detection function will detect Array.prototype as an array, which it isn’t.

http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4

Shudup spec, Array.prototype isn’t an array, that would be fucking stupid. Anyway Array.prototype.instanceof Array returns false, as you would expect, because it literally isn’t an instance of Array. If you make your own constructor, you wouldn’t expect it’s prototype to be an instance of it, would you?

Really, if you’re checking that something is a thing based on some random string you pulled from a function on a different constructor… you’ve gotta expect problems.

Stage 3; “Array-detecting libraries are stupid”.

There is a huge amount of noise on the internet around this topic, and it is all noise. You will never make a perfect one-size-fits-all .isArray, Even Array.isArray() won’t work for array-like objects that people intend to be used in place of arrays. In the end, to quote greenday…

It doesn’t even matter.

Think about what you are actually trying to check for. If you have an API that takes an array, just use instanceof Array. Who cares if it doesn’t work across frames? Thats a rare case, and if you need to talk across frames, you will probably know that you’re doing it; Convert the array to a local instance before you give it to your API. Sure it won’t work with that Hipster new library that gives you SuperArrays, but that isn’t important, because the new hotness will come and go. Your library should support JavaScript.

Don’t be afraid to use instanceof, for arrays or any other object. It is an extremely robust way of ensuring an object will look and behave how you expect. It isn’t perfect, but it’s how JavaScript was meant to be used.

The takeaway:

  • instanceof Array is NOT harmful.
  • array detection libraries are stupid, think about what you actually need to check, and check for that.

Samsung Series 9 Touchpad Fixes

Simply put, Samsung software is shit. The touch pad hardware is excellent, and even the drivers for it are great, but the software that ships to configure it is extremely limited.

Have you ever wished you could do crazy things like 3-finger-touch right click? Or maybe use the touch-pad while pressing keys? Probably not right? That all sounds WAYYY too hard and crazy for a user, or at least that’s what Samsung thinks.

Luckily you can change pretty much everything, the Elan driver is really feature-rich and configurable, if you know what to do.

So, to convert your touch-pad from usable to awesome:

1. Open regedit

  • windows+r
  • type ‘regedit’, press enter, 
  • Accept the prompt

2. Go to the honey pot of touchpad settings

  • HKEY_CURRENT_USER
  • Software
  • Elantech
  • Smartpad

3. CHANGE ALL THE THINGS!

Want three finger right-click?

  • change Tap_Three_Finger to 1

Want two finger middle-click?

  • change Tap_Two_Finger to 2

(You can obviously swap 2 finger and 3 finger by swapping their values if you’re weird)

Want to be able to use the touch-pad while typing?

  • Change DisableWhenType_Enable to 0

Just got windows 8.1 and lost the ability to have normal scrolling?

  • Change SC_Reverse_Enable to 0

As you can see there’s a whole ton of settings that can be tweaked. I’m yet to play with everything I’ll want to tweak.

 

Gedi, an absurdly powerful model API

logo

Firstly, what’s gedi?

git: https://github.com/gaffa-tape/gedi
npm: https://npmjs.org/package/gedi

Gedi is model API wrapper. It Allows you to get and set, and remove to/from an object, and bind to changes that occur due to sets/removes.

Simple usage:

    // Set up the models data
    var model = new Gedi({
        thing: 2,
        lifeforms:{
            dogs:[
                {
                    name: "scruffy",
                    age:8
                },
                {
                    name: "spot",
                    age:4
                }
            ],
            users:[
                {
                    name: "bob",
                    age: 20
                },
                {
                    name: "john",
                    age:45
                }
            ]
        }
    });

    // get
    model.get('[thing]'); // --> 2

    // set
    model.set('[thing]', 5);

    // get after set
    model.get('[thing]'); // --> 5

    // bind to [thing]
    model.bind('[thing]', function(event){
        // this callback is called when [thing] changes.
        // event.getValue() returns the value of [thing]
    });
    

You can throw a parent path on the end of get/set/etc.. to make all bindings relative to it.

    model.get('[dogs]'); // --> undefined

    model.get('[lifeforms/dogs]'); // --> Array of dogs.

    // here, [dogs] will be relative to [lifeforms]
    model.get('[dogs]', '[lifeforms]'); // --> Array of dogs.
    

Why square braces?

Because gedi is more powerfull than just an object watcher.

you can pull data out via expressions…

    model.get('(last [lifeforms/dogs]).name'); // --> "spot"
    

And even bind callbacks to expressions…

    model.bind('(last [lifeforms/dogs]).name', function(event){
        // this callback is called when [lifeforms/dogs] changes.
        // event.getValue() returns the value of (last [lifeforms/dogs]).name
    });
    

However there was one thing I’d always thought would be awesome, and i’ve recently made some pretty big changes to how gedi works under the covers to allow.

    // Set the last item in [lifeforms/dogs] to a different dog
    model.set('(last [lifeforms/dogs])', {name: "ellie", age: 2});
    

Gedi can now keep track of paths throughout the execution of an expression, and perform useful opperations using the resulting path.

This is pretty exciting to me, expecially for how it can be used in gaffa.

You can also perform opperations on the result of a filter/map/slice/concat/etc.. eg.

(fyi, the syntax for an anonymous function in gedi is {param1 param2 paramN functionBody})

remove all items in an array that match an expression.

    model.remove('(filter [dogs] {dog (> dog.age 7)})', '[lifeforms]');
    

set properties on all items across multiple arrays that match an expression. (TO RIDICULOUS, AND BEYOND!)

    model.set('(map (filter (concat [dogs] [users]) {item (> item.age 5)}) {item item.label})', 'old!', '[lifeforms]');
    

And of course, any changes made using expressions cause model events to fire at the right paths.

How to do cross-domain async iFrame POST’s the easy/robust way

iFrames, Everyone loves them.

Haha! OK seriously now.

Every seasoned web developer has come up against the need to POST data asynchronously  to a different domain that does not accept cross-domain headers, and the usual solution is an iFrame to post into.

The code is usually something like this:

var myForm = crel('form', {'class':'braintreeForm', method : 'post', target:'myDodgyIframe'});
var myFrame = crel('iframe', {name:'myDodgyIframe'});

And then some code to make this disgusting pile of crap work:

var firstLoad;

myFrame.addEventListener('load', function(event){
    // the load event that gets fired on insertion
    if(!firstLoad){
        firstLoad = true;
        return;
    }

    var result;

    // the actual load event, probably.
    try{
        result = JSON.parse(event.target.contentDocument.documentElement.textContent);
    }catch(jsonError){
        //handle the error somehow
    }

    // use result if it parsed well.
});

An issue that you may encounter is that, if you are inserting the iFrame into the DOM arbitrarily, and not necessarily submitting it, the load event triggers every time it is inserted, not just once.

A solution to this came to me today:

myFrame.addEventListener('load', function(event){
    if(event.target.contentWindow.location.toString() === 'about:blank'){
        // ignorable load, return.
        return;
    }

    // useful load, use.
    var result;

    // the actual load event, probably.
    try{
        result = JSON.parse(event.target.contentDocument.documentElement.textContent);
    }catch(jsonError){
        //handle the error somehow
    }

    // use result if it parsed well.
    
    //cleanup
    event.target.contentWindow.location = 'about:blank';
});

This ignores any useless load events the frame might fire, without dodgy statefull ignore-the-first-load code.