Skip to content

Commit

Permalink
Update the readme with acceptance criteria for 1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
pmcelhaney committed Jul 15, 2022
1 parent 07a4e9a commit a36fbf2
Showing 1 changed file with 73 additions and 10 deletions.
83 changes: 73 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,76 @@

[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fpmcelhaney%2Fcounterfact%2Fmain)](https://dashboard.stryker-mutator.io/reports/github.com/pmcelhaney/counterfact/main)

## Why?
Counterfact is (will be) a tool that helps front end developers and back end developers collaborate by quickly building reference implementations of OpenAPI specs.

I was building an UI against back end code that was so cumbersome I spent almost as much time trying to get the latest version of the back end code running as I did writing the front end code. Also I needed to build UI code against features and bug fixes that would not be available for a long time. Eventually I determined in the long run it would be quicker to hack together a fake implementation of the API so that I could keep going. Over time that fake implementation evolved to the point that it was pretty nice to work with. And I loved that I could easily recreate the exact scenarios I needed to test against.
Counterfact is _not_ for _production_.

After leaving that job and leaving the code behind, I looked around for open source tools that do more or less the same thing, and couldn't find any that were as malleable and flexible as the code that I had hacked together. So I recreated it as an open source library. Not hacked together this time, but carefully constructed with test driven development.
Counterfact is _great_ for _testing the UI_, both manual and automated testing. UI testing can be quite tedious and brittle in part because the _arrange_ part of Arrange, Act, Assert -- getting the server into a particular state -- is often slow, unpredictable, and complex. Counterfact bypasses the accidental complexity associated with arranging a real server's state, making tests that isolate the UI fast, repeatable, and easy to maintain.

With Counterfact, we can implement a server with quick-and-dirty JavaScript code and _that's totally okay_. We're not supposed to use Counterfact in production any more than we're supposed to build a skyscraper out of Play-Doh. The design is optimized for testing scenarios quickly and painlessly. Changes are picked up immediately, without compiling or restarting the server. It's great for manual testing, especially hard to reproduce bugs. It's also great for automated testing.
It accomplishes that without over-isolating. You can run a full scenario: log in, make changes, log in with a different user, and see the effects of those changes. The server you're testing against is a _real_ server from the UI's perspective: it implements business logic and maintains state. It's only not real in the sense that it doesn't have to support 10,000 concurrent users, protect real data, go through a deployment pipeline, or maintain 99.99% uptime.

Counterfact is _great_ for _communication between front end and back end teams_. OpenAPI does an excellent job defining the inputs and outputs of a RESTful service, but it can't tell us how a server is supposed to behave. Counterfact fills that gap. The feedback cycle is orders of magnitude faster than making changes to a real, scalable back end and then seeing how those changes affect the UI/UX.

## Road to 1.0

This project is a work in progress. As of July 15, 2022, most of the plumbing is in place. This project will reach 1.0 when mutation test coverage is > 90% and:

The following command

```sh
npx counterfact init ./my-petstore https://petstore3.swagger.io/api/v3/openapi.yaml
```

creates or augments an npm package, and after changing to the directory

```sh
cd my-petstore
```

the following command

```
yarn start
```

opens a browser with Swagger-UI pointing to a server that implements the pet store API.

Not a mock server that returns canned or randomly generated responses, a [_real_ implementation](./demo-ts/), written in TypeScript.

Or at least, the _potential_ for a real implementation. Out of the box, it will return example or random responses. But the code is easy to edit so, e.g., we can change `PUT /pet` to store a `Pet` in memory / a database / a microservice / etc., and `GET /pet` to retrieve that same `Pet`.

We can see the effects of the code changes _without restarting the server_.

And then after running

```sh
yarn generate /path/to/copy/of/petstore/with/some/changes.yaml
```

it regenerates the code except for the files that we changed. Of the files we changed, the IDE (via TypeScript and ESLint) tells us if the code needs to be modified to conform to the updated spec.

_Again, without restarting the server._

## Beyond 1.0

The scenario above describes a zero-configuration happy path, adhering to the philosophy of convention over configuration.

The next phase is to add configuration options that define things like what port the server runs on, when generated files are overwritten, where those files live, whether to add `start` and `generate` scripts and what they should be named, whether to build a soup-to-nuts server or only make Express / Koa / Connect middleware available, etc. These configurations may be set in a `.counterfactrc.json` file, environment variables, and or command line options, whatever makes sense.

(By the way, generating code is optional. When this project started, that wasn't even part of the scope. If you don't have an OpenAPI spec, or don't want to use it, Counterfact is still an ergonomic platform on which to build quick and dirty prototypes of RESTful services in TypeScript or JavaScript.)

After that, more features that improve developer experience. For example, say you're demoing an iOS music player app and someone asks about edge cases. You'll be able answer questions immediately by going into a REPL and typing things like:

```ts
context.addABunchOfSongsToCatalog(1_000_000);

context.setAlbumTitle(
123,
"This Is is a Very Long Name That is Definitely Not Going to Fit in the Allotted Space and it has Emoji 🦧"
);

network.setLatency("1-5s");
```

## Installation

Expand All @@ -24,7 +87,7 @@ yarn add -D counterfact

## Usage

See the [demo](./demo/README.md) directory for an example.
See the [demo-ts](./demo-ts/README.md) directory for an example.

### Using the Koa plugin

Expand All @@ -43,7 +106,7 @@ const app = new Koa();
const initialContext = {};

const { koaMiddleware } = await counterfact(
fileURLToPath(new URL("routes/", import.meta.url)),
fileURLToPath(new URL("paths/", import.meta.url)),
initialContext
);

Expand All @@ -52,15 +115,15 @@ app.use(koaMiddleware);
app.listen(PORT);
```
### Setting up routes
### Setting up paths
The first thing you need to do is create a directory where you will put your routes.
The first thing you need to do is create a directory where you will put your paths implementations.
```sh
mkdir routes
mkdir paths
```
To mock an API at `/hello/world`, create a file called `./routes/hello/world.js`.
To mock an API at `/hello/world`, create a file called `./paths/hello/world.js`.
Inside that file, output a function that handles a GET request.
Expand Down

0 comments on commit a36fbf2

Please sign in to comment.