Borak - software developer illustrational
Blog
21.11. 2019 / 00:00

javascript

typescript

front end

sw patterns

CRUST Principle and modular architecture in frontend applications

Modular architecture approach to application development, for long time, was mostly the domain for backend development. Let’s at what the CRUST principle means and how it relates to modern development of SPA.

What is modular

As of the Javascript application on the frontend became more and more complex, the modular architecture became a topic also for the frontend development.
 In those times Javascript concepts like IIFE and revealing module pattern became a hot topic. Later on, tools as requie.js were concieved. The recent situation, compared to the beginnings of the modular approach in Jvascript client-side application is much more various.
On the transpiler part like typescript this problematic is handled without any third-party libraries or the need to use modular design patterns.
Also the ECMA 2015 was an important step forward as the modules became official part of the ECMA specification. Recently, the

script type=module
seems to be supported by most browsers.
On the other parts of the specification, namely the


import, export 
statements and linked constructs the implementation is still poor and we will have to wait some more time for the specification to become the implemented reality.

At the moment, we have to use transpilers to leverage the functionality and constructs the modules provides us. In the case of webpack it’s incorporated to the engine, so we can use the ECMA module syntax as well as we can setup some other module syntaxes.
In the case of Typescript, the modules are included in the language compiler. All we have to do, is setup the module resolution setup in the according tsconfig.json.

 Why modular

Modularity solves the issues with reusability of the code. Coherent modules architecture make the architecture of the app more readable and eliminate friction among developers. Also consistently designed modules lower the risk of merge conflicts and modules impose the code to be run in the strict mode, which betters the overall coding experience and mitigate some javascript quirks. Last but not least, modules impose their own scope, not cluttering the global space.
These are only few points advocating the usage of the module in the frontend development process. The usage of the modules itself provides us important tool to keep the codebase coherent and architecture readable, but it’s not automatically a salvation. There are some more rules that should be taken into account, when considering the design of the modules in your app.

What CRUST stands for

Crust stands for Consistent, Resilient, Unambigous, Simple and Tiny. These are basically few rules that, when imposed to our process of designing the modules, should ensure the development process to be easier and final product to be more maintainable.

Consistent

This says us to keep the surface API of the modules and it’s shape of the exposed methods similar in the core principles.  Further the shape of the output should not vary with different inputs. The consumer should not bother with handling the output that has different shape changing with the input provided.  It’s OK to provide different output for failures and successes. But among these two types of result, the output should be as coherent as possible.

Robust

This term depicts the necessity to consume the input in a few different shapes. It’s always up to the discussion among programmers, what the polymorphic attributes should look like. The golden rule here is to provide handling of the most frequent use cases and wait with further enhancing till the further necessity appears. Just as it is important to provide a few different ways of accepting the input, it is also important to handle the wrong inputs with the properly designed errors.

Unambigous

Means to ensure that the consumer of the module API can always expect the same shape of the output. There should not be dependency of the shape of the output on the parametrs provided. In the opposite case, the consumer would be forced to handle many possible outcomes from the API, which would lead to cluttered code.

Simple 

Means the surface of the modules’ API should be only that complex as the use case the API handles. The API should accept only few compulsory parameters, without which the module could not provide the proper solution. Everything other should be provided in options object. The modules API should be conservative. It means, the module should handle the most common scenarious without optional parameters with some default, most expected, setup. This setup should be possible to overload in the optional options object.

Tiny

The surface of the exposed API should cover all use cases expect at the moment and still the architecture of the module should be ready for further expansion.

Modularity in Angular

Angular’s architecture leverages both ECMA and Its own modules.

Ng module and ECMA module

NgModule are javascript classes decorated through Typescript’s decorator function defined in the ECMA module of the @angluar/core. Whilst it is considered as good convention to define one class per file, which basically creates ECMA modules, the NgModules are angular constructs which serve the purpose of bundling declarable classes (those decorated by the respective decorator) into one place and then provide them through the injector.

Components

There are two basic mental constructs, when it comes to Component classes in Angular.

Containers

Container basically contains logic and handle the traffic from services handling the side effects and providing the data to the application. These Components basically don’t expose API as they are consumers of the services API and provides their results further to the Presentational components.

Presentational components

These components, on the other hand, expose some kind of API through @output decoratorated properties and accepts inputs throught the @input properties. They are self-contained ,modularized pieces of the application, where we can impose all the former rules for the modularized application. Most of the work is already done by the implementation of the decorators itself.

To keep the API consistent for services, we have types at our disposal, we should strive to define the interfaces for all the parameters that the components and services consume. This will allow us to keep the API consistent as we can reuse the types for parameters at different parts of the application for common use cases.

More by Borak

To maximalize your user experience during visit to my page, I use cookies.More info
I understand

#BORAKlive

This page is subjected to the Creative Common Licence. Always cite the Author - Do not use the page's content on commercial basis. Comply with the licence 3.0 Czech Republic.
go to top