Skip to main content
 

Oh, September. You're making me want to put the heating on.

 

Is Ad-Blocking Good For The Web?

6 min read

A slew of thoughts around content-blocking (née ad-blocking). Why now? well Apple.

I've been having those hipster feelings about privacy, – I was into protecting my privacy before Apple told me it was cool – but I realised that it was at worst wrong, and best irrelevant to anything. But it did kick me into action of writing them down.

So: Apple is giving programmatic access to let developers control the loading of images and scripts while the user is using the built in web browser.

The press are going crazy about this, because they have skin in the game: almost all mainstream news outlets on the web are funded by running ads next to the journalism.

Much of the accepted timeline of events draws a straight line from:

  • fewer ads been shown
  • fewer ads been clicked on (and paid for)
  • less money going to individual news sites
  • fewer journalists making their living from journalists
  • less informed population with less diverse set of view points.
  • functional democracy becomes impossible without an informed electorate

I will take it as axiomic that a functional democracy is a necessity.

A tractor

At this point it should be mandatory to disclose my use or not of content-blockers.

I moved from Opera to Firefox in 2003? to take be able to use an ad-blocker. The web is not tolerable without it.

The browser is the user's agent that loads content from the web. How the user configures her agent is up to her.

Anyone insisting that I not use a content-blocker is like telling me how I should eat a Creme Egg.

My employer gets most of its money from 'clients', who make most of their money selling ads and displaying ads.

Apple makes almost nothing from ads, and claims the side of the user, and has a relationship with the user at the exact place ad-blocking would be possible.

iOS9, dubbed by no-one, the ad-pocolypse, brings ad-blocking to Mobile Safari.

However, it has stopped short of implementing an 'ad-blocker', but given app developers access to Safari's content loading pipeline.

So, questions here for Apple Kremlinologists, interesting, but unanswerable:

  • why did Apple do anything to do with content-blocking?
  • why did Apple not do an Apple blessed ad blocker, instead of API access.

My guess, for the record: pro-user-experience reasons & anti-Google & Facebook strategic reasons.

I think the second question is more interesting than the first, but still not that interesting. For the record: a combination of resourcing, legal and app ecosystem reasons.

None of those reasons about Apple are for the benefit of the web.

I'm sure one may look back when it all turned out ok and say that Apple foresaw all this, and that came into the reasoning of doing content-blocking; but I think that's a stretch.

But is it, you know, good for the web? Or better, how will all that content on the web be paid for, if not by ads.

The most important thing in the short term to say about this is this:

  • it is off by default.

The second most important things in the short term is this:

  • the user has to find and install an app from the app store.

Every single tap that the user has to do in order to start using it will see a proportionate drop off in user uptake.

My prediction is that large ad-driven sites will report that content-blocker usage will be perceptibly small to neglible in comparison to the rest of their traffic. In the short term.

So what happens next? Users don't like ads, People who put stuff on the web need to get paid.

Back when napster was new and record companies were claiming a drop in sales because of it, the popular comeback was 'The internet is here to stay, don't fight it. Find new business models to work with it.'

That, and people want things for free, are the only similarities between file-sharing and content-blocking.

The ramifications, the finding of new business models, are still playing out, as the pre-internet content-businesses meet the internet and find that their previous business models don't work or can't work online.

So what future can I see, which is good for the web and better for users than megabytes of ad-tech for bytes of content?

The set of perverse incentives needs to be straightened out so all the goodies pull together.

It is clear that the publisher, who has no desire to manage an ad inventory, has lost control of the code that actually runs on your browser in their page.

For 'publisher' I mean anyone putting your words or images or video or sound or whatever on a webpage. That might be you, but it might be Flickr.

The publisher may have had a few granular switches to throw, but have ceded editorial control of what ads are displayed next to their content.

Publishers, if they're not already, need to demand better tools from their ad-networks and ad-exchanges. They need to start pushing the worst offending ad-networks off their rosters.

@jeffjarvis believes that the publishers should be owning the relationship with their reader or viewer. I agree, and that the first thing they need to do make sure we're only shown ads that are in-keeping with their editorial and/or brand voice.

This all pre-supposes that running ads next to your content /is/ a viable way of running a business on the internet.

Online advertising has just discovered another sets infinite of billboards which can have ads on: video, snapchat, vine. More effective ads, unblockable ads.

The pool of global online advertising spend is not going to grow as fast as the number of billboards: payout for ads are decrease, and will continue to decrease.

There is a bunch more to write about funding of online news (an important subset of news); how Facebook, Apple, Google and Twitter are stripping out the ads for their own News offerings.

There's more to discuss about what news needs from those platforms and the ad-networks themselves, but that'll wait for another post, here or some place else on the web.

 

Addonception: Addons extending addons.

8 min read

Copenhagen airport

I'd like to talk about addons again. This time about extendable addons. This is a natural consequence of go-faster.

I'm going to assume the shape of the manifest is largely like Chrome Extensions and WebExtensions.

Here, I'm proposing two new top-level properties of the manifest.json: extension-points and extenders.

Addons can contribute extenders to extension-points. Addons can consume contributed extenders via extension-points.

Extenders are fragments of the manifest.

The normalized forms of this would be:

{
  "name": "contributing-addon",
  …
  "extenders": {
    "${extension-point-id}": ARRAY_OF_EXTENDER_OBJECTS
  }
  …
}
{
  "name": "host-addon",
  …
  "extension-points": {
    "${extension-point-id}": CONFIG_OBJECT
  }
  …
}

The config object isn't strictly necessary, but may become useful to extension point tooling.

For the sake of Product type readers, the first bit is a clear cut use-case. For the second part, I use a README-driven-development style.

Here's a use case for us to talk about and around.

What

The example here: an addon to parse the content document for micro-formats.

Sidebar for the lay-reader: microformats are specially crafted generic HTML for structured data like addresses or contact details. There is a loose set of standards.

The bulk of the work is done in a microformatting core addon. This can detect and linkify the text, but what to do when the user interacts with it?

Why

We wish to be able to customize the browser based upon territory, or for partnership reasons.

Where the user is taken when she interacts with the microformat is customizable – by default mozilla and its internationalization and partnership choices.

The micro-formats team is part mozilla and part contributor based; they are likely proficient in any language but they already have good implementations of a detector in javascript, and are unlikely to want to start over. They are motivated to see their existing implementations running on iOS and will be able make an addon.

The micro-formats team would like to have a different release cadence to the Firefox iOS team.

The Firefox for iOS team have not the bandwidth to take on a microformat detector in Swift project especially for an addon so ripe for re-use from desktop.

Tapes

User choice

The choices of map, or contact resolver may be ultimately up to the user when they interact with a microformat, but the choices that the user selects from can be provided from several (once competing) places:

  • the very first run defaults. This is provided by the microformats team.
  • the i18n contributors. The most likely useful address finders in one country may be different to the next.
  • the partnership engineering team.

The browser only needs to glue the pieces together.

Concepts. Words.

In the eclipse world, the unit of distibution Firefox calls an addon is a 'plugin'.

In OSGi, it is a 'bundle'.

The other eclipse words would be 'extension' and 'extension point'. How the extensions were joined to the extension points was the job of the registry.

OSGi bundles have 'service provider' and 'service'. There was no explict Service Registry, but it described itself in terms of a 'whiteboad' pattern.

Analogues with Android intents are noted, and differs mainly in granularity and lifecycle control.

I prefer the Eclipse nomenclature simply because its more descriptive.

However, I am aware that other browsers already use 'extension'. Thus, I will now consistently use extender and extension point (or EP).

Back to business

For the rest of this post I'll assume a set of addons:

  • microformat-core
  • microformat-i18n-xx
  • microformat-commercial-xx

How these addons get there we can talk about later on.

The microformat-core addon advertises an extension point for microformat linkifiers. Linkifiers are templates for a given detected object that the core addon can use to send the user to a new tab.

Declaratively, we could define an address resolver like so:

{
  "name": "Open Street Map",
  "template": "http://www.openstreetmap.org/search?query={line1}%2C{line2}%2C{zipcode}%2C{country}"
}

Linkifiers are extenders provided by the i18n-xx and commercial-xx addons, as well as any other addon that the user could install. Importantly microformat-core addon can provide one, as a fallback when all other addons have been uninstalled.

The linkifier extension point is not part of the manifest spec, but for addon review purposes we'd like to be able to declare it in the manifest. But the syntax to declare extension-points and extenders should be in the spec, so more developers can add to the Firefox ecosystem without stepping on each others toes.

For similar review purposes, and convenience for small addon creators, the extenders should be declared in or near the manifest.json file.

{
  "name": "Microformatter"
  …
  "extension-points": {
    "mf-linkifier-address": {
      "selector": "pref"
    },
  },
  "permissions": [
    "extenders"
  ]

Somewhere, in a manifest not far away.

  "extenders": {
    "mf-linkifier-address": {
      "name": "Open Street Map",
      "template": "http://www.openstreetmap.org/search?query={line1}%2C{line2}%2C{zipcode}%2C{country}"
    },
  }
  // no explicit permission is needed to declare extenders in the manifest.
}

The extension point collects all the extenders up from different addons and presents them as a list.

In the microformats-core addon, the extension point is consumed in an event based manner:

function findAddress(detectedObject) {
  var ep = chrome.extenders.get('mf-linkifier-address');
  var linkifiers = ep.all();
  var linkifier = linkifiers[0]; // naïve

  var url = makeURL(linkifier.template, detectedObject);
  return url;
}
// 

It is possible to limit the access to extension points via the manifest.

Thus, we have parts of other addon manifests squirted into an addon that invites it, and the many-to-many relationship is mediated by an addon 'registry'.

Further work

Dinosaurs

Bootstrapping addons

The underlying technology is not particularly difficult: a dictionary of extension-point ids mapping onto a list of extenders, with some events and ordering independence thrown in.

The same objects can be used to implement other parts of the addon manifest interfaces (e.g. content-scripts, background-pages, pageActions).

It starts to become magical when extension points are notified when extenders appear and disappear.

var ep = chrome.extenders.get('firefox.addon-manifests');
ep.onAdd(function (addonManifest) {
  var allExtenders = addonManifest.extenders || {};
  …
  for (extensionPointID in allExtenders) {
      // …
      for (var extender in allExtenders[extensionPointID]) {
        var extender = … // iterating through the manifest
        chrome.extenders.add(extensionPointID, extender);
        // …
      }
  }
});

ep.onRemove(function (manifest) {
  …
  chrome.extenders.remove(extensionPointID, extender);
  …
});

Thus, we have restart-less install.

Developer tools to ease extender

The mf-linkifier-address extension point above declares a "selector".

  var linkifier = ep.choose(); // select based upon a preference page choice.

Swift consumers of extension points

  let ep = registry.get("browserAction")
  let buttonMetadata = ep.choose(); // select based upon a preference page choice.

The integration between javascript and Swift is just nice enough to get things done, but pretty ugly syntax wise.

However, the registry can be kept in Swift or Javascript, and be shared relatively painlessly between Swift consumers of extension points.

Going further, Swift knows enough about the extension point and the contributed extenders that it can generate a preference page for the extension point.

Extenders with js functions

JSContexts can share functions quite comfortably executing functions in the context they were declared in. JSContexts seem to behave almost exactly like a module-pattern module would.

Thus, programatic access to add functions as or part of an extender would be really interesting.

The extender registry provides a simple API to add and remove extenders – simple enough for a manifest parser to do it in an automated way. Providing access through JS may not be advisable for addon-review purposes, so some manifest driven access

Concerns with JS adding extenders

  • Content-scripts access to the registry is needed (WebExtensions needs getManifest()) anyway, but sharing functions across this boundary may be unneccessary or difficult.
  • Contributing addons may expose user-data to other addons.
  • A good fences rule will be needed to ensure one addon doesn't crash another.

Security

  • Addons can only consume the extension-points they declare in their manifest.
  • Addons contribute only the data they want to – extenders do not have access to the extension-points.
  • Extension points starting with 'firefox.' are not accessible from any addon.
  • A policy where multiple addons consume the same extension-point.

Ghetto Gecko Back to our example

So we have an microformats-core addon and a microformats-i18n, microformats-commercial addons.

Now we also have API for home tiles. This would also be a likely candidate for the same pattern.

However, the units of extension are extenders, which are can be distributed as a group in single addon.

  • feature-a
  • feature-b
  • feature-c
  • i18n-xx
  • commercial-xx

The feature addons are shipped with the app.

The locale specific configuration for feature addons can either be distributed from a remote server – and appropriately signed, or distributed with the app and chosen at runtime.

Additional conifg for a, b and c can of course come from other addons the user installs.

This, plus an addon update mechanism gives us great scope to ship code faster, prototype new additions to the spec.

Summary

I've described an extender registry: a fairly simple data structure which can be the enabling technology for addon management and implementation, but also enables a secure and stable extension mechanism for third party addons.

 

Parts needed for Addon infrastructure for Firefox for iOS

10 min read

I've been thinking a lot about addons recently.

This post is exploratory and technical in nature.

Context: I work on the Firefox for iOS team; we have an inkling that Firefox for iOS addons may be a Good Thing™, but have not got anything concrete on our current road map. This particular post is just finding the things that will be hard or impossible and/or what to ask the Webkit developers next time they come to speak to us.

Disclaimer: We may want to adopt the proto-spec that is WebExtensions, supporting some or all of it; we may want to contribute to the spec by adding our own innovations. We may want to ignore the spec altogether. It is too early even for these decisions.

Arches My assumptions on this matter for this post are:

  • We do want to support extensions (otherwise, it's a short conversation, and not go-faster).
  • We are convinced that Apple won't reject the app, or we know what to do if they do.
  • We'd like to be able to follow along with the rest of the Firefox addons ecosystem, for porting reasons.
  • Tradeoffs mean that we can or will never support 100% all platforms Firefox has a presence.

Instead, here I'm going to focus on sketching out the major assumptions that any addons need and the pile of technology that iOS provides.

WebExtensions non-functional requirements start with:

  • Porting add-ons to and from other browsers should be easier.
  • Reviewing add-ons for addons.mozilla.org should be easier.
  • WebExtensions must be compatible with multiprocess Firefox (Electrolysis).
  • Changes to Firefox's internal code should be less likely to break add-ons.
  • WebExtensions should be easier to use than the existing Firefox XPCOM/XUL APIs.

Additionally:

  • Install and uninstall should be done without a restart. The concept of 'restart' doesn't really exist on mobile.
  • Given that it's our stated aim that we want to ship major components as addons, and we may want to extend those major components with other addons, we should allow limited and controlled communication between addons.
  • Addon authors should have a reasonable expectation of secure separation between addons.
  • Speed is always a feature.

Some interesting addons worth thinking about:

  • WhimseyPro
  • µblock Origin
  • PDF.js (it doesn't need to be done, but /could it/).

From an architectural view, my assumptions are:

  • an addon has a manifest.json which declares the components of the addon.
    • html pages loaded in a new tab or popup
    • browser chrome implemented in swift with event listeners in javascript.
    • addon reviewers should have a strong expectation that the addons capabilities is limited to what it declares in manifest.json.
  • an addon can have javascript and css that runs in the content – in the WKWebView
    • it is conditionally run based on the page's location.
    • the js can be run before or after the page is loaded
    • the js can fetch resources from domains specified
  • an addon can have javascript that runs in the background
    • the background can interact with the browser chrome,
  • javascript from the two different contexts can communicate, but by message passing.
  • Wiring javascript to chrome events and access to the addon api is done through the chrome object.
    • the chrome object has api objects added to it, via permissions declared in each addon's manifest.
    • non-persistent background scripts are said to be event scripts.
  • The actual api that developers will use is not being discussed here: just the foundations on which that API will be built.

The pile of bits provided by iOS8 consist of:

  • JSVirtualMachine, which can host multiple JSContext objects, which must all run in the same thread, which doesn't have to be the main thread.
    • Each context has its own global object, but not much else. JSON is provided, but XHR isn't.
    • Objects can be shared between JSContexts in the same JSVirtualMachine, including functions, functions called by functions in the same shared object behave are run in the context they are declared in. Side-effects stay with whichever context the function is declared in. I have not experimented with this twiddling. From a javascript pov, it feels almost exactly like the seperation provided by CommonJS modules.
    • There is a rich API for sharing Swift mutable objects with Javascript, and vice versa. This is upto and including passing function literals back and forth.
  • webView.configuration.userContentController WKUserContentController, WKUserScript, WKScriptMessage and its associated WKScriptMessageHandler.
    • User scripts can be executed each time the content is loaded, before the content or after the document is loaded: there is no sharing of state across reloads.
    • evaluateJavascript: completionHandler: provides a bridge from swift to js.
    • WKScriptMessage and WKScriptMessageHandler provide a bridge from js to swift.
    • WKUserContentController can add WKUserScripts one at a time, but can only remove all scripts at once.
    • Out-the-box, I haven't found a way to allow user-scripts to XHR a domain other than allowed by the server from where the content came. There are workarounds, but none of them are pretty, or cheap. Research and help needed.
  • GCDWebServer. This would be very useful if content scripts could load resources via HTTP, but since we can't mutate the single origin policy of webcontent, it is limited to only loading addon pages into content. If we can, then we could
    • implement chrome.runtime.connect with WebSockets into the GCDWebServer
    • load addon CSS asynchronously by writing script and style tags

Wrong ATM

Our job now is to decide how to make the first list of things out of the second list of things.

Having done a lot of this research I'm pretty convinced that we should run all background and chrome event scripts in a single virtual machine, preferably off the main thread. This would mean all addons run on the same thread, but the extra thread seperation would come at the cost of implementation speed and flexibility.

Since the manifest is meant to be the central auditable glue that ties the addon together, it should almost certainly be parsed in Swift, and the Source of Truth About Addons to be kept there. However, it should be accessible from Javascript, both for WebExtensions spec and to allow us to implement the chrome object in terms of javascript as well as swift. Collectively, the JS and Swift access to the source of truth, I am referring to as the registry.

Given how easy it is to move objects between JSContexts, and the extra seperation it provides it should be obvious to have a JSContext object per addon (shared between all background and event scripts).

However, given that manifest.json access is expected by the addons, and we'll be constructing some of the chrome object in Javascript, we should also have a tying-the-js-knot JSContext that manages the JS side of manifest semantics, and the JS-implemented bits of the chrome object.

I haven't looked at this yet, but we may be able to extend WKUserContentController to allow finer grain control over which WKUserScripts are loaded: I do not know if these can be changed after the new location is known (after redirects) and before the scripts are loaded. This would be the ideal situation.

If not, we have to load all content scripts for all addons for all pages, later becoming low hanging fruit for optimization. The worst case will be passing javascript over the bridge to an AddonContentHelper.js user script; this would be horrible, especially to simulate the AtDocumentStart.

CSS contributed by addons could go either route.

There needs to be some addon runtime made of two WKUserScripts loaded at run AtDocumentStart and AtDocumentEnd.

This would, minimally, construct the chrome object and metadata for each addon before running it. Maximally, it needs to be able to receive javascript and CSS or coordinate which of the addon scripts are going to run, and CSS applied.

We have enough bridges between Swift and the various Javascript contexts that chrome.runtime.sendMessage can be done with a little bookkeeping. I'm not sure about chrome.runtime.connect.

Eye test

Javascript Build tools

I can't decide whether to go balls out bleeding edge and futuristic or so simple its painful but won't scale. This would be primarily for the more capable background and event javascript runtimes.

The JS side of addon management can be cleanly locked away in a different context to the addons, so can structured how we want.

A require function would be a perequisite for nice code and developer productivity, and once we have a require step running, there is essentially no limit to the tooling JS and npm can bring to the table.

For the lay reader: require is the CommonJS way of doing imports. Namespacing and encapsulation in the webdev javascript before ES6 modules has always been shit show.

In fantasy dream land, I'd like to be writing this code in ES6, with Flow Types.

Of course, we are not the first to be aggressively using JSContext: react-native packager may be of use here, which does the ES6->plain old JS->Flowtypes->Packaging, ready for execution in JSContext.

Getting require to work in JSContext may take some work, but would yield benefits almost immediately: by not having 1000 line javascript files.

There will be a bunch of 'standard' APIs we will need to shim, including local storage and XHR.

UX Considerations

Addons bring a lot of choice for the user, and there isn't the same real estate that desktop has.

Addons can contribute to the UIView UI, and can be filtered agressively (url, mimetype?) though it is possible (likely?) that there isn't a clear winner (e.g. pageAction). Additionally, browserActions can come from zero or more addons, so we should expect multiples of these choosable by the user – either by preferences or habits, or pickers.

I have been thinking in terms of a OneOfSome pattern of OneOfSome<T?> views, with UserPreferencedOneOfSome, URLFilteredOneOfSome, FrecencyOneOfSome; perhaps with a submenu to select from when there's more than one, or an ordered list of choices (toggleable or not) maintained in a preference page.

We are already seeing this play out when extending about:home tiles.

Additionally, in the same way Android doesn't force each app to invent its own preference pages, we may want to be able to offer a generic preferences template which localized content can be squirted in from the addon registry.

Further more, addons are exciting! We get to concrete the cowpaths and invent different places to put other people's content, all while handing off most of the work to other people!

Summary

I've explored some of the iOS APIs which we can implement a WebExtensions-like API, and sketched out a possible route to get there. I've identified some places which need further research, and problems that need to be solved.

I am optmistic that this can be done.

Flowers

Links

 

Writing about writing

2 min read

clouds uncovering the hills I've been on the web since 1994. My first email address was with yahoo.com. The first browser I used was Netscape Navigator.

I've periodically kept a blog, and while I enjoy writing, I find it difficult, and I find it time intensive.

withknown is dead, like totally

The harder problem is that I seem to have a knack for picking really bad publishing platforms. To give you a hint: I've written posts on Yahoo 360, Posterous, identi.ca and app.net. I had a slashdot.org account, for goodness sake, complete with goofy cool internet-handle – it was all the rage.

For the lay-reader: all of these are now dead, or at least, in decline or about to be dead. All of that content, all of those words – now gone. Not to mention the various versions of business cards that had incarnations of 'my blog' printed on real dead trees – poor dead trees.

For the last few years, however, my primary web presence has been on twitter. I have more than 10,000 tweets, which my various friends and family have described as too technical or too cryptic.

twitter isn't

I was a relative late comer to twitter. There were various reasons why I waited, and once I'd joined it took about 6 months to go from first post to second. But I really hit my stride when I heard twitter described as 'micro-blogging'.

So, that's how I use it: as a web-log with tiny posts. At times, it's an information radiator, but at other times, it's just a journal, with one intended reader – me, from the future.

But lately, I've been having more long-form thoughts that I want to write about. I've tried tweet-storms, but find the process of writing them too encumbered by the character limit.

Is this thing even on?

So: this is me trying something new. I think I've solved the stuff going away problem by using an instance of withknown.com and my own domain.

The harder problem is more internal to me: the writing itself. So the 'something new' is to trick myself into writing more by calling it 'milli-blogging'. Keen observers of SI units of measure will observe that milli-blogging should be a thousand times longer than micro-blogging, but pedants gonna ped.

This concludes first post.

 

Looking for biscuits.