Web Components: have we not been here before?

Addy Osmani describes Web Components, of which an important part is custom tags. The promise:

In one word, a future with Web Components is declarative. JavaScript still exists in this future, but is relegated back to a role where it acts as a glue holding the other bits of a component together. Web Apps in the near future will be composed almost entirely from elements (tags). Some of these elements (like the <audio> tag) will be given to you by the browser but others like <slide-show> will be custom elements provided by UI libraries or you can write it yourself.

Programming with tags. Where have we heard this before?

Starting in the 90′s (and through to the present), there’s ColdFusion. It offers quite a library of custom tags — for everything from control flow (<cfif>) to database interaction (<cfinsert>).

Microsoft has ‘em too — called Web Controls  — abstracting away things like authentication and (again) database access. Drop in a tag, get a fully-functioning login form.

Logic as markup. So tempting, and so wrong.

Markup is nouns and adjectives. It doesn’t have verbs. It describes, but it does not impel.

Unless we start from the assumption that we want our logic to be declarative! In which case we end up with tags representing verby things like “authenticate the user, hit the database, and iterate the results”.

Now, expressing a syntax tree in markup is just as syntactically “correct” as any other way. If you want to wrap your if statements and subroutines in angle brackets, no problem, you can do that. If you want function arguments expressed as attributes, OK.

But why would we? We’ve got languages — lots of them. And we make new ones all the time. Why retrofit HTML?

ColdFusion and Web Forms were not unsuccessful. Lots of people adopted them, and there was a marketplace for custom tags. The same will probably go for Web Components.

I suspect, however, we’ll go through a time of irrational exuberance before realizing that everyone has created their own weird-ass pseudo-language with angle brackets.

discuss on hacker news

Nesting is state

There are stylistic debates about how much nesting or indentation one should choose in code. This slide and the one that follows illustrate the issue well. The slide refers to “cognitive load” without explaining, and it occurs to me that nesting is state.

In the first example, if we want to debug around the highlighted line, what do we need to keep in mind?

func (g *Gopher) WriteTo(w io.Writer) (size int64, err error) {
    err = binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
    if err == nil {
        size += 4
        var n int
        n, err = w.Write([]byte(g.Name))
        size += int64(n)
        if err == nil {
            err = binary.Write(w, binary.LittleEndian, int64(g.AgeYears))
            if err == nil {
                size += 4
            }
            return
        }
        return
    }
    return
}

Answer: the truth of each of the if statements that precede it. Each of those bits of truth is a piece of state. Now look at the alternative:

func (g *Gopher) WriteTo(w io.Writer) (size int64, err error) {
    err = binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
    if err != nil {
        return
    }
    size += 4
    n, err := w.Write([]byte(g.Name))
    size += int64(n)
    if err != nil {
        return
    }
    err = binary.Write(w, binary.LittleEndian, int64(g.AgeYears))
    if err == nil {
        size += 4
    }
    return
}

In this case, the highlighted line “cares” very little about what came before — all it needs to know is that we got there.

The flattening of the hierarchy plus lots of return-on-fail can be thought of as “shedding” state. I call this pattern “fail fast”: by the time you get to the bottom of the code, you really only need one piece of “state”, which is “we’ve gotten this far successfully”. You can forget the past.

Of course, the logic of these two examples is equivalent. I am speaking of the mental model — the list of “non-local” things that must be kept in mind when working with a local piece of code.

And for me, “list of non-local things” is a good definition of “state”.

discuss on hacker news

Ben Horowitz on wage-fixing

I am really, really enjoying Ben Horowitz’s The Hard Thing About Hard Things. It’s blunt and refreshing, and lives up to its title. It’s a nice counter to the notion that running a business is dreamy and life-affirming all the time.

But! I was a bit surprised to find him advocate the sort of behavior that has ensnared a bunch of tech firms in a wage-fixing suit.

A good rule of thumb is my Reflexive Principle of Employee Raiding, which states, “If you would be shocked and horrified if Company X hired several of your employees, then you should not hire any of theirs.” [...]

In order to avoid these sticky situations, many companies employ written or unwritten policies that name companies where it is not okay to hire without CEO (or senior executive) approval. With such a policy in place, you will be able to give your friend one last chance to save their employee or to object prior to you hiring them. (pp. 116-117)

On its surface, it seems like relationship advice: don’t take your friends’ or business partners’ employees.

But this is precisely what collusion is. Eric Schmidt and Steve Jobs didn’t aim to “collude”; they just intended to protect their relationships (and their interests). That they failed to notice that they were interfering in a market for employee talent is the problem.

discuss on hacker news

What Stack Overflow and Go have in common

I’ve been working at Stack for over three years now, and over the last six months or so I’ve been doing playing with a programming language called Go. Both are highly regarded and, for many, controversial, and I’ve realized what they have in common.

Stack Overflow and Go are both optimized for artifacts. Which is to say, their goal is to create good outcomes that last a long time. Note that this is not the same as optimizing for the pleasure of their users.

Stack users are sometimes frustrated the strictness of our policies, especially regarding the relevance and objectivity of questions. Go users often gripe about the need to constantly be handling errors at their source — bubbling and catching exceptions is just not a thing.

What both of these design choices have in common is that they help to ensure that what comes out the other side is actually of value.

And make no mistake, they are design choices. They are not technical shortcomings or oversights.

Now, these choices need to be balanced against the pleasure of the authors. If Go were hard to write, or Stack capriciously rejected good questions, neither would be a success.

What both of them demand is, do your homework. Stack questioner: take the time to research your question and express it clearly. Go programmer: that file system call can fail, and your code needs to account for that.

It’s a trade-off between the hedonic happiness of authors in exchange for a longer-term eudaimonia of end users.

discuss on hacker news

How I optimize conversations

I had an epiphany some years ago in working with a person at a previous firm. After many interactions, I noticed that my productivity, my happiness, my motivation consistently were diminished after dealing with this person.

In other words, I found that I came out of these conversations feeling more burdened than I had going in.

I noticed with certain other people, our conversations were exactly the opposite — I came away with fewer problems, or a new perspective, or food for thought, or feeling freshly challenged.

Once I came to notice this pattern, I resolved to be the latter person. This means optimizing conversations for the other person being glad that they dealt with you. This can take many forms, some more tangible than others.

The most tangible form, perhaps, is where you say “I’ll take care of it”, and it’s true, and they leave with a lesser burden. But it takes many other forms.

At Stack, for example, I’ve become a bit of a rubber ducky lately. There are several people — programmers and otherwise — who seek me out when they want to talk through technical or product challenges.

Now, I am very good programmer working at a place where the other programmers are more than very good. It’s unlikely that I’ll tell them what code to write.

But I might help them characterize the problem differently than they are currently doing. Maybe it’s a compression problem, or a caching problem, or a type problem, or a separation of concerns problem, but they haven’t recognized it as such.

More likely, I’ll nod and ask leading questions. Not because I am trying to lead them anywhere in particular, and not because I know the answer, but because I want to lead them away from rut they are in. I am optimizing the conversation for the other person having a new perspective.

But these are just examples. The point is to think creatively and empathetically about why a person started a conversation with you. Make it profitable.

Threshold thinking

I consider our industry’s current approach to ads to be wildly inefficient. Very “good” click-through rates are in the single-digit percentages, and more likely one or two orders of magnitude below that.

Let’s assume for the sake of argument that some brand advertising is valuable, which is to say that the impression serves a purpose even if the user doesn’t click.

So, being charitable, 90% of ads that we put on our sites are of no economic value, which is to say, of no value to the user.

This makes them a degradation of our product. We go to great lengths to get the design just-so, and then we mar it with an element that serves the user not at all.

I don’t say this because I am against ads; I am against ads for which there is no evidence of value.

I think of this in economic terms. Ads are negative consumer surplus in 90% of cases. They make our published product a worse value. Over time, customers should be expected to migrate to products that provide better value.

I don’t expect this to simply be solved by better targeting which nudges up click-through rates. There needs to be an order-of-magnitude change.

I’d like to see the first publisher or ad network that only chooses to serve ads for which it has evidence of economic value; in the absence of such evidence, an ad is not shown at all.

Our current method of ad delivery is spray-and-pray. If we are very good at targeting, 10% of the ads have value. What if we had higher standards than that?

The trouble with interfaces in Go

I am working on a tool for generics-like functionality in Go. Despite what you may have heard, Go does have generic functionality, in that you can create (e.g.) methods which operate on any type, by using interface{} — the interface that all types implement. For example, you can do something like:

func DoSomething(interface{}) interface{} {
...
}

…where both the input parameter and the output return value are interface{}. It’s quite flexible. The very nice go-linq operates this way, as do data structure packages like Set. That they will accept any type, and can return any type, meets a definition of generic.

The trouble is, the user will (in all likelihood) need to cast return values into types to do something meaningful. If they use such a function to, say, filter a slice of int, the user will need to cast the resulting values back to int to proceed.

There is an adage in programming that one should be liberal in what one accepts, and conservative with what one emits. The above pattern only gets the first part right. The input parameter is liberal, but unfortunately so is the return value.

This burdens the user with figuring out the nature of the output. It’s more code, and less safety.

For me, static typing means exploiting type information to make guarantees at compile time. Without traditional generics, we must resort to doing some of what (IMHO) is the type system’s job.

So one of the motivations of gen is to deal with that return value on the right-hand side of the above code sample — to bring it into the realm of known types that the compiler (and the user) can reliably exploit.