I’ll be participating in the Web Workers BarCamp in Paris today, discussing topics vaguely similar to those of my previous blog post. My slides are downloadable here [pdf], or you can watch them below:
See you around!
Everyone Loves Me
My apologies to my non-technical readers: this article is going to be a hairy, brain-roasting piece of technical innovation. The same goes for my technical readers not familiar with Hindley-Milner.
An access control system is a piece of software architecture that makes sure only authorized users can access certain parts of the software. Access restrictions are usually defined as rules in a variety of formats. The most basic ones apply to general user categories and features: for instance, only a moderator (user category) can ban another user (feature). Rules can get extremely complex. For your amusement, here’s a real-life example:
The event page may be edited by the creator of that event page, by the moderator of any of the groups in which that event was posted, or by any global administrator account, as long as the editing user has entered their password at least once since they entered the website.
As a software architect mindful of the safety of your data, you have a few basic requirements for any access control system:
This is pretty hard to achieve, mostly because every single project out there contains code like the one below:
User.checkRecipientList(Request.recipients, Request.user) foreach (var recipient in Request.recipients) { var email = new Email(); email.From = Request.user email.To = recipient; email.attach(file); email.send(); }
Of course, the main danger is that the Email class was not written to check that the sender can indeed send a message with an attachment to the recipient. Of course, this can be solved through code reviews, which scan all classes in search of missing access control code, and functional tests, because the specs said an error message should appear. These are costly, tedious solutions that eliminate that problem. However, assuming that the class was indeed written correctly, there’s another problem:
User.checkRecipientList to throw an error if a recipient is invalid.In short, this piece of code contains a time bomb that no user or software can detect until it happens.
Before I explain what I’ll be doing, I need to describe the tools I’m going to use. As you might have guessed from the Hindley-Milner reference above, I’ll be using a variant of ML, namely Objective Caml. The language provides a sophisticated type system, entirely checked at compile-time, and which can be almost completely inferred from the code (that is, you almost never have to add type annotations to your programs). For instance :
let print_integer x = printf "The integer is %d" x print_integer "hello"
This code defines a function called print_integer that accepts a single argument, and uses the classic printf function to print it. It then tries to call that function with a string argument. The Objective Caml type inference algorithm will look at the format, which contains a single %d, and deduce that it expects a single integer argument. From there, it deduces that the first argument to print_integer should be an integer, and the function returns nothing : int -> unit. As a consequence passing a string is a type error :
This expression has type string but an expression was expected of type int
A highly expressive compile-time type system means we can use it to prove important properties about our software, but it increases the size of type expressions (because types have to carry more information) : and type inference means we won’t have to write those long type expressions everywhere.
Objective Caml types are parametric, which works a bit like generics in C# and Java. The type system automatically infers the type parameters from the code :
let first_element array =
array.(0)
In this example, the type of the function would be correctly identified as 'a array -> 'a : accepts an argument which is an array of a generic type 'a, and returns an element of that same type 'a. There are plenty of parametric types in the standard library alone : 'a array, 'a list, 'a option…
The latter is the Objective Caml replacement for null values : the language does not allow values to be null (when you say a variable is an array, then it’s always a valid array), so values that might be missing are explicitly tagged as optional using the option type. For instance, when you’re looking for an item in a database, you might want to return an optional type to represent the situation where the item is missing. While exceptions would interrupt the control flow and rise up to the nearest try-catch block that can handle them, using options forces the developer to decide on the spot what he wants to do with the value, usually with pattern matching:
match Database.read id with | Some item -> frobnicate item | None -> frobnicate default_item
Options have the advantage that you can’t forget to handle the null case, because you have to use pattern matching to access the returned value. On the contrary, you can always forget that an exception might be thrown (and it’s not obvious when doing a code review, either).
Another important element of the Objective Caml type system is the ability of modules to hide away type information. Consider the following example :
type 'a page = { password : string ; id : int } let read page = Database.read page.id let write page content = Database.write page.id content let unlock page password = if password = page.password then Some page else None let lock page = page
This is an elementary access control system : you can read both locked and unlocked pages, but once you lock a page, you need to unlock it with a password before you can write to it again. Looking at the code above, this doesn’t appear at all : theres no locked/unlocked boolean variable on the page, which means I could pass a locked page to the write function and it would not complain about it at all! The lock function merely returns its argument without doing anything to it! The only password-related code is the unlock function, which does indeed check that a page is password-protected, but there’s no need to unlock a page before it’s written to…
The unnecessary type parameter on the page type should have been a hint, and it all becomes clear when one looks at the module signature :
type 'a page val read : 'a page -> string val write : [`Unlocked] page -> string -> unit val unlock : [`Locked] page -> string -> [`Unlocked] page option val lock : [`Unlocked] page -> [`Locked] page
This module signature describes how every other module in the system will see our page-related functions. It hides the definition of the page type, to prevent people from accessing its fields directly, uses the seemingly unnecessary type parameter to carry additional information about the locked/unlocked state of the page, and it restricts the type of the write function to only accept pages which are unlocked. All of this is allowed : as long as the signature defines a type that’s more restrictive than the actual type inside the module, it’s still going to work.
So, from inside the module, the page is fully accessible regardless of its locked/unlocked status, but outside the module, the locked/unlocked status is enforced at compile time by the type system. This is very important : if you try to write to the page without asking for a password first, you don’t get a runtime exception, you get a compiler error message. And a pretty clean one, too:
This expression has type
[`Locked] pagebut an expression was expected of type[`Unlocked] page
Also, since the definition of the page type is hidden away by the module signature, the only way to create an unlocked page is with the unlock function above.
As for performance, once the software is compiled, all of this vanishes into nothingness : Objective Caml only uses type information for checking the validity of the program, and discards it from the final binary.
All of it using only standard language features. Can your language do that?
This approach revolves around proving that you have access to a certain feature of a certain object. That proof is created by a first function (the provider) , placed in the type parameter of the object, and required by a second function (the consumer) that actually performs the intended operation. In the example above:
unlock function is a provider : it proves that the user knows the password by placing [`Unlocked] in the type parameter of the page.write function is a consumer : it expects the page to be [`Unlocked] before it writes data to it.In short, you have providers that perform the access control tests (is this user authenticated? is he an administrator? does he know the password?) and then securely store the result of those tests to be used by the features they are protecting. The type system prevents the users from using features without successfully calling the providers first, and the module system lets you write providers and consumers without having to define brand new types all the time.
The security comes from the fact that if the consumer expects a certain proof (as an argument of specified type) then that argument was necessarily returned by one of the providers able to create that proof. Tight control of proof providers (made possible by the fact that providers are always in the same module as the one that defines the type that carries the proof) combined with responsible and conservative definition of consumers helps keep a system safe and secure.
In practice, the proof that is being carried around takes many shapes, the two main ones being about proving who the user is, and proving what the user can do. The provider of who-proofs is the authentication system, which digs up information about the user from the cookie, the session and the database, and concludes about its nature:
type 'a user val current_user : [`Unknown] user val as_admin : 'a user -> [`Admin] user option
It’s fairly common to transform who-proofs into what-proofs based on generic rules such as “an administrator can edit everything“:
type 'a page val edit_by_author : 'a page -> 'b user-> [`Editable] page option val edit_by_admin : 'a page -> [`Admin] user -> [`Editable] page val edit : [`Editable] page -> string -> unit
This illustrates the difference between absolute rules and conditional rules : “an administrator can edit everything” is an absolute rule, because it’s always true, whereas “the author can edit his creation” is a conditional rule because the user might not be the author of the page. This is outlined in the example above by the fact that one function returns an option (indicating the possibility of failure) while the other does not.
The edit-by-author property could also be handled by representing ownership as a proof on the page :
val is_author : 'a page -> 'b user -> [`Owned] page option val edit_by_author : [`Owned] page -> [`Editable] page
As an example, the above can be used to construct a generic “editable” function that accepts any page and user as an argument, and proves whether the page can be edited by the user :
let editable page user = match is_admin user with | Some admin -> Some (edit_by_admin admin page) | None -> match is_author page user with | Some owned -> Some (edit_by_author owned) | None -> None val editable : 'a page -> 'b user -> [`Editable] page option
Another example would be giving another user a token that they can use to edit a page, but do nothing else :
let prove_editable page = hash (secret_key, page.id, "editable") val prove_editable : [`Editable] page -> string let check_proof_editable proof page = if proof = hash (secret_key, page.id, "editable") then Some page else None val check_proof_editable : string -> 'a page -> [`Editable] page option
This effectively lets you serialize a proof to a string, and later unserialize it to allow edit access to a user that normally couldn’t have edited the page.
I know you want to start working on your Start-Up right away. Who doesn’t? You have a great idea that is bound to earn you millions as soon as it makes it out of your garage, so the obvious choice would be to start working on it immediately. And, as usual, the most obvious choice is probably not the best one.
While it might send you flying into a panic, wasting some time when a project first begins is quite satisfying if you don’t let your instincts shame you into regretting it. While I officially started working on RunOrg this week, one of the first tasks I got out of the way was to finish Half-Life 2 again in a single session. Needless to say, I was so tired by the end that I was starting to see stupid things:

This is a joke. We don’t really support cross-dimensional transhuman dictatorships. Don’t listen to me, I’m just crazy.
Spending one or two weeks doing nothing productive before you start working on that Start-Up has its benefits:
Of course, all of this will be for naught if you don’t first get rid of that nagging feeling that you should be doing something. Yes, I know your fate and financial independence lies in your hands alone, but that doesn’t mean you should rush head first into an uphill battle. A quick vacation improves productivity better than the typical «insert more caffeine» strategy.
Now, if you’ll excuse me, there’s some Cake on my todo-list.
A personal pet peeve of mine: people who add captions to images using monochrome text. If you use a white font, then it will be unreadable when it sits on light backgrounds. If you use a black font, then it will be unreadable when it sits on dark backgrounds. Unless your image is exceptionally well-tempered (also known as boring) you will end up with the wrong kind of text sitting on the wrong kind of background and it will look terrible. And if you decide to use two different font colors to handle different backgrounds gracefully, remember that there’s nothing graceful about using two different font colors.
What you need is a dark-edged light font (or a light-edged dark font, depending on the effect you wish to achieve). What readers will see is the inner edge between the light center and the dark contour, and that edge is well-preserved regardless of color. For instance:
This can be done in most editing software these days. If you have Office installed, just use the WordArt tool to set a black edge and white body for your font. Adobe Photoshop and Illustrator handle this nicely as well. If you only own free-as-in-beer software, Inkscape allows you to achieve this effect quite easily.
The above image was done with Microsoft PowerPoint 2010, while this earlier image was done with Inkscape.
You’re saving an important document on your computer and all of a sudden, it explodes. Maybe the power went out, maybe the hard drive joined the choir invisible, or maybe the application just bluescreened. Either way, you lost your work for the past five minutes (because you’re hitting Ctrl + S every five minutes, right?)
I have some bad news for you: the computer went down while it was writing on top of the file. What used to be a though-provoking bullet-based presentation has now turned into the software equivalent of a week-old roadkill.
In the software industry, we need higher reliability. You don’t want your bank to say «your payment is safe, unless a random crash occurs in the next five minutes», what you expect is nothing less than «should the apocalypse strike within the next five seconds, your financial transaction will be safe with us» and this causes us technical types to run around in circles looking for better ways to keep your data crash-proof.
So, obviously, every single database vendor out there advertises itself as being completely and irrevocably crash-proof. Usually as part of a huge bulleted list of features. Boring.
Here, CouchDB is the one with the outstanding marketing message. The CouchDB server cannot be shut down by any safe means, the only way to stop it is to cause it to crash (or kill it with a task management tool, or power off the computer). They’re basically implying that their crash protection design is so good, crashing the software is the normal shutdown procedure.
One way to be outstanding is to make difficult things appear effortless — routine events no more remarkable than tying your shoes or drinking water. Where every other software package makes crash recovery sound like an exceptional effort worthy of being included in a feature list, CouchDB shrugs, an unimpressed «I eat crashes for breakfast» look on its face, and goes back to manhandling your data.
So, what do you eat for breakfast?
There was a 900-hour countdown on this blog. The hardcore fans who stalk me on LinkedIn already knew. For the rest of you, here it is:

As of today, I leave the warm safety of being a full-time, well-paid employee and take my first steps down the road of Bootstrapped Start-Up adventures. And I’m giddy like an Evil Overlord who just had his new Death Ray delivered by UPS. I guess I could technically call myself a CEO, but there’s only three of us so far, so the delusional titles will have to wait.
We’re building an online tool that helps associations, unions, organizations and communities manage their members, contacts, activities, events, knowledge and online presence.

Obviously, we won’t be the first tool in this category, and we’ll be going against free competitors. Why would RunOrg be different?
Bad answer #1 : if he wasn’t afraid of people, the hacker inside me would answer that we intend to write godlike code and bring together a baroque triumph of technical prowess. I remain deeply convinced that our users don’t care about code quality as long as the interface is usable, the data is secure and the features are delivered on time.
Bad answer #2 : every member of the RunOrg team holds or recently held a position of responsibility in an association or community, and frequently interacts with other people in such positions in other associations. This is where I would insert the standard blathering about how we intimately know the needs of our customers, how we eat our own dog food to make sure it tastes good, and that’s why our product will rock your socks off like no member management tool ever did (I swear there’s a sock rocker feature in the design blueprints). That’s not the case for all of our competitors, but several of them are as familiar with the issues as we are.
Now, if you’ll excuse me, it’s time for my daily prayer to Seth Godin and Kathy Sierra. I’ll be right back.
Good answer : the challenge of building a tool for associations, unions, organizations and communities is neither software engineering nor interface design. Software engineering is for computers, interface design is for users, and RunOrg is for groups. What we need to be doing is social engineering : making sure that in addition to being friendly to the computer and useful to the user, the tool encourages behavior that helps the group thrive and discourages behavior that has a negative impact on the group.
Make sure you pre-order our $299 RunOrg™ neural implants, which send stimuli directly into the pleasure centers in the brains of your members to keep them acting in the best interest of the group. Surgery not included.
Just kidding. Or am I?
Failing to see the needs of associations and groups as deeply rooted in social behavior leads to mistakes being repeated over and over again, both by service providers and by group leaders. The high turnover rate in these groups imposes some hard requirements on any long-term software strategy. Members spend most of their time not participating in the community, so involving them enough to keep the community alive is a real challenge. There’s a fine line to be walked between spamming members to death and boring members to death, and it’s easy to create tools that turn that line into a line of negative width.
We’re in the business of helping communities thrive. We do it by writing software that recognizes that communities are more than lists of members, activities and events. For every feature, we ask ourselves how it can help members get involved in their community, both online and offline.
The RunOrg project will begin its Beta phase at the end of November 2010. It will be held in French, although an English version is possible if there is overwhelming demand for it. You can pre-register (or simply keep in touch) by sending me an email (victor@nicollet.net) or from the project home page.
The first commercial version will be done by the end of January 2011, and beta participants will get nifty bonuses to thank them for their time.
The current project site is hosted on a small laptop in a small room at home, so it might break down unexpectedly (we’ll move to professional hosting next week).
Until then, you can read the RunOrg/blog (in French) to learn more about our project. You could also follow us on Twitter (@RunOrg) or join our Facebook Page.
You have probably noticed an unusual lack of updates here lately. That would be because I’m currently in the final stages of a devious world domination plan to be revealed in a short while. The clock is ticking. You will not escape.
Once that deadline flies by, I will be returning to my traditional five-times-a-week publishing schedule. In the mean time, guest post suggestions are welcome: victor@nicollet.net, as usual.
Recent Comments