Refactorings by Stakeholder Concerns
Click on the table entries for quick access. We also have a Refactorings by Smells index.
- Agility 1
- Auditability 1
- Availability 1
- Client Information Needs 2
- Cohesion 3
- Compatibility 1
- Consistency 1
- Cost 2
- Coupling 5
- Data Access Characteristics 2
- Data Currentness 1
- Data Freshness 1
- Data Ownership And Placement 1
- Data Parsimony 1
- Data Privacy 1
- Developer Experience 7
- Development Velocity 1
- Discoverability 1
- Ethicality 1
- Evolvability 6
- Explainability 5
- Flexibility 8
- Green Software 4
- Independent Deployability 2
- Information Hiding 1
- Interoperability 1
- Learnability 5
- Maintainability 9
- Modifiability 2
- Observability 1
- Offline Support 1
- Performance 9
- Readability 1
- Reliability 2
- Resource Utilization 1
- Runtime Qos 1
- Scalability 4
- Security 7
- Service Rightsizing 1
- Simplicity 2
- Single Responsibility Principle 3
- Stability 2
- Team Organization 2
- Testability 2
- Understandability 7
- Usability 1
- User Experience 1
This index lists refactorings by the stakeholder concerns they address (Show / Hide all details):
Agility
- Segregate Commands from Queries
(Hide Details )
Read operations and write operations may evolve at different speeds. For example, data analytics queries may often change, driven by client demand and insights just gained, while commands to modify master data might only change with major releases, if at all.
Auditability
- Encapsulate Context Representation
(Hide Details )
In multiprotocol scenarios, end-to-end security guarantees can only be given and enforced when the information in protocol headers is aggregated and correlated somehow. System and process assurance auditors appreciate if all relevant compliance information can be found in a single place (that is adequately protected) [@Julisch:2011].
Availability
- Split Application Backend Logic
(Hide Details )
Failures in one part of the system can impact others unless fault isolation is carefully designed. In distributed systems, service dependencies and network issues increase the risk of cascading failures. In monoliths, a single crash can bring down the entire application. Availability must be addressed explicitly during design, evolution, and operation.
Client Information Needs
- Add Wish List
(Hide Details )
APIs are often used by multiple clients with different information needs, which makes it difficult for their providers to offer one-size-fits-all solutions.
- Add Wish Template
(Hide Details )
As motivated in Add Wish List, APIs are often used by multiple clients with differing information needs, which makes it difficult for providers to offer one-size-fits-all solutions. Some clients may require overviews of information elements, for instance lists of identifiers; others may require a subset or all of the data fields (attributes) of these elements.
Cohesion
- Introduce Data Transfer Object
(Hide Details )
API providers strive for low coupling and high cohesion in their endpoint, operation, and message designs.
- Merge Endpoints
(Hide Details )
Cohesion refers to “the degree to which the elements inside a module belong together” according to Wikipedia. In the context of this refactoring, the “elements” are the API operations, and the “modules” are the API endpoints. API designers, and software engineers in general, strive for high cohesion, meaning that operations that belong together are offered by the same endpoint. [@Constantine:1974] define a scale of cohesiveness that ranges from coincidental, logical, temporal, communicational, sequential to functional cohesiveness. In the highest form, functional cohesiveness, “all of the elements [of a module] are related to the performance of a single function.” The Systems Engineering Body of Knowledge also provides an explanation of this general term.
- Merge Operations
(Hide Details )
Cohesive design elements (here: API operations in an endpoint) belong together naturally because they share certain properties. In an API design context, the security rules that apply are an example of such a property. Cohesion is desirable because it makes the system easier to understand and maintain. ISO/IEC/IEEE 24765 [@ISO24765:2017] defines cohesion as “manner and degree to which the tasks performed by a single software module are related to one another.”
Compatibility
- Introduce Version Identifier
(Hide Details )
Explicit versions, possibly introducing breaking changes, might appear costly and anti-agile or not RESTful at first glance. However, fixing bugs caused by not knowing about versioning mismatches is often expensive.
Consistency
- Split Application Backend Logic
(Hide Details )
Data stored together can be guaranteed to meet the ACID properties more easily than distributed data. A single, local system transaction manager (such as a relational database management system) can take care of that. “Software Architecture: The Hard Parts” discusses this concern as one of the difficult-to-make architectural decisions that are required [@Ford:2021].
Cost
- Relax Evolution Strategy
(Hide Details )
Less code to be maintained over time means less maintenance costs. Sometimes, a planned (or managed) obsolescence approach is followed.
- Tighten Evolution Strategy
(Hide Details )
Effort comes with cost. Operational and capital expenditure, including budget for training, evolution (including documentation), and operations, increases as lifetime guarantees are extended.
Coupling
- Extract Information Holder
(Hide Details )
Systems and components evolve at different speeds. Hence, they should not depend on each other unless this is justified in the business requirements. Data dependencies often introduce unwanted coupling that is difficult to detect and resolve.
- Introduce Data Transfer Object
(Hide Details )
API providers strive for low coupling and high cohesion in their endpoint, operation, and message designs.
- Merge Endpoints
(Hide Details )
According to the Wikipedia entry for this term, coupling is the degree of interdependence between software modules, a measure of how closely connected two modules or API endpoints are. “Strong coupling complicates a system since a module is harder to understand, change, or correct by itself if it is highly interrelated with other modules” [@Constantine:1974]. The pattern summary of Loose Coupling suggests time, platform, reference, and format as key autonomy dimensions. “The Many Facets of Coupling” and other “ramblings” by Gregor Hohpe suggest a “nuanced discussion of coupling”.
- Merge Operations
(Hide Details )
In our context, coupling is a measure of how closely connected and dependent on each other endpoints and their operations are. The coupling may concern the data exchanged and/or the operation call sequencing. See Wikipedia entry for Coupling and Loose Coupling pattern for general explanations.
- Split Application Backend Logic
(Hide Details )
Application logic and data storage within a single deployment unit are inherently coupled in terms of change management and scaling, even when separated by local interfaces. The amount of coupling is a multidimensional stakeholder concern. See for instance “The Many Facets of Coupling”.
Data Access Characteristics
- Introduce Pagination
(Hide Details )
In principle, the client wants to access all data elements, but not all have to be received at once or every time. For example, older posts to a social media site might be less relevant than recent ones and can be retrieved separately.
- Make Request Conditional
(Hide Details )
API clients might use caching and do not want to retrieve data they already have.
Data Currentness
- Extract Information Holder
(Hide Details )
Data returned by an API might age at different rates. In the e-commerce shop scenario, for instance, the master data of customers (e.g., names, shipping addresses) will change less frequently than transactional data (such as orders). API clients might want to cache some of the data retrieved, which is harder if faster-changing data is embedded in slower-changing data.
Data Freshness
- Split Application Backend Persistence
(Hide Details )
Local data is less likely to outdate than remote data.
Data Ownership And Placement
- Split Application Backend Persistence
(Hide Details )
Distributed data, which may originate from different sources, with different locations and owners, is more difficult to validate, integrate, and use than homogeneous local data.
Data Parsimony
- Add Wish List
(Hide Details )
Overall response time, throughput, client-side and server-side processing time are qualities that concern API clients and their providers. Unused data that is prepared, transported, and processed wastes resources and ought to be avoided.
Data Privacy
- Segregate Commands from Queries
(Hide Details )
Read and write operations might have different protection needs. Few user roles, for instance, are usually authorized to update master data; many or all user roles may read it. If there are two separate endpoints for read and write access, it might be easier to fine-tune the Confidentiality, Integrity, and Availability (CIA) rules and related compliance controls. See the OWASP API Security Top 10 for risks and related advice on API security.
Developer Experience
- Bundle Requests
(Hide Details )
Bulk/batch uploads might be prepared by iterating through a data set and then calling API operations multiple times, once for each entry in the set. It might be easier for client developers to prepare a single technical request message (for instance, a JSON array) that contains several business-, domain-, or application-level requests (each represented as a JSON object). Such design frees the clients from having to manage the state (running, succeeded, failed) of all individual requests.
- Encapsulate Context Representation
(Hide Details )
Accessing protocol headers is different from accessing message payload; different local APIs and/or platform-specific libraries have to be used. Consolidating information in the payload reduces the learning and implementation effort.
- Inline Information Holder
(Hide Details )
An API that provides clients all the required data with as few requests as possible may be easier to use than an API where the client has to issue many requests and requires complex state management on the client side to keep track of multiple API calls. See the blog post API Design Review Checklist: Questions Concerning the Developer Experience (DX) for hints on improving the developer experience.
- Introduce Data Transfer Object
(Hide Details )
API clients want to navigate the required data with minimum effort, taking as few coding steps (expressed as statements and expressions) as possible.
- Introduce Version Identifier
(Hide Details )
Since Version Identifiers can be placed in protocol headers (in most protocols) or in the message payload, additional learning and decision making is required. Accessing protocol headers differs from accessing payload in terms of code to be written, tool and library support, and portability.
- Introduce Version Mediator
(Hide Details )
Breaking changes in APIs and pressure to upgrade may frustrate client developers, especially if they must migrate to a newer version on short notice. For instance, cloud application developers sometimes have to react rather quickly to changes introduced by their public providers.
- Make Request Conditional
(Hide Details )
Knowing when and how long to cache which data might be challenging for API clients and providers. Permanent or temporary storage is required. These valid concerns have to be balanced with the desire for performance.
Development Velocity
- Segregate Commands from Queries
(Hide Details )
Read operations and write operations may evolve at different speeds. For example, data analytics queries may often change, driven by client demand and insights just gained, while commands to modify master data might only change with major releases, if at all.
Discoverability
- Distribute Application Frontend
(Hide Details )
Search Engine Optimization (SEO) can have a significant impact on business success. Distributing rendering strategies to dedicated tiers influences the way information can be indexed by web crawlers. The chosen presentation strategy should address and reflect SEO requirements early in the design.
Ethicality
- Split Application Backend Logic
(Hide Details )
Openness, transparency, accuracy are typical ethical values and values requirements, for instance for Web applications that work with personal sensitive information. Distributing application logic and data might raise additional value requirements, for instance regarding data privacy. Furthermore, teams responsible for deployment units might prioritize values differently than developers, end users, product managers, or project sponsors [@Kapferer:2024:VDAD]. Irrespective of the chosen architectural styles and patterns, no application content should violate “Netiquette” or other guidelines and principles for communication and digitalization.
Evolvability
- Add Wish List
(Hide Details )
The information needs of clients and users vary over time, and an API and its provider-side implementation should not have to be adjusted every time something changes in its clients. Maintaining several variations of the same operation for different clients is possible but increases the maintenance effort and coordination needs, which in turn might constrain the flexibility of the API provider.
- Distribute Application Frontend
(Hide Details )
User interfaces must remain adaptable as technologies, platforms, and user needs evolve. Supporting different platforms or updating frameworks should not require full system changes.
- Extract Information Holder
(Hide Details )
Systems and components evolve at different speeds. Hence, they should not depend on each other unless this is justified in the business requirements. Data dependencies often introduce unwanted coupling that is difficult to detect and resolve.
- Introduce Data Transfer Object
(Hide Details )
API providers want the freedom to change the API implementation without revealing such changes to clients. Such information hiding [@Parnas:1972] is crucial for the independent evolvability of API providers and clients.
- Introduce Version Mediator
(Hide Details )
To evolve an API, providers must have the flexibility to refactor, redesign, and adapt an API over time. Ideally, this happens without breaking compatibility, but this is not always realistic.
- Split Operation
(Hide Details )
Operations that follow the single responsibility principle are easier to maintain and evolve, for instance, because their API provider only has a single reason to change their request and response message structure and content when evolving the API. Changing an operation that does many things is unnecessarily complex if the change only affects certain aspects of the operation; unexpected side effects may occur. For example, deprecating the operation is more complicated if it has multiple stakeholders.
Explainability
- Merge Endpoints
(Hide Details )
Fewer endpoints might be easier to understand and maintain—if they are cohesive and do not contain too many operations. The refactorings Move Operation and Rename Operation explain the quality attributes maintainability and understandability further.
- Merge Operations
(Hide Details )
There are many reasons to change an API (not just refactorings) [@StockerZimmermann2021]. APIs should be changed as much as required and as little as possible, and ripple effects be avoided. One of the first steps in related maintenance tasks is to determine which parts of the system should be changed. An API whose endpoints have clearly identified roles helps developers to quickly understand the API.
- Rename Endpoint
(Hide Details )
A good name expresses what an endpoint has to offer, which helps clients decide whether and how to use it. The Rename Operation refactoring provides additional explanations of the understandability and explainability qualities.
- Rename Operation
(Hide Details )
All stakeholders involved in development and operations should be able to grasp what an API is supposed to do (and actually does) with ease; it should be straightforward to teach API usage. On the contrary, educated guesses and implicit assumptions are likely to cause misunderstandings that lead to technical risk and defects later on.
- Rename Representation Element
(Hide Details )
A well-chosen name expresses what a representation element (such as a JSON object with its properties) has to offer, which helps clients decide whether and how to use it. The named element has a single meaning and purpose.
Flexibility
- Add Wish List
(Hide Details )
The information needs of clients and users vary over time, and an API and its provider-side implementation should not have to be adjusted every time something changes in its clients. Maintaining several variations of the same operation for different clients is possible but increases the maintenance effort and coordination needs, which in turn might constrain the flexibility of the API provider.
- Add Wish Template
(Hide Details )
Client information needs change over time, but an API and its implementation should not have to be updated every time a client does. Maintaining multiple variants of the same operation for different clients is possible, but increases maintenance cost and coordination effort, which in turn can limit the flexibility of the API provider.
- Introduce Version Mediator
(Hide Details )
To evolve an API, providers must have the flexibility to refactor, redesign, and adapt an API over time. Ideally, this happens without breaking compatibility, but this is not always realistic.
- Relax Evolution Strategy
(Hide Details )
Not having to maintain different versions in parallel makes the provider team more flexible, but limits the options client developers have.
- Segregate Commands from Queries
(Hide Details )
Keeping the read and write operations of an endpoint together is easy to understand and brings functional endpoint cohesion. A separation of these types of operations increases the ability to change them independently from each other; this can then happen more flexibly and more frequently.
- Split Application Backend Logic
(Hide Details )
Distribution of backend logic decouples the build cycles of the parts. For instance, independent changeability, deployability, and scalability are among the drivers for microservices.
- Split Application Backend Persistence
(Hide Details )
Data models evolve just like code and the domain models driving design and development; both flexibility and rigor are desired when it comes to changing these models. A large body of work on this tradeoff exists in database and data management research.
- Tighten Evolution Strategy
(Hide Details )
The more lifetime guarantees are given and the longer the committed time spans are, the less freedom remains to maintainers with respect to changing product vision, roadmap, and corresponding API designs (for instance, the role of an API in the organization).
Green Software
- Add Wish List
(Hide Details )
Overall response time, throughput, client-side and server-side processing time are qualities that concern API clients and their providers. Unused data that is prepared, transported, and processed wastes resources and ought to be avoided.
- Extract Information Holder
(Hide Details )
Assembling, transferring, and processing a response utilizes resources both on the provider and client side. These resources should not be wasted but handled with care and respect for the environment and the energy consumed. Bandwidth and computing power are examples of valuable and costly resources.
- Inline Information Holder
(Hide Details )
Both API clients as well as providers are interested in keeping the latency and bandwidth usage low and using as few resources as possible.
- Make Request Conditional
(Hide Details )
Response, throughput, and processing times concern API clients and providers. Unused data that is prepared, transported, and processed wastes resources, which should be avoided.
Independent Deployability
- Extract Operation
(Hide Details )
Endpoints can be deployed and then scaled separately, which is one of the defining tenets of microservices-based systems [@Zimmermann:2017]. The fewer operations an endpoint exposes, the easier it is to optimize the scaling for those operations.
- Move Operation
(Hide Details )
Principles such as single responsibility and independent deployability can guide the selection of refactorings. Some principles are affected positively, others negatively. With respect to the POINT principles for API design (purposeful, style-oriented, isolated, channel-neutral, and T-shaped), moving an operation to another endpoint can improve P, O, and I (but might harm T when looking at a single endpoint and not an entire API). Note that some principles might be defining an architectural style; for instance, statelessness of interactions in REST. Such prominent role makes it even more important to adhere to a principle during design, and stick to its evolution.
Information Hiding
- Introduce Data Transfer Object
(Hide Details )
API providers want the freedom to change the API implementation without revealing such changes to clients. Such information hiding [@Parnas:1972] is crucial for the independent evolvability of API providers and clients.
Interoperability
- Encapsulate Context Representation
(Hide Details )
Less protocol-specific functionality means fewer changes are required when one protocol is replaced by another.
Learnability
- Encapsulate Context Representation
(Hide Details )
Accessing protocol headers is different from accessing message payload; different local APIs and/or platform-specific libraries have to be used. Consolidating information in the payload reduces the learning and implementation effort.
- Merge Operations
(Hide Details )
There are many reasons to change an API (not just refactorings) [@StockerZimmermann2021]. APIs should be changed as much as required and as little as possible, and ripple effects be avoided. One of the first steps in related maintenance tasks is to determine which parts of the system should be changed. An API whose endpoints have clearly identified roles helps developers to quickly understand the API.
- Rename Endpoint
(Hide Details )
Using expressive and meaningful names makes navigating a code base easier, for instance when searching for endpoints while fixing bugs and adding features. The Move Operation refactoring has more explanations of such learnability and readability qualities.
- Rename Operation
(Hide Details )
All stakeholders involved in development and operations should be able to grasp what an API is supposed to do (and actually does) with ease; it should be straightforward to teach API usage. On the contrary, educated guesses and implicit assumptions are likely to cause misunderstandings that lead to technical risk and defects later on.
- Rename Representation Element
(Hide Details )
A well-chosen name expresses what a representation element (such as a JSON object with its properties) has to offer, which helps clients decide whether and how to use it. The named element has a single meaning and purpose.
Maintainability
- Add Wish Template
(Hide Details )
Client information needs change over time, but an API and its implementation should not have to be updated every time a client does. Maintaining multiple variants of the same operation for different clients is possible, but increases maintenance cost and coordination effort, which in turn can limit the flexibility of the API provider.
- Introduce Version Identifier
(Hide Details )
There are many reasons to change an API (besides quality refactorings [@StockerZimmermann2021]). It should be changed as much as required and as little as possible, and ripple effects be avoided. One of the first steps in related maintenance tasks is determining which system parts should be changed. The impact of the major and minor changes on other parts should be kept at a minimum, but it is worth communicating when such changes occur.
- Introduce Version Mediator
(Hide Details )
Fewer components and/or code paths that handle deprecated behavior make an API and its implementation easier to maintain for the provider.
- Move Operation
(Hide Details )
There are many drivers for changing an API [@StockerZimmermann2021]. APIs should be changed as much as required and as little as possible, and ripple effects be avoided. One of the first steps in maintenance tasks is to determine which parts of a system have to be changed. Separation of concerns tends to make changes smaller, but also adds to the amount of dependencies between system parts.
- Relax Evolution Strategy
(Hide Details )
Reducing the number of versions that run in production and reducing their lifetime guarantees reduces the maintenance effort.
- Rename Operation
(Hide Details )
APIs should be changed as much as required and as little as possible, and ripple effects be avoided; source code and documentation on client and provider side using a particular name have to be updated if this name changes. Expressive operation names help with orientation during API evolution. Debugging and troubleshooting is also easier if logs and error reports contain meaningful names.
- Rename Representation Element
(Hide Details )
The more expressive and meaningful a name (for instance, the key in a key-value pair) is, the easier it is to search and navigate the code base, for instance, when fixing bugs and adding features during API evolution. Split Operation covers this quality in more detail.
- Split Operation
(Hide Details )
Operations that follow the single responsibility principle are easier to maintain and evolve, for instance, because their API provider only has a single reason to change their request and response message structure and content when evolving the API. Changing an operation that does many things is unnecessarily complex if the change only affects certain aspects of the operation; unexpected side effects may occur. For example, deprecating the operation is more complicated if it has multiple stakeholders.
- Tighten Evolution Strategy
(Hide Details )
During their lifetimes, API versions have to be supported and evolved. Security patches are applied, bugs are fixed, and so on. The effort for such activities might not be proportional to the guaranteed lifetime but certainly is related to it. Related (sub-)concerns are compatibility and extensibility [@PatternsForAPIDesign:2022].
Modifiability
- Encapsulate Context Representation
(Hide Details )
Less protocol-specific functionality means fewer changes are required when one protocol is replaced by another.
- Introduce Data Transfer Object
(Hide Details )
API providers want the freedom to change the API implementation without revealing such changes to clients. Such information hiding [@Parnas:1972] is crucial for the independent evolvability of API providers and clients.
Observability
- Split Application Backend Logic
(Hide Details )
Distributed business logic increases the requirements for and the complexity of monitoring and debugging. Logging, tracing, and metrics must be designed to work across service boundaries, which requires extra design and implementation work. For instance, distributed traces must be correlated with each other and with the business transaction they belong to. The Context Representation pattern, which is the target of the Encapsulate Context Representation refactoring in IRC, may help to consolidate and correlate trace information to achieve end-to-end observability.
Offline Support
- Inline Information Holder
(Hide Details )
When the connection is unstable or if one wants to build offline functionality into an app, one large request is often better than many small ones.
Performance
- Add Wish List
(Hide Details )
Overall response time, throughput, client-side and server-side processing time are qualities that concern API clients and their providers. Unused data that is prepared, transported, and processed wastes resources and ought to be avoided.
- Add Wish Template
(Hide Details )
Response time and throughput are qualities that concern both API clients serving end users and API providers. Preparing, transporting, and processing data but not using it on the client side wastes resources and ought to be avoided when sustainability and “Datensparsamkeit” are required.
- Bundle Requests
(Hide Details )
Transferring many small requests may stress network and communication endpoints preparing requests and consuming them (for instance, on the HTTP or the TCP/IP level).
- Extract Information Holder
(Hide Details )
Assembling, transferring, and processing a response utilizes resources both on the provider and client side. These resources should not be wasted but handled with care and respect for the environment and the energy consumed. Bandwidth and computing power are examples of valuable and costly resources.
- Inline Information Holder
(Hide Details )
Both API clients as well as providers are interested in keeping the latency and bandwidth usage low and using as few resources as possible.
- Introduce Pagination
(Hide Details )
Transferring all Data Elements at once can lead to huge response messages that burden receiving clients and the underlying infrastructure (i.e., network and application frameworks as well as databases) with a high workload. For instance, single-page applications that receive several megabytes of JSON might freeze until all contained JSON objects have been decoded.
- Make Request Conditional
(Hide Details )
Response, throughput, and processing times concern API clients and providers. Unused data that is prepared, transported, and processed wastes resources, which should be avoided.
- Segregate Commands from Queries
(Hide Details )
Computationally expensive workloads such as loading data from data stores, filtering, and formatting it, and high data volumes may make certain operations expensive. Such complex query operations should not slow down cheaper operations exposed by the same endpoint (for example, atomic updates of single attribute values).
- Split Application Backend Persistence
(Hide Details )
Queries and other SQL operations should perform in such a way that the end-to-end performance goals of the system can be met.
Readability
- Rename Endpoint
(Hide Details )
Using expressive and meaningful names makes navigating a code base easier, for instance when searching for endpoints while fixing bugs and adding features. The Move Operation refactoring has more explanations of such learnability and readability qualities.
Reliability
- Extract Operation
(Hide Details )
Independent endpoints that do not share the same execution context and resources can be deployed independently; operations co-located in a single endpoint, however, share their deployment characteristics. For instance, if a long-running operation causes an API provider-internal error, its sibling operations might suffer from quality-of-service degradations as well. [@Nygard:2018] uses the term stability: “A robust system keeps processing transactions, even when transient impulses, persistent stresses, or component failures disrupt normal processing.”
- Move Operation
(Hide Details )
When co-located in a single endpoint and deployed jointly, operations might influence each other. For instance, if one of these operations is long-running or causes a provider-internal error, its siblings might suffer from quality-of-service degradation too.
Resource Utilization
- Introduce Pagination
(Hide Details )
Transferring all Data Elements at once can lead to huge response messages that burden receiving clients and the underlying infrastructure (i.e., network and application frameworks as well as databases) with a high workload. For instance, single-page applications that receive several megabytes of JSON might freeze until all contained JSON objects have been decoded.
Runtime Qos
- Distribute Application Frontend
(Hide Details )
The distribution of presentation logic (i.e., forms and views, dialog control) across physical tiers affects runtime Quality-of-Service (QoS) attributes such as performance, scalability, and reliability. For example, moving certain functions to the client side can reduce server load but might impact client performance or network utilization.
Scalability
- Extract Operation
(Hide Details )
Endpoints can be deployed and then scaled separately, which is one of the defining tenets of microservices-based systems [@Zimmermann:2017]. The fewer operations an endpoint exposes, the easier it is to optimize the scaling for those operations.
- Move Operation
(Hide Details )
When co-located in a single endpoint and deployed jointly, operations might influence each other. For instance, if one of these operations is long-running or causes a provider-internal error, its siblings might suffer from quality-of-service degradation too.
- Segregate Commands from Queries
(Hide Details )
Computationally expensive workloads such as loading data from data stores, filtering, and formatting it, and high data volumes may make certain operations expensive. Such complex query operations should not slow down cheaper operations exposed by the same endpoint (for example, atomic updates of single attribute values).
- Split Application Backend Logic
(Hide Details )
Backend components may carry different workloads, which suggests to scale them independently. This is possible with a distributed application backend, but not with a monolith.
Security
- Distribute Application Frontend
(Hide Details )
Remote placement of presentation layer responsibilities exposes more code to external parties. The data accepted from and displayed to end users as such does not change, but is transported and treated differently. Authentication, authorization, and data validation concerns become more complex when the frontend is distributed.
- Encapsulate Context Representation
(Hide Details )
In multiprotocol scenarios, end-to-end security guarantees can only be given and enforced when the information in protocol headers is aggregated and correlated somehow. System and process assurance auditors appreciate if all relevant compliance information can be found in a single place (that is adequately protected) [@Julisch:2011].
- Extract Information Holder
(Hide Details )
Not all API clients have the same access privileges. More fine-grained data Retrieval Operations make it easier to enforce related controls and rules, avoiding the risk that restricted data “slips through” accidentally. To revisit the e-commerce scenario, what if the shop software also includes public ratings of products that show the name and picture of the rating customer? Here, only limited and carefully selected information about the customer should be returned.
- Extract Operation
(Hide Details )
With multiple operations co-located within a single endpoint, it can be challenging to enforce fine-grained access control policies. Refactoring this endpoint into multiple specialized ones allows for more granular control over access permissions and authorization rules. The security requirements for the data an API endpoint exposes may also differ; hence, separating operations can make it easier to apply data protection measures that ensure confidentiality.
- Segregate Commands from Queries
(Hide Details )
Read and write operations might have different protection needs. Few user roles, for instance, are usually authorized to update master data; many or all user roles may read it. If there are two separate endpoints for read and write access, it might be easier to fine-tune the Confidentiality, Integrity, and Availability (CIA) rules and related compliance controls. See the OWASP API Security Top 10 for risks and related advice on API security.
- Split Application Backend Persistence
(Hide Details )
Moving persistence to a separate tier or host introduces new security considerations. Authentication, authorization, encryption in transit, and network segmentation become essential to protect data. Reducing the attack surface and isolating critical data are common goals.
- Split Operation
(Hide Details )
Access restrictions of an API can be implemented on different levels: whole API, per endpoint, individual operations, or even depending on the executed control flow paths in the implementation of operations or the data accessed. Securing an operation that does many things is complex. The access control list must include the superset of all involved participants; changing it has a significant impact.
Service Rightsizing
- Split Application Backend Logic
(Hide Details )
A major problem when adopting microservices and other approaches to server-side componentization and decomposition is the myth that it is inherently better than a monolith. Inadequate expectations and misunderstandings occur easily. Which evolution and maintenance problems are addressed? Is there an actual need for independent scalability and changeability? What is easier to do in a distributed, service-based system than in a monolith? [@Mendonca:2021]
Simplicity
- Make Request Conditional
(Hide Details )
Knowing when and how long to cache which data might be challenging for API clients and providers. Permanent or temporary storage is required. These valid concerns have to be balanced with the desire for performance.
- Segregate Commands from Queries
(Hide Details )
Keeping the read and write operations of an endpoint together is easy to understand and brings functional endpoint cohesion. A separation of these types of operations increases the ability to change them independently from each other; this can then happen more flexibly and more frequently.
Single Responsibility Principle
- Extract Operation
(Hide Details )
Architectural principles are affected positively or negatively when APIs are refectored. Here, the Purposeful, style-Oriented, Isolated, channel-Neutral, and T-shaped (POINT) principles for API design apply; extracting an endpoint can improve P, O, and I (but might harm T when looking at a single endpoint and not an entire API).
- Move Operation
(Hide Details )
Principles such as single responsibility and independent deployability can guide the selection of refactorings. Some principles are affected positively, others negatively. With respect to the POINT principles for API design (purposeful, style-oriented, isolated, channel-neutral, and T-shaped), moving an operation to another endpoint can improve P, O, and I (but might harm T when looking at a single endpoint and not an entire API). Note that some principles might be defining an architectural style; for instance, statelessness of interactions in REST. Such prominent role makes it even more important to adhere to a principle during design, and stick to its evolution.
- Split Operation
(Hide Details )
An API that offers endpoints with operations that follow the single responsibility principle is easier to understand for clients because operations are focused and do not offer extra capabilities that not all clients use. The API provider team also benefits from a lower complexity of the implementation.
Stability
- Extract Operation
(Hide Details )
Independent endpoints that do not share the same execution context and resources can be deployed independently; operations co-located in a single endpoint, however, share their deployment characteristics. For instance, if a long-running operation causes an API provider-internal error, its sibling operations might suffer from quality-of-service degradations as well. [@Nygard:2018] uses the term stability: “A robust system keeps processing transactions, even when transient impulses, persistent stresses, or component failures disrupt normal processing.”
- Tighten Evolution Strategy
(Hide Details )
Stability has two different meanings according to the arc 42 quality model. Stability at runtime means being free from severe errors that cause interruption of system function. Stability in development means that existing parts can remain largely unchanged when adding new features. API clients welcome both reliability and dependability.
Team Organization
- Distribute Application Frontend
(Hide Details )
Cases in which there is a dedicated team (silo) of designers (such as Web designers or user interface designers) have to be taken into account; while the notion of a “full stack developer” exists that covers frontend and backend development, specializations can also be observed. The specialized teams should communicate well and collaborate intensively (but cannot be assumed to always do). Conway’s Law applies, stating that organizations which design systems produce designs that are copies of the communication structures of these organizations [@Conway:1968; @Vernon:2022]; an adequate organizational fit is a critical success factor. The Team Topologies community and book [@Skelton:2019] elaborate and suggest suited organization structures. An “inverse Conway maneuver” has been proposed by [@Fowler:2022] but also criticized by [@Dupuydauby:2023].
- Merge Endpoints
(Hide Details )
Both well-established [@Conway:1968] and newer literature [@Skelton:2019] emphasizes the impact that team structures and organization charts have on software structure and software quality. “Team Topologies” suggests four types of teams: stream-aligned team, platform team, enabling team, and complicated subsystem team. Assuming that these teams provide and consume APIs, changes to the team organization may cause a need to refactor their APIs.
Testability
- Distribute Application Frontend
(Hide Details )
UI testing includes both logic verification and visual validation. Architectures that combine frontend with backend in one tier make automation harder and increase effort for consistent, isolated UI tests.
- Split Operation
(Hide Details )
Test cases have to cover all, and all combinations of, the many things the operation is in charge of. Testing such an operation is more complex than testing a single-responsibility operation.
Understandability
- Merge Endpoints
(Hide Details )
Fewer endpoints might be easier to understand and maintain—if they are cohesive and do not contain too many operations. The refactorings Move Operation and Rename Operation explain the quality attributes maintainability and understandability further.
- Merge Operations
(Hide Details )
There are many reasons to change an API (not just refactorings) [@StockerZimmermann2021]. APIs should be changed as much as required and as little as possible, and ripple effects be avoided. One of the first steps in related maintenance tasks is to determine which parts of the system should be changed. An API whose endpoints have clearly identified roles helps developers to quickly understand the API.
- Move Operation
(Hide Details )
Endpoints with clearly stated, properly separated concerns and distinguished roles help developers to quickly understand and navigate the API. More documentation has to be studied, but its parts are easier to grasp.
- Rename Endpoint
(Hide Details )
A good name expresses what an endpoint has to offer, which helps clients decide whether and how to use it. The Rename Operation refactoring provides additional explanations of the understandability and explainability qualities.
- Rename Operation
(Hide Details )
All stakeholders involved in development and operations should be able to grasp what an API is supposed to do (and actually does) with ease; it should be straightforward to teach API usage. On the contrary, educated guesses and implicit assumptions are likely to cause misunderstandings that lead to technical risk and defects later on.
- Rename Representation Element
(Hide Details )
A well-chosen name expresses what a representation element (such as a JSON object with its properties) has to offer, which helps clients decide whether and how to use it. The named element has a single meaning and purpose.
- Split Operation
(Hide Details )
An API that offers endpoints with operations that follow the single responsibility principle is easier to understand for clients because operations are focused and do not offer extra capabilities that not all clients use. The API provider team also benefits from a lower complexity of the implementation.
Usability
- Inline Information Holder
(Hide Details )
An API that provides clients all the required data with as few requests as possible may be easier to use than an API where the client has to issue many requests and requires complex state management on the client side to keep track of multiple API calls. See the blog post API Design Review Checklist: Questions Concerning the Developer Experience (DX) for hints on improving the developer experience.
User Experience
- Distribute Application Frontend
(Hide Details )
The easier it is to navigate, provide input, and view output, the better. There may not be a one-size-fits-all user interface for all stakeholders. Supporting different User Interface (UI) paradigms (e.g. desktop, web, mobile) might be necessary. Certain user interface designs might require special hardware.