Book Review: The Hard Thing About Hard Things

CEO stories aren’t just for CEOs—good news for all of us that haven’t helmed a Silicon Valley rollercoaster or followed up on our successful exit by founding an acclaimed venture capital fund. Even readers who aren’t Ben Horowitz still face choices between outcomes that aren’t always good. Life is a panoply of unexpected challenges, no-win scenarios, and options of bad and worse. The Hard Thing About Hard Things is about that.

The book itself unfolds against Horowitz’s own close calls amid the bubbles and busts of the early Internet boom. Through his battles with Microsoft as a Product Manager at Netscape and his struggles to keep successive cloud computing firms afloat in the wake of the dotcom crash, there’s an uncanny symmetry to the formula. Rocket, crater, lesson learned.

Lessons like:

  1. “Bad” can get very bad,
  2. Crises are never intractable,
  3. Action breeds opposition, and
  4. “Least bad” is better than nothing.

If you come for the insight, stay for the telling. Horowitz’s own experiences as a CEO (and later coaching them) provide rich fodder for the book’s many parables. Blunt, plainspoken delivery leaves little space for padding and lends a veneer of authenticity rarely found on airport bookshelves.

Not all of the book will be immediately applicable to everyone, but a rich blend of credibility and catharsis make it worthwhile reading for anyone–and that’s all of us–who has ever faced down a difficult choice.




AMP, Quick and Dirty

Accelerated Mobile Pages (AMP) trade userland JavaScript and network-loaded resources for lightning-fast load times. Since AMP is able to constrain resource loading and page rendering, it can save both CPU cycles and bandwidth during page rendering. It’s a compromise, but for content-driven sites it’s certainly worth a look.

Plus it’s easy to do. I start porting this blog mostly out of curiosity, but after half an hour, one new template, one additional build rule, and a little bit of polish with the AMP validator, I had a simple (but functional) AMP-compliant facsimile of the real thing.

Updating the Template

Following the getting started guide, I first created a template exclusively for the AMP route. It shares all of its variables with the route that’s served to desktop browsers, but it allowed me to check AMP’s boxes with no impact on the existing experience. These really only meant a few changes:

  • noting AMP support in the <html ⚡> tag
  • removing all userland <script /> and <style /> tags
  • adding the AMP runtime and <style amp-boilerplate> styles

Not wasn’t my prettiest work–stripping away the base stylesheet will do that–but it was somewhere to start.

Updating the Stylesheet

Next up was the stylesheet. All new, but heavily dependent on existing parts.

/* amp.css */
@import 'normalize.css';
@import 'screen';

.header {
  /* AMP-specific rules go here */
}

Since the site build was already running through gulp. I’d barely added amp.css to the list of source files before a compiled version was ready for injection (as compiledCss.amp) back into the template using an amp-custom style.

<style amp-custom>
{{{compiledCss.amp}}}
</style>

Restoring Analytics

Most modern analytics libraries use JavaScript for tracking–streng verboten in AMP. But since the format is designed with advertisers in mind, the <amp-analytics> provides a reasonable alternative (with pretty good vendor support). I imported it into the AMP template just after the core library.

<head>
  <meta charset="utf-8">
  <script async src="https://cdn.ampproject.org/v0.js"></script>

  <script async custom-element="amp-analytics"
    src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>
  <!-- ... -->

Setting up tracking (e.g. Google Analytics) just meant adding an <amp-analytics> element inside the existing page <body />:

<amp-analytics type="googleanalytics">
<script type="application/json">
{
  "vars": {
    "account": "UA-XXXXXXXX-X"
  },
  "triggers": {
    "trackPageview": {
      "on": "visible",
      "request": "pageview"
    }
  }
}
</script>
</amp-analytics>

Referencing the AMP page from the original page

All that work and no-one to see it? Switching back to the desktop template, I added a <link /> to the AMP version of the page:

<link rel="canonical" href="{{url.self}}" />
<link rel="amphtml" href="{{url.selfAMP}}" />

Thirty minutes in, and things were ready for finishing touches. Chrome has AMP validation built-in; by browsing the local development site with #development=1 in the URL hash, I was able to find and fix lingering issues with the implementation. I sanded down the rough edges, and voila! v0.1 was off to the races.

Conclusion

While the step-by-step details here may help you get up and running, the more important message here is for other emerging technologies. When big business depends on pulling the internet onto a new standard–and make no mistake, alongside the noble mission of ‘make the web fast’, AMP also happens to be very well suited for selling ads–decent documentation and tooling go a long way.

Water runs downstream. Make adoption easy and adoption will come!




Composing Higher-Order React Components in TypeScript

Higher-order components are a powerful tool for encapsulating behaviors, but using them isn’t always pretty:

const Foo: React.SFC<State & OwnProps> = (props) => {
  // ...
}

export default loadable(isLoading)(withUser(connect(mapStateToProps)(Foo)));

Since higher-order components are first-class objects, however, we can use a small compose utility to halt the rightward drift.

const FinalComponent = compose<OwnProps>(
  MyComponent,
  loadable(isLoading),
  connect(mapStateToProps),
  withUser,
)

All we need is the implementation.

import * as React from 'react'

type RC<P> = React.SFC<P> | React.ComponentClass<P>

type HOC<O, P> = (C: RC<O>) => RC<P>

// compose components from left to right
const compose = <P>(C: RC<P>, ...hocs: HOC<any, any>[]): RC<P> =>
  hocs.reduce((g, f) => f(g), C)

There’s quite a bit of hand-waving here. While the final component must have props matching <P>, the composed components can have any–a convenient if less-than-satisfying compromise. We don’t get type-safety within the composed component, but we do keep a variadic signature familiar from (e.g.) lodash.flow and interoperability with untyped 3rd-party components.

Someone out there has a clever way to address types of subsequent components. For now, validation of the “public” prop-types is better than nothing!

View all posts