Sweet API — Syntactic Sugar and You

sweet-api-syntactic-sugar-and-you-nordic-apisThe internet is bar none the most effective and amazing tool for connecting people. What it’s historically not, however, is an effective and amazing tool for connecting people with systems. While networks form and information is shared, the underlying systems have historically been hidden underneath complex code and abstraction.

Enter syntactic sugar, a syntax that removes a lot of complexity for the average developer, all while making the ever-present layer of abstraction more transparent. Incorporating syntactic sugar into development can bridge the gap between system and user, creating a digestible and and understandable language that empowers users and developers alike.

What is Syntactic Sugar

Syntactic sugar is best described simply as a syntax that moves machine readable code towards human digestibility. Part of the issue with coding is that the developer is fundamentally instructing a machine to do certain functions — because of this, the code underneath the system is typically made for machines, not people, to understand.

In order to move the focus on understandability towards the human end of the digestibility scale, developers have often focused on clarifying functionality through language adoption. In 1964, Peter J. Landin coined the term “syntactic sugar” when he described the syntax of an ALGOL-like language he worked within. By replacing the lambda symbol (λ) with the alias “where”, Landin greatly simplified the language construct, while not removing any of the basic and essential constructs.

This, then, is the essence of syntactic sugar — clarifying and simplifying processes without removing or altering the fundamental structures therein.

As a simple example, consider the mathematical operation “lhs.Add(rhs)”. To the layman, this operation is confusing — even if meaning could be abstracted from it, the punctuation, structure, and organization is needlessly complex, especially when looking at a large group of such operations.

The above operation could be easily simplified, however, to the following function — “lhs + lrs”. By looking at the new operation, the user immediately understands exactly what the operation is doing, and can more easily communicate this function to others, utilize it in their own code, and even modify it for extended functionality.

This balancing of human and machine digestibility comes at a cost, however — while there are many benefits, perhaps enough to warrant a developer’s inclusion of syntactic sugar conceptualization during development, there are many drawbacks as well.

Benefits of Syntactic Coding

One of the biggest benefits of syntactic sugar is the obvious increase in human readability. By shifting away from complex syntax and towards more simple, understated, and clear operations, code is simplified dramatically.

This has the added benefit of making development by novice users and fork developers a much easier process. When an API is more clearly explained and the processes within better documented, the API can be more easily transformed and extended. As more and more advanced constructs are implemented and supported, and the use of Hypermedia expands, this understandability has only become more and more important.

Likewise, this has great benefits when troubleshooting with and experimenting on the base code. With clarity comes simplicity, and having well commented code that is easily understood means that issues can be more clearly identified before they enter production, and once in production, can be more easily pinpointed as the root cause of an issue.

More to the point, syntactic sugar removes a lot of confusion, even within the development team. When syntax is abstracted into an easier to understand format, functional elements and classes that are similar in structure but different in function are harder to confuse and conflate with one another, making debugging and understanding a far easier affair.

The biggest benefit comes not from what syntactic sugar does do, but instead what it doesn’t do. Syntactic sugar doesn’t change the interaction between the machine and the code, and the consumer can always use the base code if preferred. It would be one thing if a developer utilizes a low-adoption or questionable language for the sake of brevity and clarity, because in this case, they would lose just as much, if not more, as they gained.

By adopting syntactic sugar, however, nothing is technically lost — humans can read the code more easily, and machines can utilize the same operations utilizing the same base code. When paired with API Gateways, an API can be made simple, yet deceptively powerful.

Drawbacks of Syntactic Coding

Syntactic sugar isn’t all brevity and clarity, however — while the case for adoption of syntactic sugar is rather robust, there are a good deal of drawbacks inherent in the approach.

Prime of these is the fact that syntactic sugar, despite simplifying the codebase for the reader on first glance, has the potential to overly complicate the languages and systems utilized by developers. If not approached and documented correctly, syntactic sugar can result in a more complex, less standardized variant on a language that forces the user to relearn a lot of what they already know, even if what they do need to learn is easier to understand.

This can’t be overstated as a significant caveat — employing syntactic sugar means there is yet another new thing for the developer to learn. Even if the syntax is simpler, any developer worth their salt will still want to learn the underlying code that it’s being abstracted from, adding yet another layer. What they lose in initial learning time, they make up for in use, but it is still a significant initial time sink that must be considered.

There are a great deal of developers who have spoken out against syntactic sugar, not the least of which was Alan Perlis, a major contributor to the early development of computer programming. When speaking on bracket-delimited languages in his “Epigrams on Programming”, he said:

“Syntactic sugar causes cancer of the semi-colons”.

What Perlis was referring to is the fact that syntactic sugar can cause issues with parsability when porting between languages. He argued that given the deluge of already easy to understand languages, syntactic sugar could be considered frivolous and wasteful. Some languages even already support syntactic sugar, such as RAML, negating the need for custom syntactic sugar.

Additionally, there is concern about the complexity and length of documentation when syntactic sugar is employed. As more syntax is created and abstracted, each addition needs to be documented, extending the length of documentation, and accordingly, the effort required to maintain and correct documentation throughout the lifecycle of the language or API.

Examples

To better understand how syntactic sugar influences the codebase after adoption, let’s look at some implementations, both from the perspective of the developer and of the consumer.

Developer Examples

In COBOL, a simple syntactic sugar operation can be seen in the modification of the move operation:

MOVE A B

When clarified under syntactic sugar, the operation changes to this:

MOVE A TO B

While this is a rather simple example, the simple addition of “TO” to the operation clarifies the relation between A and B, specifically showing that A is the point of origination, and B is the destination.

This might seem like a small thing, but when you are faced with a codebase of several hundred thousand lines of code, having lucid operations is very important and helpful.

Clarification isn’t all syntactic sugar does, however — it can also shorten functions while clarifying their purpose. Take the following mathematical function constrainment:

if x then y else false

To the average developer, the function is relatively easy to understand. For a new developer however, or a developer used to alternative mathematical operation syntaxes, this might be confusing.

When implemented under syntactic sugar, that operation is greatly simplified:

x and y

This simple reduction in length specifies in no uncertain terms that x and y are required. The reduction in length here is vastly more important than the loss of verbosity with the “else false” result, and for many programmers, the understanding between “and” and “or” operations is pretty universal.

This can be seen even better in the reduction of the following mathematical operation:

(lam(v1 : typof(x1), ..., vn : typeof(xn)) { body })(x1, ..., xn)

When reduced, the operation turns into a simple operation:

let v1 = x1, …, vn=xn

Anyone familiar with mathematics can instantly understand what this sequence means, and with greater ease than the original operation to boot.

Finally, we can look at the PERL implementation of a conditional statement:

if(not condition) {...}

While this is somewhat easy to understand, the phrasing “not condition” is somewhat strange on the tongue. When constrained under syntactic sugar, we get:

unless(condition) {...}

This makes it clear the following only occurs in the absence of the stated condition. Unless is easy to understand — and far easier to understand over “not condition”.

Consumer Examples

While at first the average user might not experience too much of a change from simple operators to even more simplified operators through syntactic sugar, the main benefits appear with larger codebases.

As the codebase grows, the ability to see the “bigger picture” and understand each individual operation and how it functions is often lost. By simplifying operations and clarifying the language therein, getting lost in the complexity becomes a feat in and of itself.

Additionally, the benefits added when troubleshooting aren’t readily apparent, but when a user troubleshoots errors in their code and interactions, syntactic sugar very quickly makes its benefits known.

Imagine, for a moment, a user accessing an API that converts audio format from high bitrate FLAC streams to compressed 320kbps MP3s. When thousands of lines of code aren’t clear in exactly how the stream is established, in what situations certain operations occur (especially in the case of “if” and “unless”), and how data is moved, the code becomes needlessly complex and hard to understand.

The user very quickly runs into a situation where needless complexity results in a failure to understand where exactly a point of failure occurs. By specifying the exact function of the operation, the user can capture the audio conversion midstream, recognize the error, and rectify it — with minimal knowledge of the complexities under the hood, so to speak.

Syntactic sugar is essentially an approach for consumers — while it improves the development experience to a point, the clarity and explanatory nature of syntactic sugar makes it easier for consumers and exterior developers to utilize the code.

An Age Old Argument

Whether or not to adapt syntactic sugar is an age old argument that ultimately comes down to personal choice between two distinct approaches, both with ample benefits and drawbacks.

Sugary APIs are more easily consumable by their very nature, and are thus more apt for new developers and users. Syntactic sugar makes code easier to understand, implement, transform, and conceptualize for the average user. Unfortunately, this comes at the cost of added abstraction and loss of standardization.

The question comes to one of size and standardization over understandability. If small codebase size and standardization is your choice, then forgoing syntactic sugar is a good choice, even though it makes the language more complex.

If understandability and conciseness of codebases is more important, however, syntactic sugar is a wonderful choice, and should be implemented.