Front End Architecture — Making rebuild from scratch not so painful

Fabrício Mendonça
SHARE NOW TECH
Published in
6 min readMar 15, 2018

How to create a package to handle application business rules, API calls, localStorage and change frontend frameworks as often as you want to.

Single page applications are the mainstream of front-end development for the last years and they are becoming more complex every day. This complexity brings the opportunity for the growth of frameworks and libraries to offer different solution flavors for front-end developers. AngularJS, React, Redux, Vue, Vuex, Ember are a few options available over there.

A team can choose any kind of framework and/or ecosystem — car2go is using Vuejs for new projects — but once an application becomes more complex, the term "rebuild from scratch" starts being a nightmare for any developer. Having the business rules, usually, tied to the FrameworkOfChoice way of doing things and the need of rebuilding the whole front end from scratch certainly will lead the team to weeks (or months) of business rules implementation and testing.

This can be avoided by separating those business rules from the FrameworkOfChoice. I will show a simple, but effective, way of implementing this separation and prepare your SPAs to be "rebuilt from scratch" anytime you need or want to, using the greatest framework of last week! ;)

Note: I will write the examples in TypeScript, like we are doing at car2go web team, but ES6, Vanilla JS and so on can be used at all.

A little bit of Clean Architecture

Using concepts of Clean Architecture, the package will be organized into four different groups: Entities, Interactors, Services, and Exposers.

Entities
This group will contain business object models, data interfaces. Properties validation rules can be implemented into this group.

Interactors
This group will contain the business rules.

Services
This group will contain the API calls, LocalStorage handling, etc.

Exposers
This group will expose Interactors methods to the application

A Clean Architecture (CA) advocate would say that this is not CA at all and would be probably right, but looking at the concentric layers picture it is possible to relate this architecture model to it.

Uncle Bob, The Clean Architecture
  • Entities -> Enterprise Business Rules
  • Interactors -> Application Business Rules
  • Services and Exposers -> Interface Adapters

There are also boundaries crossing with the Dependency Inversion Principle referencing Services inside Interactors.

This simple architecture makes things easier to mock, test and implement. :)

Coding!!!

The example project can be cloned from:
https://github.com/fabriciomendonca/business-rules-package

We will create a package to fetch, create and save posts using the jsonplaceholder API.

Project structure

/showroom # A Vuejs app to test and document package usage
/playground # A simple usage example in NodeJS
/src
/common
/entities
/exposers
/interactors
/services
__mocks__

The source folder is structured in a way to see each layer, it is also an option to organize it by functionality.

Common folder

This folder contains shared adapters to use inside different layers. e.g: HttpClient class — creates an instance of axios library and abstract some methods of it as well.

Entities

In this group, we will create our Business Objects interfaces and classes. If the object needs to own some rules, it would be nice (not mandatory) to implement them here. But it is also acceptable to just export data interfaces and let all validations to the Interactors layer.

To illustrate that, both data interface and class will be created for the Post business object.

JSONPlaceholder Post data object has 4 properties: id, userId, title and body. We will validate the title and the body, assuming that:

  • title should not be empty and should not have more than 256 characters;
  • body should not be empty and should not have less than 10 characters;

Also, we want to validate properties separately (previous validation), provide additional validation for them and inject (copy) data into the object. With this, we can come up with some behaviors to test.

// Post business object
- copies an object data into a Post instance
- title is invalid for empty string
- title is invalid using additional validator
- title is invalid for long titles
- title is valid
- title is valid using additional validation
- body is invalid for strings with less than 10 characters
- body is invalid using additional validation
- body is valid
- body is valid using additional validation
- post is invalid without previous validation
- post is valid without previous validation
- post is invalid with previous title validation
- post is invalid with previous title and body validation, title is valid
- post is invalid with previous title and body validation, body is valid
- post is valid with previous title validation
- post is valid with previous body validation
- post is valid with previous title and body validation

Let's implement the Post interface and class now.

The trickiest thing here is to detect if the post properties were validated previously while checking if the post is valid and to not use the internal validation if any kind of previous validation was used.

The properties _validTitle and _validBody should be initialized as undefined and get a boolean value when the previous validation method is used.

This way, it is possible to use property live validation in the presentation layer and use some cool third-party libraries for additional verification — in our example application (showroom), VeeValidate.

Services

The Services are classes to load/send data from/to APIs, handle localStorage operations, socket connections. The PostService class is pretty simple.

The PostService mock-up is simple as well. Check here.

Interactors

The Interactors are classes that handle business rules. They are responsible to verify if all conditions for a specific user request are fulfilled — basically, they implement use cases.

In this package, an Interactor is a singleton which give us the possibility of store some state and avoid unnecessary HTTP calls, provide a way to reset an application state property (e.g: restore post data after losing track of changes), decide when new data should be loaded (e.g: a socket connection with a NodeJS application to live update critical content).

Once only interactors methods will be exposed to the presentation layer, all business object creation will be handled by them.

We can come up again with some behaviors to test.

// PostInteractor class
- returns a new post object
- gets a list of posts
- returns the existing posts list (stored state)
- resets the instance and throws an error while fetching posts
- creates a new post
- throws there is no post data
- throws post data is invalid when creating post
- throws a service error when creating a post
- saves a new post
- throws a service error when saving a post

Let’s implement the PostInteractor interface and class now.

Exposers

We are now ready to expose our package to applications. The reasons to use exposers are that we publish an API which can be consumed independently of the implementation, export just a set of methods based on environment or application and use different names for them.

Often, exposers will simply export those methods. So we don’t need to add logic.

Exporting the library

Using the library

For the showroom, we will directly link the package to the project. But it is possible to publish it to npm, a private registry, install it from GitHub, GitLab. It is a simple npm package and will work as any other one.

To run the showroom, go to the folder /showroom.

Then, run npm install before running npm link ../ to guarantee the package will be installed correctly and will not be removed by npm.

The npm link command is useful when developing libraries once it will automatically update the dependent node_modules folder when package build changes.

The showroom is live here.

A simple NodeJS (yeah! we can use this approach for back-end apps too) usage example application can be found inside the playground folder. To test it, just go to this folder, run npm link ../ then run node simple-usage.js and check the console to see the results.

If you have any doubt, suggestions or disagree at some point, please leave a comment and let's discuss about front-end architecture. It is really awesome to see different visions for the same problem. There is always room for learning something new. Thanks for reading! :)

--

--

Fabrício Mendonça
SHARE NOW TECH

Senior Front End developer at Wunder Mobility, skateboarder, roller skater and bass player