Skip to content

Hammock thoughts

Current plan

domain driven frontend, Architecting UI3 min read

So, It's about time we have a plan, or at least an initial one. After thinking, brainstorming with my team, deciding, formulating and any other possible verb, I thought it's about time we get to work. The actual action items where already established as part of creating an execution plan, but there are a few minor steps.

I'll split this one into three sections:

  1. High-level design - The main idea behind the decisions

  2. Next steps - Action items and how we proceed

  3. The vision - A few thoughts I keep at the back of my mind and see if the garden agrees with me or not.

High-level

Essentially, I have two main guiding principles - co-location of files, and separation of ui from state.

Recently my wife suggested a new way of organizing one of our closets. Up to that point we had one pile of bedsheets, one pile of pillow cases, etc. This was great and the closet was organized and pretty. But after a while we realized that when we change bed sheets - we take a bed-sheet, then go through the pillow cases and look for the matching pair, and so on. What my wife suggested if to create "bundles" - we put a full set into a pillow-case. Essentially the closet looks the same now, but when we want to change a set we simply take a ready made set out of the closet and switch it.

This is the same in our code. If I want to add a user capability, in most cases I'll add a user-action, then it will affect the user-reducer and possibly a few components. So why not keep them close together? How about the tests? Ever opened a pull-request just to be reminded you forgot to write the tests? Same goes here - if they are close they are just there and we won't forget them.

Separation of state from ui is explained very nicely by Michel Werstrate, and many of my thoughts are based on his talks. The ui, or at least the current ui is just one of the possible ways to display the current state of the app. That's why our state and the ways we can operate on it should be completely separate from the actual ui. Moreover, the state should clearly express the app logic and the different functionalities we have.

There are more subtleties, but these are my general guides. Oh, and of course constantly reminding myself to keep it simple...

Next steps

First off, we need to reorganize the file structure to support co-location and modules. This step was quite straightforward - one of us moved everything around, fixed imports and merged back. Although (mistakenly) we created a ton of git issues, this wasn't too critical.

Meanwhile, we also fixed the app layout. We had some legacy css and past assumptions that proved wrong so we wanted to clean that up. This wasn't a critical path in the refactor plan, though did provide a lot of benefits. We removed a lot of dead css, moved more to styled-components and used more plain css grid instead of external libraries.

The final step, which we are still in, was to refactor each module and move it to mobx. This was the core of the refactor - taking each module, clearing up the functionality and understanding through our work how we would like to structure things. We started by simply separating everything into the "obvious" modules - essentially each screen. At this stage we ignored all common logic (authentication, user, account and such) and started from refactoring the pages themselves.

We take a self contained module, move all of its logic to a typed mobx store. Then we simplify the components themselves, and move the to TS as well (assuming they don't have bothersome dependencies). Add tests for the store and viola - a refactored module.

We try to keep things simple and once we need reusable logic / components see what the best fit is, and not guess in advance.

Vision

While we are gardening our frontend, I like to keep in mind the vision. I can't say I know what the garden will look like but I do have a few thoughts. I know I would like to detach the router from the component tree and have it affect just the state. This is usually the last part to disconnect the ui from the state, in modern React apps. However, as much as I would like to do so I decided first to complete refactoring all modules and then fix the router.

The other part which I hope to see how it grows are shared logic and components. As (I believe this quite obvious by now) I hope to find a way to create a domain oriented component library, I will groom the garden in that direction, but only when it fits. This is part of the gardner's struggles - although you really want an apple tree, it might not fit there. So lets wait and see what happens.

I guess that's enough for now.

p.s. I hope to either re-write this post once in a while, or move it to a gist where I could see the changes over time. I'll keep you posted

© 2022 by Hammock thoughts. All rights reserved.
Theme by LekoArts