<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Manuel Vila</title>
    <description>The latest articles on Forem by Manuel Vila (@mvila).</description>
    <link>https://forem.com/mvila</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F94131%2F8cf57f27-b785-484b-a00a-820d3aa74c93.jpeg</url>
      <title>Forem: Manuel Vila</title>
      <link>https://forem.com/mvila</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mvila"/>
    <language>en</language>
    <item>
      <title>Layr v2 Is Out, but You May Never Use It</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Fri, 13 Jan 2023 00:04:13 +0000</pubDate>
      <link>https://forem.com/mvila/layr-v2-is-out-but-you-may-never-use-it-34ja</link>
      <guid>https://forem.com/mvila/layr-v2-is-out-but-you-may-never-use-it-34ja</guid>
      <description>&lt;p&gt;Finally, after two years of hard work, &lt;a href="https://layrjs.com"&gt;Layr v2&lt;/a&gt; is out.&lt;/p&gt;

&lt;p&gt;Actually, Layr v2 was published on NPM a year ago, but I haven't announced it because I needed to achieve three important things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documented the new features.&lt;/li&gt;
&lt;li&gt;Created a CLI for Layr, which turned out to be a companion tool called &lt;a href="https://boostr.dev"&gt;Boostr&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Rewrote the &lt;a href="https://layrjs.com/docs/v2/introduction/hello-world"&gt;"Hello, World"&lt;/a&gt; tutorial and updated all the &lt;a href="https://layrjs.com/docs/v2/introduction/introduction?language=ts#examples"&gt;app examples&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all done, and I can now officially announce the release of Layr v2. However, as I will explain later, you may never use it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please check out my &lt;a href="https://dev.to/mvila/good-bye-web-apis-2bel"&gt;previous article&lt;/a&gt; if you've never heard of Layr.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What's New?
&lt;/h2&gt;

&lt;p&gt;Here are the most notable new features in Layr v2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/sanitizer"&gt;Attribute sanitization&lt;/a&gt;: When you assign a new value to an attribute, this value can be automatically sanitized with some built-in (e.g., &lt;code&gt;trim()&lt;/code&gt;) or custom sanitization functions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/component#attribute-value-assignment"&gt;Attribute value assignment&lt;/a&gt;: You can now change the value of multiple attributes at once thanks to the component &lt;code&gt;assign()&lt;/code&gt; class and instance methods.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/method#constructor"&gt;Method scheduling&lt;/a&gt;: Class methods have a new &lt;code&gt;schedule&lt;/code&gt; option to specify that a class method should be repeatedly called with a fixed time delay between each call.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/method#constructor"&gt;Method queuing&lt;/a&gt;: Class and instance methods have a new &lt;code&gt;queue&lt;/code&gt; option to specify that a method should be executed in the background.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Routing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/wrapper"&gt;Wrappers&lt;/a&gt;: A wrapper can be associated with a component class or instance method to wrap any method associated with a route using this wrapper. Thanks to wrappers, you can, for example, easily nest your pages into layouts.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/routable#route-decorator"&gt;Component instance routes&lt;/a&gt;: Before, routes could only be associated with component class methods. Now, you can associate routes with component instance methods as well.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/addressable#url-pattern-type"&gt;Catch-all routes&lt;/a&gt;: You can now suffix a route URL pattern with a wildcard (&lt;code&gt;'*'&lt;/code&gt;) to define a route that will be used when no other routes match the current URL. A typical use case is to define a route for displaying a "Not found" page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  React Integration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/react-integration#page-decorator"&gt;&lt;code&gt;page()&lt;/code&gt;&lt;/a&gt;: A decorator that combines the &lt;a href="https://layrjs.com/docs/v2/reference/routable#route-decorator"&gt;&lt;code&gt;route()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://layrjs.com/docs/v2/reference/react-integration#view-decorator"&gt;&lt;code&gt;@view()&lt;/code&gt;&lt;/a&gt; decorators.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/react-integration#layout-decorator"&gt;&lt;code&gt;layout()&lt;/code&gt;&lt;/a&gt;: A decorator that combines the &lt;a href="https://layrjs.com/docs/v2/reference/routable#wrapper-decorator"&gt;&lt;code&gt;wrapper()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://layrjs.com/docs/v2/reference/react-integration#view-decorator"&gt;&lt;code&gt;@view()&lt;/code&gt;&lt;/a&gt; decorators.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/react-integration#use-data-react-hook"&gt;&lt;code&gt;useData()&lt;/code&gt;&lt;/a&gt;: A hook for loading data asynchronously and rendering a React element using these data.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://layrjs.com/docs/v2/reference/react-integration#use-action-react-hook"&gt;&lt;code&gt;useAction()&lt;/code&gt;&lt;/a&gt;: A hook for executing some asynchronous actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Command-Line Interface
&lt;/h3&gt;

&lt;p&gt;Layr got a companion tool called &lt;a href="https://boostr.dev"&gt;Boostr&lt;/a&gt; for taking care of everything you need to build and deploy your apps.&lt;/p&gt;

&lt;p&gt;You can check out the revised &lt;a href="https://layrjs.com/docs/v2/introduction/hello-world"&gt;"Hello, World"&lt;/a&gt; tutorial to see Boostr in action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Breaking Changes
&lt;/h3&gt;

&lt;p&gt;Layr v2 includes some breaking changes that I will not describe here because, to my knowledge, nobody (except me) has built apps with Layr v1 for production use. Please &lt;a href="//mailto:hi@mvila.me"&gt;let me know&lt;/a&gt; if it's not the case.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Some work remains to be done in the documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some additional tutorials to cover all the basic features of Layr.&lt;/li&gt;
&lt;li&gt;A "Concepts" section to introduce the fundamental concepts behind Layr.&lt;/li&gt;
&lt;li&gt;A "Guides" section to explain how the most common features of an app could be implemented with Layr.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, writing documentation takes a lot of time, and the Layr project is currently only handled by me, who has to work for customers to make a living and is also starting a new ambitious project called &lt;a href="https://www.1place.app"&gt;1Place&lt;/a&gt;, which will be based on Layr.&lt;/p&gt;

&lt;p&gt;I need to raise money for 1Place, and if everything goes well, I should be able to hire talents to work on 1Place, and, indirectly, fuel the development of Layr.&lt;/p&gt;

&lt;p&gt;Also, to build 1Place, some critical features should be added to Layr, such as component subscription and polymorphic storage, which will probably lead to additional breaking changes and a v3 release.&lt;/p&gt;

&lt;p&gt;In the current situation, the future of Layr depends on 1Place. If 1Place fails, I'm certainly not going to give up on Layr, which I really care about, but its development will likely be slowed down.&lt;/p&gt;

&lt;p&gt;So, for all these reasons, unless you feel very adventurous, I can't recommend building your next app with Layr v2 today.&lt;/p&gt;

&lt;p&gt;You may wonder why I am announcing a new version while telling you not to use it. Well, I just felt I had to keep the few people who follow Layr's development informed.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>Some Thoughts on React Server Components</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Wed, 23 Dec 2020 01:38:18 +0000</pubDate>
      <link>https://forem.com/mvila/some-thoughts-on-react-server-components-obd</link>
      <guid>https://forem.com/mvila/some-thoughts-on-react-server-components-obd</guid>
      <description>&lt;p&gt;The React team unveiled yesterday a new experiment called &lt;a href="https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html"&gt;React Server Components&lt;/a&gt;, and I must say I'm pretty excited about it.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://twitter.com/dan_abramov"&gt;Dan Abramov&lt;/a&gt;, for saying that GraphQL is not for everyone. Thanks to the React team for looking for solutions to build web apps without web APIs and daring to challenge the status quo.&lt;/p&gt;

&lt;p&gt;A few weeks ago, I wrote &lt;a href="https://dev.to/mvila/good-bye-web-apis-2bel"&gt;an article&lt;/a&gt; to defend the idea that it is possible to create single-page apps without building a web API to connect the frontend and the backend. I believe this article was as much loved as it was hated.&lt;/p&gt;

&lt;p&gt;On the one hand, there are all the developers who are tired of developing web APIs and welcome all the solutions to get rid of them.&lt;/p&gt;

&lt;p&gt;On the other hand, there are many developers who think that web APIs are necessary and that it's a shame to want to do without them.&lt;/p&gt;

&lt;p&gt;Of course, no one is absolutely right or wrong. It depends on what you build.&lt;/p&gt;

&lt;p&gt;I think a lot of web apps can live very well without a web API. But there is also a significant number of apps for which a web API can be very beneficial.&lt;/p&gt;

&lt;p&gt;So, congrats to the React team for considering both cases and looking for a solution for those who are in the "API-less" camp.&lt;/p&gt;

&lt;p&gt;React Server Components allow to abstract away the runtime environment where the views are rendered. Any view can be rendered in the frontend, the backend, or both, and from the developer's perspective, it doesn't matter. The developer can write an application as if the frontend and the backend were a single entity.&lt;/p&gt;

&lt;p&gt;This approach appeals to me because it is in line with one of my biggest obsessions. Indeed, with &lt;a href="https://github.com/layrjs/layr"&gt;Layr&lt;/a&gt; I'm trying to achieve the same thing — to bring the frontend and the backend together.&lt;/p&gt;

&lt;p&gt;What makes Layr and React Server Components different is the nature of what is transported between the frontend and the backend. Layr transports models while React Server Components transport views.&lt;/p&gt;

&lt;p&gt;I think that transporting the models eventually offers more possibilities because the views remain entirely in charge of the frontend and it is, therefore, easier to create multiple frontends for different platforms (web, mobile, desktop, etc.).&lt;/p&gt;

&lt;p&gt;However, it is possible to imagine that React Server Components could also be used to build React Native apps. We would then have a backend capable of generating views for React Native. At first glance, the idea may seem crazy, but why not?&lt;/p&gt;

&lt;p&gt;Anyway, all this reinforces my belief that the "API-less" approach is more and more a thing.&lt;/p&gt;

&lt;p&gt;Thank you, React, for continuing to innovate. Removing the API layer is not a small deal. It is a huge architectural shift.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>Good Bye Web APIs</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Mon, 23 Nov 2020 20:26:17 +0000</pubDate>
      <link>https://forem.com/mvila/good-bye-web-apis-2bel</link>
      <guid>https://forem.com/mvila/good-bye-web-apis-2bel</guid>
      <description>&lt;p&gt;When building a &lt;a href="https://en.wikipedia.org/wiki/Single-page_application" rel="noopener noreferrer"&gt;single-page application&lt;/a&gt; or a mobile application, we usually need to implement a web API (REST, GraphQL, etc.) to connect the frontend and the backend. Technically, it's not very difficult, but it has some unfortunate consequences.&lt;/p&gt;

&lt;p&gt;Imagine two planets. The planet "frontend" speaks JavaScript and the planet "backend" also speaks JavaScript or any other advanced language.&lt;/p&gt;

&lt;p&gt;Now let's say that these planets need to collaborate extensively to form a whole called "application".&lt;/p&gt;

&lt;p&gt;Unfortunately, the planets are unable to communicate with each other directly using their native language and they have to rely on a third party called "web API" which speaks a much less sophisticated language.&lt;/p&gt;

&lt;p&gt;Indeed, the language of most web APIs is limited to a combination of URLs, a few HTTP verbs (GET, POST, DELETE, etc.), and some JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4jf4ioy2841npvbihshz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4jf4ioy2841npvbihshz.png" alt="Frontend + Web API + Backend"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The web APIs that speak GraphQL are more advanced but they remain far behind the possibilities of a programming language such as JavaScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The programming paradigm is procedural or functional (no object-oriented programming).&lt;/li&gt;
&lt;li&gt;Only the most basic types are supported (forget about Date, Map, Set, etc.).&lt;/li&gt;
&lt;li&gt;The concept of reference is missing (you can only pass objects by value).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Placing a rudimentary language between the frontend and the backend adds a lot of boilerplate and ruins the development experience.&lt;/p&gt;

&lt;p&gt;Another problem is that a web API is an extra layer to worry about. It must be designed, implemented, tested, documented, etc. And all this is frankly a pain in the ass.&lt;/p&gt;

&lt;p&gt;But the worst thing is that building a web API generally forces you to degrade the quality of your codebase. Indeed, it's quite challenging to keep your code DRY and cohesive when your frontend and your backend are separated by a web API.&lt;/p&gt;

&lt;p&gt;Now imagine that we could get rid of the web API. Imagine that the frontend could communicate directly with the backend using its native language. Wouldn't it be great?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fggelge7utvo2cbpgte2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fggelge7utvo2cbpgte2l.png" alt="Frontend + Backend"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The good news is that it's possible today thanks to a set of libraries called &lt;a href="https://github.com/layrjs/layr" rel="noopener noreferrer"&gt;Layr&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello, Layr!
&lt;/h2&gt;

&lt;p&gt;With &lt;a href="https://github.com/layrjs/layr" rel="noopener noreferrer"&gt;Layr&lt;/a&gt;, the frontend and the backend are &lt;em&gt;physically&lt;/em&gt; separated (they run in different environments) but &lt;em&gt;logically&lt;/em&gt; reunited (it's as if they were in the same environment).&lt;/p&gt;

&lt;p&gt;How does it work?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The backend is composed of one or more classes whose some of their attributes and methods are explicitly exposed to the frontend.&lt;/li&gt;
&lt;li&gt;The frontend generates some proxies to the backend classes and can use these proxies as if they were regular JavaScript classes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Under the hood, Layr relies on an &lt;a href="https://en.wikipedia.org/wiki/Remote_procedure_call" rel="noopener noreferrer"&gt;RPC&lt;/a&gt; mechanism. So, superficially, it can be seen as something like &lt;a href="https://en.wikipedia.org/wiki/Common_Object_Request_Broker_Architecture" rel="noopener noreferrer"&gt;CORBA&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Java_remote_method_invocation" rel="noopener noreferrer"&gt;Java RMI&lt;/a&gt;, or &lt;a href="https://en.wikipedia.org/wiki/Windows_Communication_Foundation" rel="noopener noreferrer"&gt;.NET CWF&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But Layr is radically different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's not a &lt;a href="https://en.wikipedia.org/wiki/Distributed_object" rel="noopener noreferrer"&gt;distributed object system&lt;/a&gt;. A Layr backend is stateless, so there are no shared objects across the stack.&lt;/li&gt;
&lt;li&gt;It doesn't involve any boilerplate code, generated code, configuration files, or artifacts.&lt;/li&gt;
&lt;li&gt;It uses a simple but powerful serialization protocol (&lt;a href="https://deepr.io" rel="noopener noreferrer"&gt;Deepr&lt;/a&gt;) that enables unique features such as chained invocation, automatic batching, or partial execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Layr starts its journey in JavaScript/TypeScript, but the problem it tackles is universal, and it could be ported to any object-oriented language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let's implement the classic "Counter" example to see what it looks like to build a full-stack application with Layer.&lt;/p&gt;

&lt;p&gt;First, we implement the "data model" and the "business logic" in the backend:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// backend.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;primaryIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;expose&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@layr/component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ComponentHTTPServer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@layr/component-http-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// We need a primary identifier so a Counter instance&lt;/span&gt;
  &lt;span class="c1"&gt;// can be transported between the frontend and the backend&lt;/span&gt;
  &lt;span class="c1"&gt;// while keeping it's identity&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;primaryIdentifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// The counter value is exposed to the frontend&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// And the "business logic" is exposed as well&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;method&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Lastly, we serve the Counter class through an HTTP server&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ComponentHTTPServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3210&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Oh my! All that code just for a simple "Counter" example? Sure, it seems overkill, but we've actually implemented a full-grade backend with a data model, some business logic, and an HTTP server exposing the whole thing.&lt;/p&gt;

&lt;p&gt;Now that we have a backend, we can consume it from a frontend:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// frontend.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ComponentHTTPClient&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@layr/component-http-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// We create a client to connect to the backend server&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ComponentHTTPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3210&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// We get a proxy to the Counter backend class&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Lastly, we consume the Counter&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 0&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 1&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 2&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What's going on here? By invoking the &lt;code&gt;counter.increment()&lt;/code&gt; method the counter value is incremented. Note that this method does not exist in the frontend. It is implemented in the backend and is therefore executed in this environment. But from the perspective of the frontend, the actual execution environment doesn't matter. The fact that the method is executed remotely can be seen as an implementation detail.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Counter&lt;/code&gt; class in the frontend can be extended to implement features that are specific to the frontend. Here's an example of how to override the &lt;code&gt;increment()&lt;/code&gt; method to display a message when the counter reaches a certain value:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExtendedCounter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// We call the `increment()` method in the backend&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// We execute some additional code in the frontend&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The counter value is 3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is what it looks like when the frontend and the backend are reunited. Pretty cool isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the Catch?
&lt;/h2&gt;

&lt;p&gt;Why does everyone build web APIs when we could do without them?&lt;/p&gt;

&lt;p&gt;There is one good reason to implement a web API, it's when you want to expose your backend to some external developers through an established protocol such as REST. But let's be honest, the vast majority of applications don't have this requirement. And if it turns out that you need a web API, it is possible to add it afterward while continuing to use the "API-less" approach for all your internal needs.&lt;/p&gt;

&lt;p&gt;Another reason is if you work on a large-scale application with millions of users. Indeed, the convenience provided by Layr doesn't come without a cost, so if you want the most optimized application possible, you'd better go with a lower-level solution.&lt;/p&gt;

&lt;p&gt;Finally, if you want to implement a frontend or a backend in a language other than JavaScript, you can still use Layr on one side of the stack, but you will then have to implement an API client or server that can speak the &lt;a href="https://deepr.io" rel="noopener noreferrer"&gt;Deepr&lt;/a&gt; protocol on the other side of the stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Removing the web API allows you to build a full-stack application much faster while increasing the quality of your codebase.&lt;/p&gt;

&lt;p&gt;By using &lt;a href="https://github.com/layrjs/layr" rel="noopener noreferrer"&gt;Layr&lt;/a&gt; on several projects, including some production projects, I was able to reduce the amount of code by &lt;a href="https://github.com/layrjs/react-layr-realworld-example-app/blob/master/docs/comparison.md" rel="noopener noreferrer"&gt;50% on average&lt;/a&gt; and greatly increase my productivity.&lt;/p&gt;

&lt;p&gt;Another important aspect is the development experience. Since the frontend and the backend are no longer separated by a web API, you get a feeling similar to developing a standalone application, and it's a lot more fun.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>api</category>
    </item>
    <item>
      <title>Full-Stack Development Should Be Easier</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Mon, 19 Oct 2020 21:33:36 +0000</pubDate>
      <link>https://forem.com/mvila/full-stack-development-should-be-easier-2i2p</link>
      <guid>https://forem.com/mvila/full-stack-development-should-be-easier-2i2p</guid>
      <description>&lt;p&gt;In the beginning, there were only full-stack developers. We implemented everything in the backend with some &lt;a href="https://www.php.net/" rel="noopener noreferrer"&gt;PHP&lt;/a&gt; or &lt;a href="https://rubyonrails.org/" rel="noopener noreferrer"&gt;Ruby On Rails&lt;/a&gt; and then, with a bit of &lt;a href="https://jquery.com/" rel="noopener noreferrer"&gt;jQuery&lt;/a&gt; running in the frontend, we were done.&lt;/p&gt;

&lt;p&gt;But times have changed. Modern web apps require rich user interfaces that can no longer be rendered in the backend.&lt;/p&gt;

&lt;p&gt;So we switched to a &lt;a href="https://en.wikipedia.org/wiki/Single-page_application" rel="noopener noreferrer"&gt;"single-page application"&lt;/a&gt; model with a frontend that entirely manages the user interface.&lt;/p&gt;

&lt;p&gt;As for the backend, it is simplified because it only has to manage the domain model and the business logic.&lt;/p&gt;

&lt;p&gt;The problem is that we now have to connect the frontend and the backend, and this is where things get complicated.&lt;/p&gt;

&lt;p&gt;We build a web API (&lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer" rel="noopener noreferrer"&gt;REST&lt;/a&gt;, &lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt;, etc.) that significantly increases the size of our code and results in duplicating our domain model.&lt;/p&gt;

&lt;p&gt;In practice, it's like building two applications instead of one.&lt;/p&gt;

&lt;p&gt;So we multiply the number of developers, and the overall complexity is such that we divide them into frontend and backend developers.&lt;/p&gt;

&lt;p&gt;If you are a half-stack developer, you can only do half the work, and you spend a lot of time communicating with the person in charge of the other half.&lt;/p&gt;

&lt;p&gt;If you're a full-stack developer, you're a real hero. You can implement a feature from start to finish in a much more efficient and satisfying way.&lt;/p&gt;

&lt;p&gt;Dividing frontend and backend developers kills productivity and ruins all the fun.&lt;/p&gt;

&lt;p&gt;But let's be honest, being a full-stack developer today is &lt;a href="https://roadmap.sh/" rel="noopener noreferrer"&gt;way too difficult&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ideally, we should all be full-stack like we were in the beginning. But for that to be possible, we need to dramatically simplify the stack.&lt;/p&gt;

&lt;h1&gt;
  
  
  Simplifying the Stack
&lt;/h1&gt;

&lt;p&gt;For the simplest projects, it is possible to use a "backendless" solution such as &lt;a href="https://parseplatform.org/" rel="noopener noreferrer"&gt;Parse&lt;/a&gt;, &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;, or &lt;a href="https://aws.amazon.com/amplify/" rel="noopener noreferrer"&gt;Amplify&lt;/a&gt;. But when the business logic goes beyond CRUD operations, it's not that great.&lt;/p&gt;

&lt;p&gt;Something called &lt;a href="https://www.meteor.com/" rel="noopener noreferrer"&gt;Meteor&lt;/a&gt; came out eight years ago (an eternity in software engineering). The main idea was to simplify the communication between the frontend and the backend, and at that time it was quite revolutionary. Unfortunately, the project has not aged well and it is not suited to today's environment anymore.&lt;/p&gt;

&lt;p&gt;Recently, two projects made the buzz — &lt;a href="https://redwoodjs.com/" rel="noopener noreferrer"&gt;RedwoodJS&lt;/a&gt; and &lt;a href="https://blitzjs.com/" rel="noopener noreferrer"&gt;Blitz.js&lt;/a&gt;. Both also aim to simplify the communication between the frontend and the backend, but with a different approach.&lt;/p&gt;

&lt;p&gt;RedwoodJS simplifies the implementation of a GraphQL API and brings together &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; and &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; in an opinionated framework.&lt;/p&gt;

&lt;p&gt;Blitz.js is also a framework using React and Prisma, but it is built upon &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; and it strives to eliminate the need for a web API.&lt;/p&gt;

&lt;p&gt;These projects are heading in the right direction — simplifying the development of full-stack applications — and I hope they will be successful.&lt;/p&gt;

&lt;p&gt;But let me introduce my attempt in the field — a project called &lt;a href="https://liaison.dev" rel="noopener noreferrer"&gt;Liaison&lt;/a&gt; that I have been working on for a year and a half.&lt;/p&gt;

&lt;h1&gt;
  
  
  Liaison
&lt;/h1&gt;

&lt;p&gt;I created Liaison with an obsession — flattening the stack as much as possible.&lt;/p&gt;

&lt;p&gt;A typical stack is made of six layers: data access, backend model, API server, API client, frontend model, and user interface.&lt;/p&gt;

&lt;p&gt;With Liaison, a stack can be seen as a single logical layer that reunites the frontend and the backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fit4h1zr1qut57aw2hdon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fit4h1zr1qut57aw2hdon.png" alt="Typical stack vs Liaison stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is that each layer leads to more code scattering, duplication of knowledge, boilerplate, and accidental complexity.&lt;/p&gt;

&lt;p&gt;Liaison overcomes this problem by allowing you to assemble an application in a single logical layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Layer Inheritance
&lt;/h2&gt;

&lt;p&gt;With Liaison, it is possible to inherit the frontend from the backend. It works like regular class inheritance but across layers running in separate environments.&lt;/p&gt;

&lt;p&gt;Physically, we still have a separate frontend and backend, but logically, we get a single layer that unites the whole application.&lt;/p&gt;

&lt;p&gt;When calling a method from a frontend class that inherits from a backend class, the execution takes place where the method is implemented — in the frontend or the backend — and it doesn't matter for the method's consumer. The execution environment is abstracted away.&lt;/p&gt;

&lt;p&gt;Let's see how a full-stack &lt;a href="https://en.wikipedia.org/wiki/%22Hello,_World!%22_program" rel="noopener noreferrer"&gt;"Hello, World!"&lt;/a&gt; would look like with Liaison.&lt;/p&gt;

&lt;p&gt;To start, here is the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ComponentHTTPServer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component-http-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;method&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ComponentHTTPServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3210&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ComponentHTTPClient&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component-http-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ComponentHTTPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3210&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Steve&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: This article focuses on the architectural aspect of the stack, so don't worry if you don't fully understand the code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When running the frontend, the &lt;code&gt;hello()&lt;/code&gt; method is called, and the fact that it is executed on the backend side can be seen as an implementation detail.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Greeter&lt;/code&gt; class in the frontend behaves like a regular JavaScript class, and it can be extended. For example, we could override the &lt;code&gt;hello()&lt;/code&gt; method like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExtendedGreeter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when the &lt;code&gt;hello()&lt;/code&gt; method is called, the execution happens in both the frontend and the backend. But again, where the execution takes place can be seen as an implementation detail.&lt;/p&gt;

&lt;p&gt;From the developer's perspective, the frontend and the backend are a single thing, and that makes everything easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Persistence
&lt;/h2&gt;

&lt;p&gt;Most applications need to store data and here also things could be greatly simplified.&lt;/p&gt;

&lt;p&gt;The idea is not new, a database can be abstracted away with an &lt;a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping" rel="noopener noreferrer"&gt;ORM&lt;/a&gt;, and this is the approach followed by Liaison.&lt;/p&gt;

&lt;p&gt;In a nutshell, the &lt;a href="https://liaison.dev/docs/v1/reference/storable" rel="noopener noreferrer"&gt;&lt;code&gt;Storable()&lt;/code&gt;&lt;/a&gt; mixin brings persistency to your data. For example, take the following class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Storable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;primaryIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/storable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Movie&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Storable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;primaryIdentifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create and save a &lt;code&gt;Movie&lt;/code&gt;, you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Inception&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to retrieve an existing &lt;code&gt;Movie&lt;/code&gt;, you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abc123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, there is nothing new here, it is similar to any ORM using the &lt;a href="https://en.wikipedia.org/wiki/Active_record_pattern" rel="noopener noreferrer"&gt;active record pattern&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What changes with Liaison is that the ORM is not restricted to the backend. The cross-layer inheritance mechanism makes the ORM available in the frontend as well.&lt;/p&gt;

&lt;p&gt;Conceptually, we therefore still have a single logical layer combining the frontend, the backend, and the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  User Interface
&lt;/h2&gt;

&lt;p&gt;In a typical application, the user interface and the domain model are completely separated. A few years ago there was a good reason to do so because the user interface was essentially made up of imperative code. But now that we have some functional UI libraries (e.g., &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;React with hooks&lt;/a&gt;), it is possible to combine the user interface and the domain model.&lt;/p&gt;

&lt;p&gt;Liaison allows you to implement your routes and views as methods of your models.&lt;/p&gt;

&lt;p&gt;Here's an example of how to define routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Routable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/routable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Movie&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Routable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Display all the movies...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/movies/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Display a specific movie...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, a route is simply a URL associated with a method of a model.&lt;/p&gt;

&lt;p&gt;Here's how to implement views:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/react-integration&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Movie&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;view&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nc"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Heading&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Details&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;view&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nc"&gt;Heading&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;view&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nc"&gt;Details&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A view is simply a method that returns something based on the attributes of a model, and returning user interface elements is not a problem at all.&lt;/p&gt;

&lt;p&gt;Since a view is bound to a model, you probably won't need to use a state manager such as &lt;a href="https://redux.js.org/" rel="noopener noreferrer"&gt;Redux&lt;/a&gt; or &lt;a href="https://mobx.js.org/" rel="noopener noreferrer"&gt;MobX&lt;/a&gt;. The &lt;a href="https://liaison.dev/docs/v1/reference/react-integration#view-decorator" rel="noopener noreferrer"&gt;&lt;code&gt;@view()&lt;/code&gt;&lt;/a&gt; decorator makes sure that the view is re-rendered automatically when the value of an attribute changes.&lt;/p&gt;

&lt;p&gt;So we've encapsulated the user interface in the domain model, and that's one less layer to worry about.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I strongly believe that flattening the stack is crucial to make full-stack development more approachable.&lt;/p&gt;

&lt;p&gt;Liaison allows you to build a full-stack application in two physical layers — the frontend and the backend — which are gathered in a single logical layer.&lt;/p&gt;

&lt;p&gt;It's easier to start a project with as few layers as possible, but that doesn't mean you have to build all your projects that way.&lt;/p&gt;

&lt;p&gt;For some projects, it may be a good idea to break down an application into more layers. For example, it may be useful to separate the data access from the backend model or separate the user interface from the frontend model.&lt;/p&gt;

&lt;p&gt;No worries. The cross-layer inheritance mechanism allows you to multiply the physical layers while keeping a single logical layer.&lt;/p&gt;

&lt;p&gt;If object-oriented programming is not your cup of tea, you won't like Liaison. But please don't reject OOP because you think it offers a poor composition model. JavaScript classes can be functionally defined (e.g., &lt;a href="https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/" rel="noopener noreferrer"&gt;mixins&lt;/a&gt;), and are therefore extremely composable.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://liaison.dev/docs" rel="noopener noreferrer"&gt;Liaison documentation&lt;/a&gt;, start building something, and &lt;a href="https://github.com/liaisonjs/liaison/issues" rel="noopener noreferrer"&gt;let me know&lt;/a&gt; what you think.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on &lt;a href="https://hackernoon.com/full-stack-for-all-l5q3tqb" rel="noopener noreferrer"&gt;Hacker Noon&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Liaison 1.0: Reuniting the Frontend and the Backend</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Fri, 18 Sep 2020 13:00:37 +0000</pubDate>
      <link>https://forem.com/mvila/liaison-1-0-is-out-a-set-of-js-ts-libraries-to-dramatically-simplify-the-development-of-full-stack-applications-4hnm</link>
      <guid>https://forem.com/mvila/liaison-1-0-is-out-a-set-of-js-ts-libraries-to-dramatically-simplify-the-development-of-full-stack-applications-4hnm</guid>
      <description>&lt;p&gt;Let's talk about web app development.&lt;/p&gt;

&lt;p&gt;It used to be simple. We implemented everything in the backend with some PHP code or Ruby on Rails and then, with a bit of JavaScript running in the frontend, we were done.&lt;/p&gt;

&lt;p&gt;But times have changed. Modern web apps require rich user interfaces that can no longer be rendered in the backend.&lt;/p&gt;

&lt;p&gt;So, from a bit of JavaScript running in the frontend, we switched to a lot of JavaScript using a single-page application model and a bunch of libraries.&lt;/p&gt;

&lt;p&gt;There's nothing wrong with this. It's actually quite an elegant architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The frontend is in charge of the user interface.&lt;/li&gt;
&lt;li&gt;The backend takes care of the data model and the business logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem, however, lies in the middle. Now that we have two rich execution environments, we need to make sure that they communicate effectively. So, we implement a web API (REST, GraphQL, etc.), and &lt;a href="https://dev.to/mvila/simplify-full-stack-development-with-a-unified-architecture-40kd"&gt;everything gets complicated&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Conceptually, it's like we're building two applications instead of one.&lt;/p&gt;

&lt;p&gt;The data model gets duplicated, and the overall complexity is such that the developers become duplicated as well.&lt;/p&gt;

&lt;p&gt;If you're a frontend or backend developer, you can only do half the job, and you waste a lot of time communicating with the person in charge of the other half.&lt;/p&gt;

&lt;p&gt;If you're a full-stack developer, you can implement a feature from start to finish in a much more efficient and satisfying way. But, given the sophistication of the stack, there's a lot you have to deal with, and it doesn't scale very well.&lt;/p&gt;

&lt;p&gt;Ideally, we should all be full-stack developers just like we were in the beginning. But we need to dramatically simplify the stack to make this possible.&lt;/p&gt;

&lt;p&gt;So, how to simplify the stack?&lt;/p&gt;

&lt;p&gt;Sure, the frontend and the backend need to be &lt;em&gt;physically&lt;/em&gt; separated. But it doesn't mean that they have to be &lt;em&gt;logically&lt;/em&gt; separated.&lt;/p&gt;

&lt;p&gt;With the right abstractions in place, an application can run in two different execution environments, even as it remains a single thing from the developer's point of view.&lt;/p&gt;

&lt;p&gt;This is precisely what Liaison offers — a reuniting of the frontend and the backend.&lt;/p&gt;

&lt;p&gt;The data model can be shared across the stack, and there is &lt;a href="https://dev.to/mvila/do-we-really-need-a-web-api-5cg6"&gt;no need to build a web API&lt;/a&gt; anymore.&lt;/p&gt;

&lt;p&gt;Some might argue that mastering both the frontend and the backend is not that easy.&lt;/p&gt;

&lt;p&gt;The frontend is not only UI rendering, but it's also state management, routing, etc.&lt;/p&gt;

&lt;p&gt;The backend is not only data modeling and business logic, but it's also data storage, authorization, etc.&lt;/p&gt;

&lt;p&gt;Fair enough, it's not that easy. But here, Liaison also has &lt;a href="https://liaison.dev/docs"&gt;a lot to offer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, hopefully, everyone can be a full-stack developer again.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://liaison.dev/"&gt;Liaison website&lt;/a&gt;, start building something, and &lt;a href="https://github.com/liaisonjs/liaison/issues"&gt;let me know&lt;/a&gt; what you think.&lt;/p&gt;

&lt;p&gt;Happy coding! 🧑‍💻&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Simplify Full-Stack Development with a Unified Architecture</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Wed, 11 Dec 2019 23:08:33 +0000</pubDate>
      <link>https://forem.com/mvila/simplify-full-stack-development-with-a-unified-architecture-40kd</link>
      <guid>https://forem.com/mvila/simplify-full-stack-development-with-a-unified-architecture-40kd</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally published on &lt;a href="https://www.freecodecamp.org/news/full-stack-unified-architecture/"&gt;freeCodeCamp&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A modern full-stack application (e.g., a single-page application or a mobile application) is typically composed of six layers: data access, backend model, API server, API client, frontend model, and user interface.&lt;/p&gt;

&lt;p&gt;By architecting in this way, you can achieve some characteristics of a well-designed application, such as &lt;a href="https://en.wikipedia.org/wiki/Separation_of_concerns"&gt;separation of concerns&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Loose_coupling"&gt;loose coupling&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But it does not come without drawbacks. It usually comes at the expense of some other important characteristics such as simplicity, &lt;a href="https://en.wikipedia.org/wiki/Cohesion_(computer_science)"&gt;cohesion&lt;/a&gt;, or agility.&lt;/p&gt;

&lt;p&gt;It seems we can't have it all. We have to compromise.&lt;/p&gt;

&lt;p&gt;The problem is that each layer is usually built as a completely different world on its own.&lt;/p&gt;

&lt;p&gt;Even if the layers are implemented with the same language, they cannot communicate easily and share much with each other.&lt;/p&gt;

&lt;p&gt;We need a lot of &lt;a href="https://en.wikipedia.org/wiki/Glue_code"&gt;glue code&lt;/a&gt; to connect them all, and the &lt;a href="https://en.wikipedia.org/wiki/Domain_model"&gt;domain model&lt;/a&gt; gets duplicated across the stack. As a result, the development agility suffers dramatically.&lt;/p&gt;

&lt;p&gt;For example, adding a simple field to a model often requires modifying all the layers of the stack. Don't you think this is a bit ridiculous?&lt;/p&gt;

&lt;p&gt;I've been thinking a lot about this problem recently, and I believe I've found a way out.&lt;/p&gt;

&lt;p&gt;Here's the trick: for sure, the layers of an application must be "physically" separated, but they don't need to be "logically" separated.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Unified Architecture
&lt;/h1&gt;

&lt;p&gt;In object-oriented programming, when we use inheritance, we get some classes that can be seen in two ways: physical and logical. What do I mean by that?&lt;/p&gt;

&lt;p&gt;Let's imagine we have a class &lt;code&gt;B&lt;/code&gt; that inherits from a class &lt;code&gt;A&lt;/code&gt;. Then, &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; can be seen as two physical classes. But logically, they are not separated, and &lt;code&gt;B&lt;/code&gt; can be seen as a logical class that composes the properties of &lt;code&gt;A&lt;/code&gt; with its own properties.&lt;/p&gt;

&lt;p&gt;For example, when we call a method in a class, we don't have to worry if the method is implemented in this class or a parent class. From the caller perspective, there is only one class to worry about. Parent and child are unified into a single logical class.&lt;/p&gt;

&lt;p&gt;How about applying the same approach to the layers of an application? Wouldn't it be great if, for example, the frontend could somehow inherit from the backend?&lt;/p&gt;

&lt;p&gt;Doing so, frontend and backend would be unified into a single logical layer, and that would remove all communication and sharing issues. Indeed, backend classes, attributes, and methods would be directly accessible from the frontend.&lt;/p&gt;

&lt;p&gt;Of course, we don't usually want to expose the whole backend to the frontend. But the same goes for class inheritance, and there is an elegant solution that is called "private properties". Similarly, the backend could selectively expose some attributes and methods.&lt;/p&gt;

&lt;p&gt;Being able to grasp all the layers of an application from one single unified world is not a small deal. It changes the game completely. It is like going from a 3D world to a 2D world. Everything gets a lot easier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://liaison.dev/blog/articles/Do-We-Really-Need-to-Separate-the-Model-from-the-UI-9wogqr#composition-over-inheritance"&gt;Inheritance is not evil&lt;/a&gt;. Yes, it can be misused, and in some languages, it can be pretty rigid. But when properly used, it is an invaluable mechanism in our toolbox.&lt;/p&gt;

&lt;p&gt;We have a problem, though. As far as I know, there is no language allowing us to inherit classes across multiple execution environments. But we are programmers, aren't we? We can build everything we want, and we can extend the language to provide new capabilities.&lt;/p&gt;

&lt;p&gt;But before we get to that, let's break down the stack to see how each layer can fit in a unified architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Access
&lt;/h3&gt;

&lt;p&gt;For a majority of applications, the database can be abstracted using some sort of ORM. So, from the developer perspective, there is no data access layer to worry about.&lt;/p&gt;

&lt;p&gt;For more ambitious applications, we might have to optimize database schemas and requests. But we don't want to clutter the backend model with these concerns, and this is where an additional layer may be appropriate.&lt;/p&gt;

&lt;p&gt;We build a data access layer to implement the optimization concerns, and this usually happens late in the development cycle, if it ever happens.&lt;/p&gt;

&lt;p&gt;Anyway, if we need such a layer, we can build it later. With cross-layer inheritance, we can add a data access layer on top of the backend model layer with almost no changes to the existing code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend Model
&lt;/h3&gt;

&lt;p&gt;Typically, a backend model layer handles the following responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shaping the domain model.&lt;/li&gt;
&lt;li&gt;Implementing business logic.&lt;/li&gt;
&lt;li&gt;Handling the authorization mechanisms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most backends, it is fine to implement them all in a single layer. But, if we want to handle some concerns separately, for example, we want to separate the authorization from the business logic, we can implement them in two layers that inherit from each other.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Layers
&lt;/h3&gt;

&lt;p&gt;To connect the frontend and the backend, we usually build a web API (REST, GraphQL, etc.), and that complicates everything.&lt;/p&gt;

&lt;p&gt;The web API must be implemented on both sides: an API client in the frontend and an API server in the backend. That's two extra layers to worry about, and it usually leads to duplicate the whole domain model.&lt;/p&gt;

&lt;p&gt;A web API is nothing more than glue code, and it is a pain in the ass to build. So, if we can avoid it, that's a massive improvement.&lt;/p&gt;

&lt;p&gt;Fortunately, we can take advantage of cross-layer inheritance again. In a unified architecture, there is no web API to build. All we have to do is to inherit the frontend model from the backend model, and we are done.&lt;/p&gt;

&lt;p&gt;However, there are still some good use cases for building a web API. That's when we need to expose a backend to some third-party developers, or when we need to integrate with some legacy systems.&lt;/p&gt;

&lt;p&gt;But let's be honest, most applications don't have such a requirement. And when they do, it is easy to handle it afterward. We can simply implement the web API into a new layer that inherits from the backend model layer.&lt;/p&gt;

&lt;p&gt;Further information on this topic can be found in &lt;a href="https://liaison.dev/blog/articles/How-about-interoperability-oy3ugk"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend Model
&lt;/h3&gt;

&lt;p&gt;Since the backend is the source of truth, it should implement all the business logic, and the frontend should not implement any. So, the frontend model is simply inherited from the backend model, with almost no additions.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Interface
&lt;/h3&gt;

&lt;p&gt;We usually implement the frontend model and the UI in two separate layers. But as I showed in &lt;a href="https://liaison.dev/blog/articles/Do-We-Really-Need-to-Separate-the-Model-from-the-UI-9wogqr"&gt;this article&lt;/a&gt;, it is not mandatory.&lt;/p&gt;

&lt;p&gt;When the frontend model is made of classes, it is possible to encapsulate the views as simple methods. Don't worry if you don't see what I mean right now, it will become clearer in the example later on.&lt;/p&gt;

&lt;p&gt;Since the frontend model is basically empty (see above), it is fine to implement the UI directly into it, so there is no user interface layer &lt;em&gt;per se&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Implementing the UI in a separate layer is still needed when we want to support multiple platforms (e.g., a web app and a mobile app). But, since it is just a matter of inheriting a layer, that can come later in the development roadmap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting Everything Together
&lt;/h3&gt;

&lt;p&gt;The unified architecture allowed us to unify six physical layers into one single logical layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In a minimal implementation, data access is encapsulated into the backend model, and the same goes for UI that is encapsulated into the frontend model.&lt;/li&gt;
&lt;li&gt;The frontend model inherits from the backend model.&lt;/li&gt;
&lt;li&gt;The API layers are not required anymore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result can be illustrated as follows:&lt;/p&gt;

&lt;p&gt;
    &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_3HfKlWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://liaison-blog.s3.dualstack.us-west-2.amazonaws.com/images/traditional-vs-unified-architecture.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_3HfKlWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://liaison-blog.s3.dualstack.us-west-2.amazonaws.com/images/traditional-vs-unified-architecture.svg" alt="Traditional vs unified architecture" width="581" height="581"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;That's pretty spectacular, don't you think?&lt;/p&gt;

&lt;h1&gt;
  
  
  Liaison
&lt;/h1&gt;

&lt;p&gt;To implement a unified architecture, all we need is cross-layer inheritance, and I started building &lt;a href="https://liaison.dev"&gt;Liaison&lt;/a&gt; to achieve exactly that.&lt;/p&gt;

&lt;p&gt;You can see Liaison as a framework if you wish, but I prefer to describe it as a language extension because all its features lie at the lowest possible level — the programming language level.&lt;/p&gt;

&lt;p&gt;So, Liaison does not lock you into a predefined framework, and a whole universe can be created on top of it. You can read more on this topic in &lt;a href="https://liaison.dev/blog/articles/Getting-the-Right-Level-of-Generalization-7xpk37"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Behind the scene, Liaison relies on an &lt;a href="https://en.wikipedia.org/wiki/Remote_procedure_call"&gt;RPC&lt;/a&gt; mechanism. So, superficially, it can be seen as something like &lt;a href="https://en.wikipedia.org/wiki/Common_Object_Request_Broker_Architecture"&gt;CORBA&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Java_remote_method_invocation"&gt;Java RMI&lt;/a&gt;, or &lt;a href="https://en.wikipedia.org/wiki/Windows_Communication_Foundation"&gt;.NET CWF&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But Liaison is radically different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is not a &lt;a href="https://en.wikipedia.org/wiki/Distributed_object"&gt;distributed object system&lt;/a&gt;. Indeed, a Liaison backend is stateless, so there are no shared objects across layers.&lt;/li&gt;
&lt;li&gt;It is implemented at the language-level (see above).&lt;/li&gt;
&lt;li&gt;Its design is straightforward and it exposes a minimal API.&lt;/li&gt;
&lt;li&gt;It doesn't involve any boilerplate code, generated code, configuration files, or artifacts.&lt;/li&gt;
&lt;li&gt;It uses a simple but powerful serialization protocol (&lt;a href="https://deepr.io"&gt;Deepr&lt;/a&gt;) that enables unique features, such as chained invocation, automatic batching, or partial execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Liaison starts its journey in JavaScript, but the problem it tackles is universal, and it could be ported to any object-oriented language without too much trouble.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hello Counter
&lt;/h3&gt;

&lt;p&gt;Let's illustrate how Liaison works by implementing the classic "Counter" example as a single-page application.&lt;/p&gt;

&lt;p&gt;First, let's build the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// backend.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;primaryIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;expose&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ComponentServer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// We need a primary identifier so a Counter instance&lt;/span&gt;
  &lt;span class="c1"&gt;// can be transported between the frontend and the backend&lt;/span&gt;
  &lt;span class="c1"&gt;// while keeping it's identity&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;primaryIdentifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// The counter's value is exposed to the frontend&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// And the "business logic" is exposed as well&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;method&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// We serve the Counter through a ComponentServer&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ComponentServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, let's build the frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// frontend.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ComponentClient&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/component-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// We create a client that is connected to the backend's server&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ComponentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// We get the backend's Counter class&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BackendCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// We extends the backend's Counter class so we can override&lt;/span&gt;
&lt;span class="c1"&gt;// the increment() method later&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;BackendCounter&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// Lastly, we consume the Counter&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on? By invoking &lt;code&gt;counter.increment()&lt;/code&gt;, we got the counter's value incremented. Notice that the &lt;code&gt;increment()&lt;/code&gt; method is not implemented in the frontend class. It only exists in the backend.&lt;/p&gt;

&lt;p&gt;So, how is it possible that we could call it from the frontend? This is because the frontend class (&lt;code&gt;Counter&lt;/code&gt;) is inherited from the backend class (&lt;code&gt;BackendCounter&lt;/code&gt;). So, when a method is missing in the frontend class, and a method with the same name is exposed in the backend class, it is automatically invoked, even though the backend is remote.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that in this simple example, the backend is not exactly remote. Both the frontend and the backend run in the same JavaScript runtime. To make the backend truly remote, we can easily expose it through HTTP. See an &lt;a href="https://github.com/liaisonjs/liaison/tree/master/examples/counter-with-http/src"&gt;example here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From the frontend point of view, the operation is transparent. It doesn't need to know that a method is invoked remotely. It just works.&lt;/p&gt;

&lt;p&gt;The current state of an instance (i.e., &lt;code&gt;counter&lt;/code&gt;'s attributes) is automatically transported back and forth. When a method is executed in the frontend, the attributes that have been modified are sent to the backend. And inversely, when some attributes change in the backend, they are reflected in the frontend.&lt;/p&gt;

&lt;p&gt;How about passing/returning values to/from a remotely invoked method? It is possible to pass/return anything that is serializable, including class instances. As long as a class is registered with the same name in both the frontend and the backend, its instances can be automatically transported.&lt;/p&gt;

&lt;p&gt;How about overriding a method across the frontend and the backend? It is no different than with regular JavaScript — we can use &lt;code&gt;super&lt;/code&gt;. For example, we can override the &lt;code&gt;increment()&lt;/code&gt; method to run additional code in the context of the frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// frontend.js&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;BackendCounter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// The backend's `increment()` method is invoked&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Some additional code is executed in the frontend&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's build a user interface with &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; and the encapsulated approach shown earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// frontend.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@liaison/react-integration&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;BackendCounter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// We use the `@view()` decorator to observe the counter's attributes&lt;/span&gt;
  &lt;span class="c1"&gt;// and automatically re-render the view when needed&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;view&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;Display&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;+&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, to display the counter, all we need is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Display&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà! We built a single-page application with two unified layers and an encapsulated UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Proof of Concept
&lt;/h3&gt;

&lt;p&gt;To experiment with the unified architecture, I built a &lt;a href="https://github.com/liaisonjs/react-liaison-realworld-example-app"&gt;RealWorld example app&lt;/a&gt; with Liaison.&lt;/p&gt;

&lt;p&gt;I might be biased, but the outcome looks pretty amazing to me: simple implementation, high code cohesion, 100% &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt;, and no glue code.&lt;/p&gt;

&lt;p&gt;In terms of the amount of code, my implementation is significantly lighter than any other one I have examined. Check out the &lt;a href="https://github.com/liaisonjs/react-liaison-realworld-example-app/blob/master/docs/comparison.md"&gt;results here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Certainly, the RealWorld example is a small application, but since it covers the most important concepts that are common to all applications, I'm confident that a unified architecture can scale up to more ambitious applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Separation of concerns, loose coupling, simplicity, cohesion, and agility.&lt;/p&gt;

&lt;p&gt;It seems we get it all, finally.&lt;/p&gt;

&lt;p&gt;If you are an experienced developer, I guess you feel a bit skeptical at this point, and this is totally fine. It is hard to leave behind years of established practices.&lt;/p&gt;

&lt;p&gt;If object-oriented programming is not your cup of tea, you will not want to use Liaison, and this is totally fine as well.&lt;/p&gt;

&lt;p&gt;But if you are into OOP, please keep a little window open in your mind, and the next time you have to build a full-stack application, try to see how it would fit in a unified architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://liaison.dev/"&gt;Liaison&lt;/a&gt; is still at an early stage, but I am actively working on it, and I expect to release the first beta version in early 2020.&lt;/p&gt;

&lt;p&gt;If you are interested, please star the &lt;a href="https://github.com/liaisonjs/liaison"&gt;repository&lt;/a&gt; and stay updated by following the &lt;a href="https://liaison.dev/blog"&gt;blog&lt;/a&gt; or subscribing to the &lt;a href="https://liaison.dev/#newsletter"&gt;newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>architecture</category>
      <category>javascript</category>
      <category>oop</category>
    </item>
    <item>
      <title>Do We Really Need to Separate the Model from the UI?</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Sat, 23 Nov 2019 00:25:29 +0000</pubDate>
      <link>https://forem.com/mvila/do-we-really-need-to-separate-the-model-from-the-ui-tldr-no-593m</link>
      <guid>https://forem.com/mvila/do-we-really-need-to-separate-the-model-from-the-ui-tldr-no-593m</guid>
      <description>&lt;p&gt;Typically, domain models and UI views are completely separated. A few years ago, we had a good reason to do so because the views were mostly made of imperative code. But now that we have functional UI libraries (e.g., &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; with hooks), wouldn't it be possible to gather everything together, and implement the views as methods of the models they represent?&lt;/p&gt;

&lt;h1&gt;
  
  
  Object-Oriented Approach
&lt;/h1&gt;

&lt;p&gt;For example, let's say we have a &lt;code&gt;User&lt;/code&gt; class defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;getFullName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's add a React component into this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getFullName&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create an instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Arthur&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rimbaud&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, to render a &lt;code&gt;View&lt;/code&gt; for this &lt;code&gt;user&lt;/code&gt;, we can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a perfectly valid JavaScript/JSX code, and I don't think there is something wrong with it. Conceptually, the &lt;code&gt;View()&lt;/code&gt; method is no different than the &lt;code&gt;getFullName()&lt;/code&gt; method. They are just methods returning a different kind of view: &lt;code&gt;getFullName()&lt;/code&gt; returns a string and &lt;code&gt;View()&lt;/code&gt; returns a React element.&lt;/p&gt;

&lt;h1&gt;
  
  
  Functional Approach
&lt;/h1&gt;

&lt;p&gt;In a typical React app, we would not do so though. We would separate the view from the model like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;UserView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getFullName&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, to render &lt;code&gt;UserView&lt;/code&gt;, we would do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserView&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does this more verbose approach bring benefits? No matter how much I scratch my head, I don't see any. The code is just more scattered.&lt;/p&gt;

&lt;h1&gt;
  
  
  Decoupling
&lt;/h1&gt;

&lt;p&gt;It is always good to decouple the pieces of an application as much as possible.&lt;/p&gt;

&lt;p&gt;But does the functional approach (React components implemented separately as functions) brings more decoupling than the object-oriented approach (React components implemented as methods of a model)?&lt;/p&gt;

&lt;p&gt;It doesn't. Getting the models from a parameter or accessing them through &lt;code&gt;this&lt;/code&gt; makes no difference. In both cases, models and views become tightly coupled.&lt;/p&gt;

&lt;h1&gt;
  
  
  Separation of Concerns
&lt;/h1&gt;

&lt;p&gt;Some might argue that it is good to separate the model from the view because they are two different concerns. I don't get it. Again, how, in the object-oriented approach, the &lt;code&gt;getFullName()&lt;/code&gt; method is different than the &lt;code&gt;View()&lt;/code&gt; method? Both are returning a representation of the model, so why should we separate them?&lt;/p&gt;

&lt;p&gt;It remembers me of the discussion about separating HTML and CSS. Yes, they serve two different purposes. HTML describes the content and CSS describes the presentation. But I don't think there is something wrong about putting them together in a cohesive way.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sharing One Model with Multiple UIs
&lt;/h1&gt;

&lt;p&gt;Let's imagine we are building an app for several platforms: a web app (with ReactDOM) and an iOS app (with React Native).&lt;/p&gt;

&lt;p&gt;In this case, we usually want to share the same model with all platforms, and implement different UIs for each platform. To achieve this, we can implement the model separately and subclass it to implement the different views.&lt;/p&gt;

&lt;p&gt;Refactoring our previous example, we define the &lt;code&gt;User&lt;/code&gt; model in a separate file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// shared/user.js&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;getFullName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we subclass it to implement the views of the web app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// web/user.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;BaseUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../shared/user.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;BaseUser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getFullName&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same goes for the iOS app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ios/user.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;BaseUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../shared/user.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;BaseUser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getFullName&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Physically&lt;/em&gt;, the code is then a bit more scattered, but &lt;em&gt;logically&lt;/em&gt;, it is not. Whichever the platform, from a &lt;code&gt;User&lt;/code&gt; instance, we have access to both the model (&lt;code&gt;user.firstName&lt;/code&gt;) and its views (&lt;code&gt;&amp;lt;user.View /&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;h1&gt;
  
  
  Composition over Inheritance
&lt;/h1&gt;

&lt;p&gt;« Inheritance is evil. »&lt;/p&gt;

&lt;p&gt;« Composition is the way to go. »&lt;/p&gt;

&lt;p&gt;I am tired of hearing that all the time about anything and everything.&lt;/p&gt;

&lt;p&gt;Yes, single inheritance in static languages (Java, C#, etc.) may not be the right approach for composing the multiple pieces of an application. But it is not true with JavaScript where inheritance is dynamic, and therefore, extremely flexible.&lt;/p&gt;

&lt;p&gt;For example, we can use mixins to enable any kind of inheritance: multiple, conditional, parameterized, etc.&lt;/p&gt;

&lt;p&gt;There are many ways to implement mixins in JavaScript, but there is only one good way, and it is incredibly simple. Please &lt;a href="https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/"&gt;head over here&lt;/a&gt; for a nice explanation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I tried the object-oriented approach when implementing the &lt;a href="https://github.com/gothinkster/realworld"&gt;RealWorld example&lt;/a&gt; with &lt;a href="https://liaison.dev"&gt;Liaison&lt;/a&gt;, and I think it worked pretty well. Encapsulating the views into the models made the code a lot more cohesive than if the views were implemented separately.&lt;/p&gt;

&lt;p&gt;If you are skeptical (you should be), please have a look at &lt;a href="https://github.com/liaisonjs/react-liaison-realworld-example-app/tree/master/frontend/src/components"&gt;the code&lt;/a&gt; and tell me what you think.&lt;/p&gt;

&lt;p&gt;Since most of the models are implemented in the &lt;a href="https://github.com/liaisonjs/react-liaison-realworld-example-app/tree/master/backend/src/components"&gt;backend&lt;/a&gt;, the frontend models are pretty much just composed of views.&lt;/p&gt;

&lt;p&gt;Some might think that the classes are a bit crowded. I guess it is a matter of taste. Personally, as long as the content is related, I don't mind large files. If you prefer small files, you can group some views into mixins and assemble them into a single model.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://liaison.dev/blog"&gt;Liaison Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>oop</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Do We Really Need A Web API?</title>
      <dc:creator>Manuel Vila</dc:creator>
      <pubDate>Sun, 17 Nov 2019 09:32:26 +0000</pubDate>
      <link>https://forem.com/mvila/do-we-really-need-a-web-api-5cg6</link>
      <guid>https://forem.com/mvila/do-we-really-need-a-web-api-5cg6</guid>
      <description>&lt;p&gt;Typically, when we build a single-page application, the frontend and the backend are living in two very separate worlds that are connected with a web API. Even if they are implemented with the same language (JavaScript), they cannot communicate directly using this language. They need something else in between, so we build a web API (REST, GraphQL, etc.), and that complicates everything.&lt;/p&gt;

&lt;p&gt;First, the web API must be implemented on both sides: an API client in the frontend and an API server in the backend. Second, to transport the domain model between the frontend and the backend, we must constantly serialize and deserialize it. All this leads to a lot of code scattering, duplication of knowledge, boilerplate, and accidental complexity. We get lost in translation.&lt;/p&gt;

&lt;p&gt;Most of the time, web APIs are not functional requirements. They don't add any value to the product we are building. They are just a necessary evil so the frontend can communicate with the backend. But is that really the case? Wouldn't it be possible to get rid of these web APIs?&lt;/p&gt;

&lt;h1&gt;
  
  
  Liaison
&lt;/h1&gt;

&lt;p&gt;I started building &lt;a href="https://liaison.dev"&gt;Liaison&lt;/a&gt; to achieve exactly that: getting rid of these "pain-in-the-ass" web APIs.&lt;/p&gt;

&lt;p&gt;With Liaison, frontend and backend can communicate directly with the language they are implemented in. The frontend can call a method in the backend without further ceremony. It is just a regular JavaScript method invocation.&lt;/p&gt;

&lt;p&gt;The way it works is simple: a frontend class can "inherit" from a backend class. So, when a method is called, if this method is missing in the frontend, the corresponding method is executed in the backend, automatically.&lt;/p&gt;

&lt;p&gt;For example, let's say the frontend is executing the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;anotherUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the implementation of &lt;code&gt;follow()&lt;/code&gt;, the execution can happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the frontend, if the method exists only in the frontend.&lt;/li&gt;
&lt;li&gt;In the backend, if the method exists only in the backend.&lt;/li&gt;
&lt;li&gt;Or both in the frontend and the backend, if the method exists in the backend but is overridden in the frontend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a method is executed in the backend, the attributes of the involved instances (&lt;code&gt;user&lt;/code&gt; and &lt;code&gt;anotherUser&lt;/code&gt;) are transported to the backend, the method is executed, and if some attributes have changed during the execution, those changes are automatically reflected in the frontend.&lt;/p&gt;

&lt;p&gt;Conceptually, it works like class inheritance. The only difference is that the inheritance occurs across two execution environments: the frontend and the backend. And when we call a method, it doesn't matter where the execution actually happens. For the developer, frontend and backend become one unified world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IuHy1Hlx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/su95fnx48910a99wh8vc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IuHy1Hlx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/su95fnx48910a99wh8vc.png" alt="Diagram showing traditional vs Liaison architecture" width="880" height="773"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So there is no need to build a web API anymore. We can still implement such an API if it is actually required (for example, we intend to open our application to third-party developers through a REST API), but for our own needs, we greatly benefit from doing without it.&lt;/p&gt;

&lt;p&gt;Without the burden of building a web API, we can dramatically reduce code scattering, duplication of knowledge, and boilerplate. We can build faster, and better.&lt;/p&gt;

&lt;h1&gt;
  
  
  RealWorld Example
&lt;/h1&gt;

&lt;p&gt;Is this approach working? I think it does. I built a &lt;a href="https://github.com/gothinkster/realworld"&gt;RealWorld example&lt;/a&gt; with Liaison, both the frontend and the backend, and &lt;a href="https://github.com/liaisonjs/react-liaison-realworld-example-app"&gt;the outcome&lt;/a&gt; looks quite amazing to me: straightforward implementation, high code cohesion, 100% DRY, and zero boilerplate.&lt;/p&gt;

&lt;p&gt;In terms of the amount of code, in case it matters, my implementation is significantly lighter than any other one I have examined:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Frontend&lt;/th&gt;
&lt;th&gt;Backend&lt;/th&gt;
&lt;th&gt;Shared&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/liaisonjs/react-liaison-realworld-example-app"&gt;react-liaison&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1374&lt;/td&gt;
&lt;td&gt;356&lt;/td&gt;
&lt;td&gt;66&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/gothinkster/react-mobx-realworld-example-app"&gt;react-mobx&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1937&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/gothinkster/react-redux-realworld-example-app"&gt;react-redux&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2050&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/gothinkster/vue-realworld-example-app"&gt;vue&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2118&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/gothinkster/angular-realworld-example-app"&gt;angular&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2122&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/gothinkster/node-express-realworld-example-app"&gt;node-express&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;596&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/lujakob/nestjs-realworld-example-app"&gt;nestjs-typeorm&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;967&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/gothinkster/koa-knex-realworld-example"&gt;koa-knex&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1535&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/gothinkster/hapijs-realworld-example-app"&gt;hapijs&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1872&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The numbers represent the amount of lines of code excluding comments and test suites. Count done on October 7th, 2019 using &lt;a href="https://github.com/XAMPPRocky/tokei"&gt;Tokei&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://liaison.dev/"&gt;Liaison&lt;/a&gt; is still at an early stage, and a lot of work remains so it can be used in production. I truly believe it is something worth trying, and I am actively working on it. I expect to release the first beta version in early 2020.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>fullstack</category>
      <category>apiless</category>
    </item>
  </channel>
</rss>
