Rename Representation Element

Updated:

 Note: This is a preview release and subject to change. Feedback welcome! Contact Information and Background (PDF)

also known as: Rename Payload Part, Rename Parameter

Context and Motivation

The operation in an API endpoint expects data from clients and/or delivers data to them. The data representations are structured, and certain parts of the structural elements are named (for instance, keys in key-value pairs or type definitions).

As a data modeler and/or Data Transfer Object (DTO) designer, I want to use expressive and domain-specific terminology so that data representations and their elements become self-explanatory to API developers on the client as well as on the provider side.

Stakeholder Concerns (including Quality Attributes and Design Forces)

#understandability (a.k.a. #explainability, #learnability)
A good name expresses what a representation element (such as a JSON object and its properties) has to offer, which helps clients decide whether and how to use it. It has a single meaning and purpose. Move Operation provides a deeper explanation of this quality.
#maintainability
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. Move Operation also covers this quality in more detail.

Initial Position Sketch

Let us assume the following simple endpoint design (notation: abstract MDSL):

endpoint type Endpoint1
exposes 
  operation operation1 
    expecting payload {"v1":D<string>, "v2":D<int>}* 
    // no delivering here

As the sketch shows, the refactoring targets a single endpoint and one of its operations. Presumably, the v in v1 and v2 stands for “value”, but this does not get clear from the rather terse one-letter, one-number acronyms v1 and v2.

Smells / Drivers

Curse of knowledge
The “curse of knowledge” phenomenon is that “the more you know, the less clearly you write”. A certain name may be easy to comprehend — but only for the developers of the API implementation on the provider side. On the contrary, client developers miss required context information (see Rename Operation).
Cryptic or misleading name
The chosen element name is difficult to understand for stakeholders who are not familiar with the API implementation. For instance, it might not be part of the agreed upon domain vocabulary or unveil implementation details such as column names in database tables. It might also be overloaded with different meanings (in the same context).
Security by obscurity
Sometimes it is argued that unlabeled, undocumented data is harder to tamper with. But such tactic alone does not qualify as a sound security solution, and harms maintainability because it increases the risk of introducing bugs because of lack of clarity not only for attackers but also for maintainers.
Change log jitter or commit chaos
The name has been, and continues to be, changed frequently according to the logs kept by the version control system. This indicates that the domain language is not stable yet, or has not been defined, communicated, and agreed upon sufficiently yet.
Leaky encapsulation
Program internal names or identifiers might accidentally have leaked into the API. For example, the initial API could have been generated from internal classes. Such internal names might be hard to understand for API clients; they might even introduce security threats.

Instructions (Steps)

This refactoring is rather straightforward to apply:

  1. Discuss alternative new names and decide for one. Have this decision reviewed and agreed upon.
  2. Apply code-level rename refactorings; do not forget to update code-level comments when doing so. If the code is generated from a specification, update the API design specification and then re-generate the code.
  3. Update API tests and API description/documentation.1

Several strategies for backwards compatibility exist. The implementation could continue to accept the old names as well. However, this approach can quickly become unwieldy if many such changes accumulate over time. By applying the Introduce Version Identifier and Introduce Version Mediator refactorings, clients can continue using the old names that will then get translated by the version mediator to the new names.

Target Solution Sketch (Evolution Outline)

The element names v1 and v2 in the initial position have been replaced by customerName and customerName in this MDSL sketch:

endpoint type Endpoint1
exposes 
  operation operation1 
    expecting payload {"customerName":Data<string>, "customerName":Data<int>} 
    // no delivering here

Arguably, customerName is more expressive and precise than v1, unless the representation element is a simple loop counter (which does not seem to be the case). This makes the new name easier to understand. We assume that a common understanding of the term “customer” has been reached, at least within a certain context and community.

Example(s)

In the Policy Management backend of the Lakeside Mutual sample application, we find a Data Transfer Object (DTO) called InsuranceQuoteDto, which is exposed in the Web API that is provided by a RESTful HTTP controller:

public class InsuranceQuoteDto {
    @Valid
    @NotNull
    private Date expirationDate;

    @Valid
    @NotNull
    private MoneyAmountDto insurancePremium;

    @Valid
    @NotNull
    private MoneyAmountDto policyLimit;

    [...]
}

The DTO name InsuranceQuoteDto as well as expirationDate, insurancePremium, and policyLimit are expressive names; names such as inputData, until, and amount would be less domain-specific and could be renamed with this refactoring.

One could argue that acronyms and technical jargon should be avoided. Removing Dto from the name in a refactoring would make the name shorter and cleaner, but also hide the architectural role played by the class. In this particular case, the acronym is explained in a comment in the source code.

Hints and Pitfalls to Avoid

When choosing names, keep in mind that good names should:

  • Adhere to the conventions of the interface specification and/or programming language in use.
  • Reveal the purpose/intent of the named element.
  • Be intelligible, so they do not need to be deciphered first.
  • Be simple and short.
  • Be pronounceable so that they can be talked about.

When applying this refactoring, one should promote a controlled amount of domain vocabulary into the published language of the API. Optionality and value ranges should be explained in the API documentation (for instance, inline comments and specification documents). Implementation-level data structures should be wrapped, hiding as much detail as possible. The reuse of existing data structures and vocabularies may be considered if that is permitted, for instance microformats or schema.org.2

It makes sense to avoid technical jargon (in particular jargon that might go out of fashion soon or has a different meaning in other communities already). Abbreviations should be avoided in names unless they are very common in the API stakeholder community. Mapping implementation-level data structures one to one introduces undesired tight coupling between API and implementation and should therefore be avoided.

Representation elements can be grouped by applying Introduce Data Transfer Object. Rename Operation and Rename Endpoint are also available to rename API parts with a larger scope. The Id Element pattern makes naming suggestions (for instance, regarding uniqueness) and provides pointers to additional information. Data Element is the general pattern for any kind of representation element.

“API Handyman” Arnaud Lauret provides many examples and counter examples in his book [Lauret 2019] and the online API Stylebook. “The Art of Readable Code” [Dustin Boswell 2011] has helpful hints on naming program elements that also apply to APIs.

The blog post “A Definition of Done for Architectural Decisions” presents five criteria to assess whether a decision such as a name change has been elaborated upon sufficiently: evidence, criteria, agreement, documentation, and realization/review. Applying this refactoring often is the result of a review, and a new name then has to be decided upon.

References

Dustin Boswell, Trevor Foucher. 2011. The Art of Readable Code. O’Reilly Media, Inc.

Lauret, Arnaud. 2019. The Design of Web APIs. Manning.

  1. Step 3 applies to all refactorings and is part of the general Test, Explain, Let Know and Learn (TELL) activities to enact and evaluate refactorings. TELL is featured on the Content Overview page. 

  2. Example: how should we name the attribute to store a user address? Easy, just use https://schema.org/PostalAddress