Skip to content
Karim Ayachi edited this page Jun 27, 2020 · 12 revisions

The recent years have seen a paradigm shift in web development and the rise of Composition frameworks. Whereas the previous decade was dominated by a focus on Separation of Concerns (SoC), and architectural patterns such as MVVM that facilitated developing with SoC. We believe that one isn't better than the other, nor should one replace the other. There is a time and a place for both, depending on the application and the architecture. Composition really shines when it comes to reusable and/or distributable building blocks and small applications, where SoC is great for Enterprise sized applications with large code-bases that are constantly under construction. And even if your main architecture requires a SoC approach there is still a place for components, for instance in the form of an UI library.

Unfortunately most, if not all modern (composition-)frameworks force a big part of their architecture on the developer. We love all the modern frameworks, as they are powerful methods of creating rich applications. However, we strongly feel that opinionated frameworks are no substitute for deliberate architecture.

On the other hand, the existing MVVM-libraries are getting rapidly outdated and don't interact well with modern components or development styles.

We created insert name here from our standpoint that you know best what kind of architecture would fit your application and the context of your application landscape. If you want to use MVVM style coding: be our guest. If you want to use Composition: that's great. Use both? No problem.

And for the less experienced developer there are templates available to get you started quickly, either with a composition-style application or with a MVVM-style application.

Seperation of Concerns

SoC in MVVM (horizontal SoC)

SoC in Composition (vertical SoC)

The application stack

If you look at the vertical seperation of a typical application, there are roughly three different abstraction levels:

  • Low: generic building block elements
  • Intermediate: application specific elements
  • High: Business Logic and User Flow elements

Low abstraction level

At this level, the application consists of reusable, generic building blocks. These elements have a function that is generic to most applications. Think of an UI-library with text-field inputs, checkboxes, pills, icon-buttons, etc. But also a bit more abstract: maybe a user card with an avatar. These elements are not specific to the application and are probably configurable (by CSS, attributes, etc) to fit your application. They usually implement a well understood interface to communicate with your application (value-properties, onChange-events, etc) and are reused many times both within and outside of your application.

As these elements can be regarded as black box implementations for all intents and purposes, whether they are made by you or pulled in from an outside source / package manager / etc, all architectural choices are valid. It would be completely reasonable to have multiple elements pulled in from different sources that were built on different technologies. That said, a composition style architecture seems right for the job. Web Components, LitElement, maybe even React.

High abstraction level

At the highest abstraction level we define our business logic. At this level the user flow throughout the application is defined and the behavior of all lower level elements come together to make up the functionality of the application. This is completely custom and unique to your application (unless you're making a ToDo-list-app). Reusability is low at this level: every piece of code performs a unique function. Here we need the state of all lower elements to work together to form the overall state of the application. Composition frameworks usually address this by propagating state and events up the hierarchy or by implementing a state machine / global state. Even before Composition frameworks were a thing this was considered a big mess and for this reason MVVM was created. Indeed a more horizontal SoC would be preferred at this level. At this level we're concerned with abstract functionality and user flow and not so much with more low level technical implementations and state and events. Using an MVVM strategy you could aggregate all code for a view (and since a view usually maps to a Unit Of Work, we could consider a view to be an isolated use case) in one place: the ViewModel. And have a library abstract away all low level interaction with the state of the lower elements.

Intermediate abstraction level

So far we saw that a the lowest level composition fits the bill perfectly and at the highest abstraction level we would benefit from a more horizontal approach. But what about the intermediate level? That's where things get tricky. At this level we find building blocks that are not as generic as the building blocks from the lowest level (inputs, checkboxes, etc). They may not be useful outside of this application, but are still highly reusable within this application. Think of a comment-section or any type of widget. Just as with the low level elements, you could easily think of these building blocks as black box implementations. And as they're probably also used all over the place, it stands to reason that Components would be the best solution at this level. However, at this level, there also is a lot of dependency on the application state and a lot of conditional code to react to user decisions elsewhere in your application. Using event and state propagation would probably again lead to unmanageable code.

Wouldn't it be great to use one library throughout the whole stack and glue everthing together, while still being able to use the right abstraction level at every step of the way?

Library vs Framework

Frameworks usually 'force' the developer to code in a certain way, using certain techniques, certain methods and concepts. And that is not a bad thing! In contrary: this can provide a great developer experience. For instance, it can be a great way for beginning developers to avoid common pitfalls and bad practices. For the experienced developer it offers (in general) that a lot of work on non-functional things like performance, security and UI-visuals is already covered, so the developer can focus on writing the business logic.

If using a Framework has so many advantages, than why would we think unopinionated libraries are better? Well, we don't. We love Frameworks for all the aforementioned reasons.

However...

(and this is a big 'however')

...no concept, no Framework and no methodology is perfect. Each method has it's own imperfections or use cases for which it's less suited. Building large applications usually means that you'll encounter many of these situations many times. And while using a Framework helps you out 90% of the time, it's this 10% where you feel limited in your options and you may have to settle for a less than optimal solution, if the optimal solution is not part of the Frameworks standards.

This is what we mean by deliberate architecture. A standard architecture is enormously better than no architecture, but even better still is an architecture that was created by you with your application in mind.

That is why we don't impose a method on the developer. Rather we offer a set of tools that allow you to choose the right method for every (abstraction) level of your applications stack, while maintaining a consistent syntax and workflow.

Build for speed

We have build insert name here with rendering speed in mind. Most Composition frameworks nearly require an SSR module or plugin to approach a native performance experience. With insert name here we stripped most of the ancient browser compatibility code that makes most frameworks bloated and underperformant, while still maintaining compatibility with a wide range of browsers. We believe the choice for SSR is a valid one, but shouldn't be made just to compensate for lack of performance of a framework.

MVVM Reinvented

The 15 years after the introduction of MVVM have seen many flaws and pitfalls, but also fixes and best practices. insert name here sets out to embrace those practices to create a great MVVM and SoC experience.

Some of the points that are addressed:

  • (placeholder) Decoupling the ViewModel from the library
  • (placeholder) Decoupling the View from the ViewModel