Lets start with some Problems.
If you have written approx 50-100K lines of code at frontend then you can easily understand that “Ease of Adding a new Module/Modify Existing Module” decreases as our codebase size increases.
Sometimes, We apply lots of hack or quick dirty solutions. Many times we are unable to deliver proper solution. Over the time, our frontend repo become a “MESS”. I have seen many such projects.
Problem 2 : UI Revamps
Frontend team are asked to deliver some “UI pages”. Team focus more on UI behaviour. So we get biased. Our whole architecture/design is highly influenced by the UI interaction and UI behaviour. But the problem is UI changes over the time.
Our beloved manager try to bring UI changes again and again. Sometimes they decide to revamp whole page. Many times they ask for very small changes but coding effort for those small changes are huge because of “Architecture” or more preciously “Architecture defects.”
How can we have a system where can we perform rapid UI Revamps ?
Problem 3: DOM is EVIL
Because we can call $(“#…”) or document.getElementById(“…”) from anywhere inside the codebase, we produce a highly coupled code
In order to fix something urgently, developer tends to write such ugly code. In the above codebase, developer is trying to calculate SUM of a column of a table.
You can see, developer is iterating over a column of a table. taking column values from DOM. Because it is a currency related column, we are removing “$” from extracted value. You can see why this kind of code sucks. This non maintainable. It has lots of hardcoding. It is violating large number of good practices.
How we can avoid such code ?
Write programs that do one thing and do it well
we can operate whole Linux Operating System using command line interface (CLI). we can use all utility code from command line. GUI are build on top of these command lines Utils.
This is the exact same philosophy we need to have in Frontend Development too.
If we can have this kind of separation than our life will be easy.
We can have this kind of separation in Frontend too.
DOMi vs DOMless
Our frontend Code basically do 2 jobs for us.
- It do DOM Manipulation
- It process our Data, take data from server, send to server, do other business logic.
Now we can visualise Front-end Code with a different angle.
DOMi — This is the UI Layer. Any line of code which deals with DOM Manipulation, DOM Events etc.
DOM-less — This is the Business Layer. Any line of code which is not DOMi.
Can you check any codebase and try to classify that which line of code belongs to DOMi and which line of code belongs to DOMless.
I have seen lots of projects which mix these two layers. In many projects, we can see lots of Business logic code & computation goes inside html/ui layer. DataLayer or Ajax layer has DOM manipulation code for progressbar. Button onClick handler making Ajax call (DOMless) and updating UI (DOMi) in the same callback.
We produce a large codebase where we do not have clear separation between DOM manipulation and business logic. Normally we do not take care about this kind of separation. One line belongs to DOMi and other belongs to DOMless. We must take care about this separation.
If we develop whole application with this kind of separation then it is very easy to replace UI Layer again and again.
At Unicommerce (my previous company), We have revamped some pages more than 2 times. Because our DOMi and DOMless code is not mixed, we were able to do UI revamps easily.
Develop BL Layer First (DOMless First)
We can divide our Frontend team into two sub-teams.
- BL Team — highly skilled senior member can work on DOMLess code. Focus more on code quality and architecture. Writing test case for BL Layer is super easy
- UI Team — focus more on User interaction.
Both team have separate codebase too. Yes, 2 repos.
BL Layer code will contains models, services, stores, flux etc. UI Layer will only contain DUMB Components/widgets.
BL Team will develop fully functional modules/widgets without UI. This is the first Step.
How to Code BL Layer without UI ?
In BL Layer, We do not have UI/DOM, But we have terminal/console. Like Linux, we can develop DOM-less code from Console.
Let’s Imagine we want to develop a TODO List application. We do not have access to DOM. We have access to Console. So we need to work like this
We can develop a full fledged console API. Without GUI, we can operate from console (CLI).
But what about State ? I have recently created a JSON Viewer by which you can visualise JSON in tabular format. like this
We can see, I am operating whole TODO Application from console API. JSON viewer is helping me in visualising the current state of application.
React-JSON-viewer convert JSON data (state) into tabular format. You can see JSON viewer demo here — http://nsisodiya.github.io/react-json-viewer/
We can develop modules separately.
What is our VISION for frontend code development. We want to develop a highly reusable plug and play module/widgets. If this is the vision then why we develop all modules/widgets at once. We should develop them separately. We must develop them independently.
Once our BL Layer code is done, we can now code our UI layer. Our UI layer code should be dumb. It should not contains any Business Logic. BL Layer exposes API interface to UI Layer. Both Layer communicate using predefined API.
Do not worry, We have a demo.
We need to write our BL Layer such that “coder/developer” should not be able to access to the DOM.
Problem — How to restrict DOM manipulation from BL Layer ?
Solution — Web Workers
We can put our BL Layer inside Web Workers.
If you force your developer to write BL Layer inside Web Workers, your developers automatically produce a Highly Decoupled code.
we can execute this BL Layer on Server too. You can write test cases for BL Layer very easily. You do not need test cases for UI layer. UI Layer is dumb.
We should put Whole BL Layer inside Web Workers.
How BL Layer and UI will communicate ?
We have postMessage API for communication between UI Layer and BL Layer.
If we want to have this BL Layer on server then we can use WebSocket for communication.
Smooth Animations and Transitions
I assume, most of the code belongs to BL Layer which is executing in separate thread. We are not doing much computation in main UI thread, so naturally this kind of separation will help better transitions and animations.
In React world, Flux is part of BL Layer. So let’s put Flux inside Web Workers.
Flux inside Web workers
We can see, our client is divided into two part.
BL Layer is DOMless. Flux and all kind of DOMless code is executing inside Web Worker. We are using postMesssage API for UI Layer to BL Layer communication.
UI Layer “CANNOT” Interact with Server
BL Layer “CANNOT” Interact with DOM
Both Layer “CANNOT” send Callback to each other, they send only JSON Data — just like a REST API or WebSocket communication.
UI Layer send signal to BL Layer. Every time we have any update on Store, we send signal to UI Layer. UI layer rerender with new State.
- Always have clear separation between UI Layer and Business Logic Layer
- BL Layer (DOMless) do not need access to DOM so keep it inside Web Worker.
- UI Layer should not communicate to Server.
- We can have 2 repository for client side code.
If you are worry about performance of web workers because BL thread is doing a “copy & transfer operation” then we can solve this problem using “Adapter/Bridge”. We can write a adapter that in “development mode”, BL Logic will be executed inside worker thread but in “production mode”, BL Logic will be executed in UI thread. Both Layer will sit inside main UI thread. — “check Update 2”
Please file bug/issue on main repo.
By — Narendra Sisodiya (Twitter — nsisodiya)
Author can be contacted at — narendra [@] narendrasisodiya.com