diff --git a/www/content/essays/two-types-of-decoupling.md b/www/content/essays/two-types-of-decoupling.md index 84923f66..a0e2e111 100644 --- a/www/content/essays/two-types-of-decoupling.md +++ b/www/content/essays/two-types-of-decoupling.md @@ -12,26 +12,188 @@ updated = 2023-02-03 _-Roy Fielding, _ -Decoupling is the opposite of [coupling](https://en.wikipedia.org/wiki/Coupling_(computer_programming)), where two -pieces of software have a high degree of _interdependence_. Decoupling software is the act of reducing this -interdependence between unrelated modules so that they can evolve independently. The concept of coupling and decoupling -is closely (and inversely) related to [cohesion](https://en.wikipedia.org/wiki/Cohesion_(computer_science)). A highly -cohesive software module has related logic within a module or conceptual boundary, rather than spread out. Broadly, -the more decoupled your codebase is, the more cohesive it will be as well. Developers generally have a sense that -decoupling is a good thing +## Summary -An argument we see at times for the JSON/Data API style of development, where a Single Page Application-style web -applications communicates with a back end via a JSON API, is that this architectural choice _decouples_ the front-end and -back-end code, and allows re-use of the JSON API in other contexts, such as a mobile application. +A JSON API decouples a web application's front end and back end code. Hypermedia APIs, on the other hand, +tightly couple front end and back end code. Despite this tighter _application level_ coupling, hypermedia APIs can +be changed much more freely than JSON APIs without breaking web applications. +This surprising result is due to the _system level_ decoupling achieved via REST/HATEOAS. +## Coupling & Decoupling In Software -You can imagine how creating a general JSON Data API that can be consumed by multiple clients would _decouple_ your -application's back-end code from a particular client: it provides a standard, well documented API and any client that wants -to can use that is welcome to do so. +*De*coupling is the opposite of [coupling](https://en.wikipedia.org/wiki/Coupling_(computer_programming)). Coupling +is the (generally bad) property of a software system where two pieces of software have a high degree of _interdependence_. +Decoupling software is the act of reducing this interdependence between unrelated modules so that they can evolve independently +from one another. -In the second part of this essay we are going to talk about the hypermedia approach, and how it decouples your system in -a different manner than the way a generic Data API does. But, before we get into that, we want to spend a bit of time and -look at the facts on the ground with respect to JSON APIs and see how decoupling is working out. +The concept of coupling and decoupling is closely (and inversely) related to +[cohesion](https://en.wikipedia.org/wiki/Cohesion_(computer_science)). Highly cohesive software has related logic +within a module or conceptual boundary, rather than spread out all over the place. (A related concept is our own idea +of [Locality of Behavior](/essays/locality-of-behaviour/)) -## "The Worst Part Of My Job..." \ No newline at end of file +Broadly, the more decoupled your codebase is, the more cohesive it will be as well and the better it will +handle change over time. + +## JSON APIs - Application Level Decoupling + +An argument for a JSON/Data API for your web application (typically accessed via a reactive Single Page Application +framework) is that this architecture _decouples_ the front-end and back-end code. This allows the re-use of the JSON +API in other contexts, such as a mobile applications, 3rd party client integrations and so on. + +The generic JSON/Data API provides _application level_ decoupling: you are effectively developing two different applications, +a front end that consumes a JSON API and a back end that produces one, thus imposing independence on them. + +This is certainly a valid approach to decoupling two pieces of software. The JSON API provides a "hard" interface between +the two pieces of software, making it difficult, at least in theory, to introduce coupling between them. + +But how does this approach work out in practice? + +### "The Worst Part Of My Job..." + +In our essay [Splitting Your Data & Application APIs: Going Further](https://htmx.org/essays/splitting-your-apis/) you +will find the following quote: + +> The worst part of my job these days is designing APIs for front-end developers. The conversation goes inevitably as: +> +> Dev – So, this screen has data element x,y,z… could you please create an API with the response format {x: , y:, z: } +> +> Me – Ok +> +> Jean-Jacques Dubray - + +This quote shows that, although we have driven coupling out with a pitchfork (or, in our case, a JSON API) it has come +back through application-specific JSON end point requests. These sorts of requests end up *re*coupling your front end and +back end code: you are no longer providing a *generic* JSON Data API, but rather a *specific* API for your front end needs. + +What is worse, your front end needs will likely change frequently as your application evolves, necessitating the modification +of your JSON API. But what if *other* clients have come to depend on the original API? You can start versioning your +JSON API, but that becomes complicated as the application complexity grows and changes pile up. + +Do you really want to version your JSON API every time a screen changes a field in your web application? + +#### GraphQL To The Rescue? + +One potential solution to this problem is to introduce [GraphQL](https://graphql.org/), which allows you to have a much +more expressive JSON API. This means that you don't need to change it as often when application needs change. + +While this is a reasonable idea for addressing the problem outlined above, there are problems with it. The biggest +issue that we see is security, as we outline this in [The API Churn/Security Trade-off](https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html) essay. + +Apparently facebook uses a [whitelist](https://twitter.com/AdamChainz/status/1392162996844212232) to deal with the security +issues introduced by GraphQL, but many developers appear to not understand the security threats involved with it. + +#### Splitting Your Application & General Data APIs + +Another approach recommended by [Max Chernyak](https://max.engineer/) in his article +[Don’t Build A General Purpose API To Power Your Own Front End](https://max.engineer/server-informed-ui), is two build +*two* JSON APIs: + +* An application specific JSON API that can be modified as needed +* A general purpose JSON API that can be consumed by other clients such as mobile, etc. + +This is a pragmatic solution to address what appears to be _inherent_ coupling between your web application's front end +and the back end code supporting it. + +## Hypermedia - Network Architecture Decoupling + +Now let's consider instead a _hypermedia API_. A hypermedia API is nothing more than an API that returns hypermedia, +say HTML, rather than a non-hypermedia format, say JSON. The World Wide Web is built on top of hypermedia APIs being +accessed by hypermedia clients, that is, web browsers. + +(It may sound strange, but, yes, every HTML web page you access is delivered as a result of an API request!) + +Now, consider a potential response to a simple `GET` for a page, say, `https://example.com/account/12345`: + +```html +HTTP/1.1 200 OK + + + +
Account number: 12345
+
Balance: $100.00 USD
+
Links: + deposits + withdrawals + transfers + close-requests +
+ + +``` + +If you look at this response from the perspective of coupling, well, this response _could not be more coupled_ to the +front end. In fact, the response almost *is* the front end, isn't it? We not only have the _data_ about that account +in this response, we also have all this other junk for laying out the (admittedly spartan) user interface. + +So here we have a tight coupling between the front end and back end. Bad, right? + +### REST & HATEOAS + +Well, maybe not so much. Let's say we remove the ability to transfer money from our bank to other banks, or close +accounts. (This seems like a hot topic recently!) + +What does our hypermedia response for this `GET` request now look like? + +```html +HTTP/1.1 200 OK + + + +
Account number: 12345
+
Balance: $100.00 USD
+
Links: + deposits + withdrawals +
+ + +``` + +You can see that in this response, those two actions have been removed from the HTML. The browser simply render the +new state of affairs to the user, and all is well. To a rounding error, there are no clients sitting around using the +_old_ API. People log in, see the new state of affairs, and perhaps being some panicked calls to the bank. + +Note that we don't have to version our API, because all API navigation of our hypermedia system is done through +HTML returned by that system. This means we can dramatically change our API without breaking our clients. + +This flexibility is the crux of the REST-ful network architecture and, in particular, [HATEOAS](/essays/hateoas/). + +### Decoupling At The Network Architecture Level + +So why, if the JSON API is _decoupled_ and the hypermedia API is _tightly coupled_, is it easier to change the hypermedia +API than the JSON API? + +It is easier to change the hypermedia API because there _is_ decoupling, but it is happening at a _lower level_. In +a hypermedia system we accept the coupling between our application's front end and back end code, and we optimize for +that coupling by _decoupling_ in our system's architecture, rather than at the application layer. + +A browser is decoupled from a particular web application by a general understanding of hypermedia: it just knows how to +retrieve and render hypermedia, and offer users actions based on hypermedia controls. _This_ decoupling allows for +a level of flexibility (and coupling!) in your software that a JSON API simply can't provide. + +### But That's A Terrible (Data) API! + +Some people, when presented with the above argument, note that this hypermedia API may be flexible for our web application, +but it makes for a terrible general purpose API. + +This is very true. Our hypermedia API is tuned for *our* hypermedia driven application. No one wants to be downloading +parts of it (which might disappear tomorrow, note that we don't even document it!) and parsing HTML and trying to yank +information out of it. + +This is exactly why we recommend creating a general purpose JSON API _alongside_ your hypermedia API in +[Splitting Your Data & Application APIs: Going Further](https://htmx.org/essays/splitting-your-apis/). You can +take advantage of the flexibility of a hypermedia API (and system) for your own web application, while providing a +general purpose JSON API for mobile applications, third party applications, etc. + +(Although, we should mention, a [hypermedia-based mobile application](https://hyperview.org) might be a good choice too!) + +## Conclusion + +In this essay we looked at two different types of decoupling: + +* Application level decoupling via a JSON Data API +* System-level decoupling via REST/HATEOAS in a hypermedia system + +And we showed that, despite tighter application-level coupling, the hypermedia approach appears to be easier to evolve +and adapt to change. \ No newline at end of file