Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save patrickclery/1b72bbffbc5deb66ee538573eee842de to your computer and use it in GitHub Desktop.
Save patrickclery/1b72bbffbc5deb66ee538573eee842de to your computer and use it in GitHub Desktop.

How to split technical tasks so that every developer can work asynchronously

Mock-Driven Development is a way of planning out features in a way that allows each dev to work on a feature without having to wait for other coders to finish their work.

The traditional way of assigning tasks

  • The coder is given a business requirement and told "make this happen".
  • Because the business scope might be vague, the technical scope becomes a big question mark.
  • This often makes the scope of the feature cross several domains of the app (backend, frontend, API, database, etc.)
  • By the end of the feature, the coder is expected to have all these domains working together without errors.

This makes sense when...

  • You have a team of 1.
  • You're designing a "hello world" app.
  • You love pain and suffering.

This isn't a good idea when...

  • You have a team of >2.
  • You're working on a complex app that has a lot of moving parts.
  • You don't love pain and suffering.

The big problem with "big bang" features

  • blocks other coders because they can't jump in

  • if the coder gets stuck, the entire feature is blocked.

  • the coder is often saying "it's almost done!" for weeks or months

  • it's draining to work on a feature for so long

  • by the time they're done, the feature is so big that it's hard to review

    Example of how a task like "add a new field to the form" becomes a planning disaster:

    • is it just adding the field to the database?
    • or is it also adding the field to the UI?
    • or is it also adding the field to the serializer?
    • or is it also adding the field to the backend?
    • or is it also adding the field to the frontend?
    • or is it also adding the field to the backend and the frontend?
    • or is it also adding the field to the backend and the frontend and the API?
    • or is it also adding the field to the backend and the frontend and the API and the UI?
    • or is it also adding the field to the backend and the frontend and the API and the UI and the database?
    • ...etc.

Mock-Driven Development to the rescue!

  • other coders can jump in and help
  • tasks are not so complex that only the ancient code wizard who lives on the mountain will know how to implement it
  • small reviews
  • ship faster

How it works in a nutshell

1. Define "contracts" between components

  • take a business story that has already been groomed by the product owner (with the help of the team)
  • find points where the components in the software connect and define "contracts" between them

    Example: the browser calls the API endpoint to create a payment agreement

  • Each contract is divided up into two components: usually the "request" and the "response"

    Example: the browser sends a request to the API endpoint and the API responds

  • Each component agrees on the contract (the request and the response)

    Example: calling to endpoint /api/xyz.json with the request body {a: 1, b: 2} will return the response body {c: 3, d: 4})

2. Define the "boundaries" and tools of each component

We want to clearly define the scope of work for each component so that the scope is manageable.

The components are going to assume that the other components respond exactly as they agreed to in the contract.

Here's another way to think about: we assume everything is broken (example: server is down) but we have to make the component work anyway.

  • List the components that will be mocked out, using the contracts as a guide

    Example: the API will be stubbed to respond with {c: 3, d: 4} when called with the request body {a: 1, b: 2}

  • Provide the tool that will be used to mock each component

    Example: MirageJS will be used to stub the API Example: nock() will be used to write tests Example: /public/api/xyz.json will be used to stub the API

  • Provide the actual files that will be worked on

    Example:

    • app/javascript/components/Form.jsx
    • app/javascript/components/Form.test.jsx
    • app/javascript/api/createAgreement.js
    • app/javascript/api/createAgreement.test.js
  • Specify a list of files that are outside the scope and should not be touched
    • app/controllers/api/xyz_controller.rb
    • app/models/payment_agreement.rb
    • app/serializers/payment_agreement_serializer.rb

3. Define the tests we expect

What most people call "test-driven development" is actually the opposite: It's test-REACTIVE development.

"Reactive" test-driven development is code first, tests later. "Real" test-driven development is tests first, code later.

We can make a list of tests as a way to plan the technical parts of our feature, this our coder a clear plan of where to start, and clarifies the scope of work.

> Example:
>    - when createAgreement() is called with createAgreement(1,2), it should send a post request to /api/xyz.json with the request body {a: 1, b: 2}
>    - add this to app/javascript/api/createAgreement.test.js
>    - example of a test like this: https://github.com/Lexop/lexop/blob/0888ad6ffbf56c4d9a6266eee8fc906670ad0784/test/javascript/components/payment_portal/gateways/spreedly/api.test.jsx#L16-L45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment