From the beginning we set out to use a monorepo, a single Git repository containing all the code, tests, assets, deployment scripts and non-secret configuration for each of the services and applications in the system.
This was a major factor in keeping things simple across a number of different aspects: there was only one CI; one deployment process (even if there were multiple services and data centers); automated acceptance tests covered the whole system as one; pull requests included changes to the whole system which made code review and manual testing much more straightfoward. It meant that all of our code, irrespective of how it was deployed or used, was considered as a single cohesive system that could be developed and refactored together, tested together and deployed together.
Another technique we used that allowed us to merge features more often without endangering the production release was feature toggles. We’d often do this when we were dependent on other teams, or other business processes for the whole end to end feature to work: we’d write our part of the feature, we’d test and merge it, but make sure the feature was disabled in our production environment so it wasn’t accessible, or wouldn’t endanger existing functionality. Once those blockers were gone, we’d re-enable the feature in production.
The advantage to this approach was that we didn’t see features rot in their own branches while we waited on external blockers to be lifted.
This seems pretty obvious really, but it’s easily forgotten in API design because there’s no obvious user interface, and one can waste a lot of time imagining what it might be like to use an API instead of actually using it.
APIs are building blocks, not final products, so there are potentially lots of different end-user products that can use your API. It’s really important to understand as many of these as possible, you’re very likely to have an insight for a new feature, or a different API structure when you do this. Your API’s endpoints and schema should be as much as possible structured on the basis of these primary use-cases, not on the basis of merely exposing the data and features behind it.
We worked very closely with lots of different potential users of the new API, many of them external clients and partners of TravCorp, from before our first line of code to well into stable releases. Some of these interactions completely changed our approach, giving us the opportunity to fix things that were big problems for our clients, but that were almost unnoticed by ourselves.
We built a web UI that used the API to explore, book and pay for tours. Pretending to be one of our API users really helped us to flesh out the details and structure of the API. This web UI was extremely useful, we used it in manual exploratory testing for the API and we used it in presentations and as a usable demo application for new API users to explore the API. This became a fairly well used tool amongst the wider team for exploring the data and demonstrating and understanding bugs.