There's Always a Customer

We ship some pretty crazy things when we think that customers aren’t watching. You’ve seen them: the mysterious scripts underpinning critical systems, or the Craigslist-chic GUI that gives the support team its superpowers. Take off the shackles of usability, security, and future support, and just see what we can build.

The results lend themselves to a fun little game that I like to call “spot the root cause.” The rules are simple: when you encounter an internal tool, ask yourself “why?” When you finally track down an answer–likely an internal-only interface buried a bit deeper down the platform–ask “why” again. Keep unraveling the thread until you arrive at the original, distant-past decision marked “for internal use only”. Well done! You’ve spotted the root cause.

Three Little Costs

If we know where the journey ends, why embark in the first place?

Internal-only has its allure. When we stop building with customers in mind, we can cut corners and develop at a breakneck pace. But “quick and dirty” has a nasty habit of auto-correcting to “unusable, maintenance-deferred.” Only later do we recognize the unexpected costs that a cavalier approach to quality tends to incur.

The first we notice is time. Even hacky programs take time to write and debug, let alone (perish the thought) to maintain. Next come their users, ticking away the minutes frustrated by quirky interfaces and the complete absence of documentation. For developers and customers alike, time spent wrestling against arcane tools means less time delighting customers, shipping world-changing products, or watching the kids grow up at home.

The second cost is reuse. Internal tools don’t break customers, and–in the best case–the internal ecosystem can be a valuable incubator for new technology. It’s important, however, to recognize the distinction between a tool used internally and one built for internal use. Is the tool maturing with an eye to eventual generalization? If not, it will eventually need to be thrown out and rewritten.

But the biggest cost of building for internal use are the opportunities that get shut out. Every tool is a potential product. It addresses a problem shared by at least one of the other seven billion warm bodies heating the atmosphere. Sharing isn’t just a nice thing to do: it’s also potentially lucrative (in social capital, if not revenue). Few of us are going to follow Tiny Speck and drop everything to follow an internal tool, but neither should we ignore opportunities our own needs uncover.

A Little Respect

Foregoing internal tools doesn’t mean a blank check to prototype in production. It’s simply the recognition that everything has a customer. We don’t have to be fanatics about it (it works for Amazon, of course, but then most of us aren’t Amazon) to reap the fruits of a little self-respect. We wouldn’t sell a lousy tool to our customers, so why inflict it on ourselves?

The next time you win a game of “spot the root cause”, take a good hard look at the problem unraveled before you. Could someone else’s open-source tool obviate it? Or could this be the start of a solution to someone else’s problem? I bet it could.

Let’s make it official. Here are some nice, shiny digital stickers ready for the sticking on your (proudly) open-source tool. Use them anywhere!

(All images ISC licensed | Download all)


Integrating TypeScript and redux-thunk

typescript and react

Note: this is the fifth entry in a short series about bolstering Redux applications with TypeScript. Part one introduced a simple counter application, which we then dressed up with a simple React UI and API interactions. Read on!

When last we dealt with the outside world, a redux middleware was helping insulate our counter application from the messy details of API interaction. This has the advantage of letting us consider business logic independent of the transport layer; it was also convenient for illustration. But it was also rather verbose, as the middleware added an additional step of indirection on top of redux’s existing data flow.

We can do better, and a community-supported middleware–redux-thunk–can help. As its name suggests, redux-thunk allows us to dispatch actions defined as functions (the thunk). In our counter application, this will allow us to collapse the API interactions currently contained in our middleware into constituent action creators.

If you’re just looking to see the refactored application in action, check out the example project over on github. For everyone else, let’s get started.

The beginning

Our middleware set out to solve the challenge of separating our mostly-pure redux application from the vagaries of network I/O. API requests were initiated in response to specific actions (X_REQUEST), and their success or failure expressed in terms of additional actions dispatched to the application. In code, it looked like this:

export const apiMiddleware = ({ dispatch }: redux.MiddlewareAPI<any>) =>
  (next: redux.Dispatch<any>) =>
    (action: Action) => {
      switch (action.type) {
        case 'SAVE_COUNT_REQUEST':
          api.save(action.request)
            .then(() => dispatch(saveCount.success({}, action.request)))
            .catch((e) => dispatch(saveCount.error(e, action.request)))
          break

        case 'LOAD_COUNT_REQUEST':
          api.load()
            .then(({ value }) => dispatch(loadCount.success({ value }, action.request)))
            .catch((e) => dispatch(loadCount.error(e, action.request)))
          break
      }

      return next(action)
    }

This allowed us to define logic on top of our actions without imposing side-effects on either the redux store or individual react components.

But we could achieve a very similar result if our actions were wrapped in functions that had could dispatch further actions. In other words, we’d love to be able to define an action-creator, saveCount, that will wrap the entire API interaction:

type Q<T> = { request: T }
type S<T> = { response: T }
type E = { error: Error }

type QValue = Q<{ value: number }>

export type Action =
  ({ type: 'SAVE_COUNT_REQUEST' } & QValue)
| ({ type: 'SAVE_COUNT_SUCCESS' } & QValue & S<{}>)
| ({ type: 'SAVE_COUNT_ERROR'   } & QValue & E)
// ...

export type ApiActionGroup<_Q, _S> = {
  request: (q?: _Q)         => Action & Q<_Q>
  success: (s: _S, q?: _Q)  => Action & Q<_Q> & S<_S>
  error: (e: Error, q?: _Q) => Action & Q<_Q> & E
}

const _saveCount: ApiActionGroup<{ value: number }, {}> = {
  request: (request) =>
    ({ type: 'SAVE_COUNT_REQUEST', request }),
  success: (response, request) =>
    ({ type: 'SAVE_COUNT_SUCCESS', request, response }),
  error: (error, request) =>
    ({ type: 'SAVE_COUNT_ERROR',   request, error }),
}

export function saveCount(request: { value: number }) {
  return (dispatch: redux.Dispatch<Store.All>) => {
    dispatch(_saveCount.request(request))
    api.save(request)
      .then((response) => dispatch(_saveCount.success(response, request)))
      .catch((e: Error) => dispatch(_saveCount.error(e, request)))
  }
}

Inside connected components, we would dispatch this action just as before.

// ...
onSaveClick: (value: number) =>
  dispatch(saveCount({ value })),

Not only will redux-thunk let us do this, but it will make it almost trivial. We just need to install it.

First, grab it from NPM:

$ npm install --save redux-thunk

Next, import 'redux-thunk' and include it in the middleware stack of the main redux store:

import thunk from 'redux-thunk'

import {
  reducers,
  Store,
} from './reducers'

// ...

let store: redux.Store<Store.All> = redux.createStore(
  reducers,
  {} as Store.All,
  redux.applyMiddleware(thunk),
)

Could it be that easy? It is!

Fire up the counter, and voilà: we can now dispatch the saveCount action creator like any other action.

Refactoring

Breaking the middleware into its constituent (and easily-tested) parts is a win, but we’re not done yet. As written, saveCount depends on both a rather unwieldy type definition, and ApiActionGroup, in addition to the action creator itself. There’s not much to do about the definitions, but the creator at least can be generalized in terms of the corresponding ApiActionGroup and API request.

type apiFunc<Q, S> = (q: Q) => Promise<S>

function actionCreator<Q, S>(x: ApiActionGroup<Q, S>, go: apiFunc<Q, S>) {
  return (request: Q) => (dispatch: redux.Dispatch<Store.All>) => {
    dispatch(x.request(request))
    go(request)
      .then((response) => dispatch(x.success(response, request)))
      .catch((e: Error) => dispatch(x.error(e, request)))
  }
}

With actionCreator added to our action module, it’s trivial to prepare existing ApiActionGroups for export:

export const saveCount = actionCreator(_saveCount, api.save)

Conclusion

redux-thunk has tidied things up nicely, while the original middleware continues working as before. That means that we could phase actionCreator in gradually without affecting the overall behavior of the project: not a big concern for our toy counter, but a boon for integration with any larger project.

The completed counter project is available for reference on github, build, code, tests, and all. And I’m looking forward to your suggestions, experiences, and feedback over on twitter.



Testing TypeScript with Jest

typescript and react

Note: this is the fourth entry in a short series about creating React/Redux applications with TypeScript. Part one introduced a simple counter application, which we then dressed up with a simple React UI and API interactions. Read on!

Followers of this blog won’t need to be convinced of the value of a well-maintained test suite. And lucky for us, Jest makes it nearly painless to test React applications–even with TypeScript in the mix. Let’s look at the layers involved in developing clean, test-secured code.

Linting

In vanilla JavaScript, linting validates syntax as a first line of defense against runtime errors. In TypeScript, static type-checking serves a similar purpose, though with a more sophisticated understanding of the raw syntax’s context. But linters have a secondary purpose: ensuring maintainability. Even with a type-system handling the heavy lifting of static analysis, we still benefit from linting for legible, consistent style.

Fortunately for us, tslint is a first-rate TypeScript linter with configuration and use familiar from JavaScript tools like jshint or eslint. After installing tslint, and initializing a default configuration, we’re ready to lint a new or existing project:

$ npm install -g tslint
$ tslint --init
$ tslint -c tslint.json 'src/**/*.{ts,tsx}'

Setting up Jest

Jest is a low-configuration testing harness popular in React applications, and for good reason: in vanilla JavaScript, it mostly Just Works™. That’s a big deal for developers used to wrestling with PhantomJS (you know who you are–and if you don’t, just use Jest).

Using Jest with TypeScript takes a little more effort. Facebook’s Jest/TypeScript example outlines the strategy: set up a preprocessor for any TypeScript files; run Jest as before. ts-jest is a great option for preprocessing, providing compilation, source-mapping, and an all-around pleasant preprocessing experience. It’s available via npm:

$ npm install --save-dev ts-jest

Now, to start testing we need only add a new top-level entry for "jest" into the project’s package.json:

"jest": {
  "moduleFileExtensions": [
    "ts",
    "tsx",
    "js"
  ],
  "transform": {
    "\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
  },
  "testRegex": "/__tests__/.*\\.(ts|tsx|js)$"
}

While package.json is open, let’s add scripts for linting and testing to see all of our hard work in action:

"scripts": {
  "lint": "tslint -c tslint.json 'src/**/*.{ts,tsx}'",
  "pretest": "npm run lint",
  "test": "jest"
},

Add some tests

At this point, our tests read the same as they would in JavaScript. Let’s write a simple spec that will verify future changes of our <Counter /> component using a snapshot made possible, as all good things are, by Jest.

// src/components/__tests__/counter_spec.tsx
import * as React from 'react'
import * as TestUtils from 'react-addons-test-utils'

import { createStore } from 'redux'

import { Counter } from '../counter'
import { reducers } from '../../reducers'

describe('<Counter />', () => {
  it('renders', () => {
    const store = createStore(reducers)
    expect(TestUtils.createRenderer().render(
      <Counter label='a counter!' store={store} />
    )).toMatchSnapshot()
  })
});

By rendering the component with a shallow renderer, we’re able to compare to a snapshot exactly as we would in JavaScript. All that’s left is to watch it turn green.

$ npm test

Conclusion

There you have it: the basic tools, configurations, and scripts to make testing a central part of a TypeScript application. We don’t have to stop here! Though it’s an exercise for another day, the same techniques we use to validate code and write unit tests can just as easily apply in end-to-end testing.

The completed counter project is available for reference on github, tests and all. Have an comment, suggestion, or improvement? The issue queue is open for business. And I’m looking forward to your suggestions, experiences, and feedback over on twitter.

And as ever, happy testing!

Note: this is the fourth installment of a short series about bolstering Redux applications with TypeScript. Next, we’ll revisit our API interactions, using the redux-thunk middleware to tie them up. Read on!



View all posts