Frontend Architecture Example
A review of the frontend architecture of the Network Nervous System of the Internet Computer.
Frontend Architecture
I’d like to share the architecture of the project I’m currently working on. I love discussing frontend architecture because it’s still the Wild West despite all the frameworks. Therefore, there is always something to learn, improve, and discover.
NNS Dapp
The project I’m working on is an application to manage the Network Nervous System and other DAOs of the Internet Computer. In summary, it’s a web application to manage multiple DAOs.
NNS Dapp Frontend Architecture
The frontend project has five main modules:
Components
Services
State
Api
Utils
And this is how they interact with each other. The arrow represents a module importing from another.
Utils Module
The utils module is independent and allowed to be used by all. Utils are pure functions, although some functions use date or randomization, making them impure. Utils can use other utils.
The utils folder is split by domain.
API Module
The api module is responsible for making requests. This makes it easier to avoid calls during unit tests. We mock the api module and then test whether the expected call was made.
The NNS Dapp interacts with multiple backends. Therefore, this module is further split by backends.
The API module is independent of the other modules, even having its own utils (in theory, not in practice 😅).
State Management Module
We use Svelte; therefore, we use Stores to save the data after fetching it or manipulating it in the frontend.
Stores are allowed to import only from the Utils module.
We also use the concept of derived stores to manipulate, combine, transform, and filter the data so that components don’t need to have business logic. These derived store import from other stores, but a writable store is not allowed to use another store.
Services Module
This module is like the C in an MVC architecture. Services implement user stories using the API, Utils, and Store modules.
We use a functional approach, and all of our services are functions. The services are grouped by domain. For example, all flows related to one part, such as neurons, are in one file.
It is not very common, but services might use other services.
The only module they are not allowed to import is the components.
Components Module
The final frontier of the project is the components: the UI layer the user interacts with.
The component module is allowed use services to trigger user stories, read (but not write) from stores, and import utils and other components.
The two rules of components are:
Do not write to the store. This is done in a service.
Do not import from the API module. Calls to backends must be triggered in services.
Components Division
The division of components is simple:
Route Components. “Most Parent” component of a page. Not allowed to be reused.
Page Components. This is specific to our application, where a path, such as “/neurons,” might render different components depending on the DAO. Each type of DAO has its page component. They are not reusable.
Components. The rest of the components are mainly grouped by domain. Components are allowed to import other components.
UI Elements. Most of them belong in the GIX Components library. They are allowed to use other UI elements
Benefits and Challenges
A few benefits I like from our architecture:
Mocking requests for unit tests is effortless.
Having user flows in functions makes reasoning about and maintaining them easy.
Independent stores are testable stores.
There is no circular dependency.
And a few challenges we are facing:
The utils module is becoming hard to manage and remember what we have and don’t have.
Loading the data in the store is the responsibility of a service, but the service needs to be initiated by a component. We need to remember to trigger the service when some data is required.
Our component split is imperfect; some folders are becoming too big to remember what we can or want to reuse.
Library Agnostic
This architecture is library-agnostic and is easily applied in any frontend framework.
Let me know what you think, and I’d love to hear about your frontend architectures. Let’s move from the wild west to the industrial revolution.
Thanks to my team for reviewing at DFINITY this article!
It looks kinda like Clean Architecture-ish approach. Very nice! Great to see that there are frontend projects that care about proper robust architecture.
Hey Llorenc, this architecture is pretty interesting and I have similar stuff come up as well.
I'm curious if you have a sample repo to see what an example looks like?
It would be interesting to see it in more detail to see what it looks like in practice