For Any Refactoring: Test, Explain, Let Know and Learn (TELL)
We propose a Test, Explain, Let Know, and Learn (TELL) approach to all API refactoring. Having applied a refactoring, always apply the four TELL steps:
- Test the updates locally and end-to-end to ensure the API works as expected. Do not just consider functional tests but also non-functional ones, such as performance tests, to ensure that the refactoring did not introduce a performance regression.
- Explain the new design in an Architectural Decision Record (ADR)1 and have it reviewed as needed. Adjust the API description (including Version Identifier) accordingly. Make sure that your conceptual, platform-independent design, its technology- and platform-specific refinement, the implementation, the tests, and the documentation of all of these artifacts stay current and consistent.
- Let API clients and other stakeholders know about the change (even if a change might be syntactically and semantically backward-compatible, the refactored API might offer qualitatively different features now, for example, a Wish List that clients could use to optimize their conversations). Decide whether the API version that has been refactored should continue to be supported for some time. One or more lifecycle management strategies can be applied, for instance, Version Identifier or Two In Production evolution patterns.
- Learn about the effectiveness of the refactoring (as well as potentially negative side effects) with logging and other observation instruments.
The TELL steps help to ensure that the refactoring improves the API quality and that the API clients are informed about the changes and can evolve without disruption. See Chapters 3 and 8 of “Patterns for API Design” [Zimmermann et al. 2022] for more information about options, criteria, and consequences of applying different evolution patterns.
Other General Hints and Pitfalls to Avoid
Each refactoring has a section called “Hints and Pitfalls to Avoid”. Here are a few tips that apply to most if not all refactorings:
- Establish measurable quality goals to be able to decide that it makes sense to refactor and to evaluate whether you succeeded. Alternatively, include API design quality issues in your technical risk management. The Design Practice Repository provides further guidance.
- Execute the steps under “Instructions” in an all-or-nothing manner. If it turns out that you cannot complete a refactoring successfully, undo all steps already performed to roll back to the initial state.
- Make sure that your conceptual, platform-independent design, its technology- and platform-specific refinement, the implementation, the tests and the documentation of all of these artifacts stay current and consistent. Test under normal conditions, but also edge cases and error scenarios.
- Try to decouple the API from its implementation to be able to evolve and refactor independently.
- Evaluate whether the smells are removed (or that at least some desired qualities have improved somewhat); record any remaining or new technical debt and identify additional follow-on refactorings.
- Check whether the same refactoring makes sense in other places a) to remove other smell instances or b) to preserve conceptual integrity (a term from Fred Brooks).
Sample Application: Lakeside Mutual
The Lakeside Mutual application is a sample microservice architecture we built to demonstrate API design and patterns. It comprises several Spring Boot microservices offering APIs that are used by clients written in React, Vue.js, and Node.js:
The code is available at GitHub and licensed under the Eclipse Public License.
References
Zimmermann, Olaf, Mirko Stocker, Daniel Lübke, Uwe Zdun, and Cesare Pautasso. 2022. Patterns for API Design: Simplifying Integration with Loosely Coupled Message Exchanges. Addison-Wesley Signature Series (Vernon). Addison-Wesley Professional.
-
To learn more about creating ADRs, we recommend the following article: https://medium.com/olzzio/how-to-create-architectural-decision-records-adrs-and-how-not-to-93b5b4b33080 ↩