This is a collection of techniques and tools we use at Olio Apps to make UI application development faster and more efficient!
The UI is an aggregation of discrete, composable components. These components are concerned only with presentation, eg. styling and content -- not logic.
- Smallest reusable elements are called Atoms
- They are designed to be generally agnostic of their environment
Atomic components have well defined contracts (eg. props). This expands to their containers.
Global atoms are composed into global, reusable molecules. Global atoms and molecules form the basis of feature-specific Molecules and Atoms. Molecules and Atoms are composed into pages
- Separation of concerns -- you can focus on a single domain and be maximally effective
- Reuse -- need to "bless" every button in the app with a spinner? Update the basal Atom for it
- Parallelization -- folks can be divided into focusing on the pure presentational UI components, while others work on the "logic" pieces
- You can use storybook. More on this below
Storybook is a rapid-development environment for pure presentation components. It is a framework for exercising / displaying all the behavioral variations for components as controlled by their props.
- With storybook, you get an immediate feedback on the components as they are developed
- No need to "hack" the live environment that the components are going to be used in
- Sometimes there is NO live environment yet -- but you will not be blocked because you can use storybook to view your components
- Storybook is to UI component development as test-driven unit-test development is to non-ui component development
Developers can use storybook to interact with the design team, publishing the full range and variation of components in an easy to access way
- You don't need to seed an environment to show all the permutations of particular components and even whole pages
- Designers can easily manipulate the storybook to see what things look like by simulating conditions such as size of that page, values of the props
Compile-time checking of errors. In larger apps, sometimes you will only know that a shape going into a function is incorrect once its in production.
Contract-driven development. Think of types will get developers to start thinking and planning about how pieces interact, first at the function level; next at the module level; finally at the systems level.
Without types, you can only know what the "valid" shape of an object is from its consumers.
- There are infinitely more consumers, and they change all the time
- Without a type or interface, I would have to inspect ALL the consumers of an object to know what its valid attributes are!
- Without types you cannot efficiently describe how a system interacts with itself, or other systems
Redux is global state management for large scale appplications.
Larger scale UIs often need to cache server side state. For example:
- Logged in user
- Incoming unread chat notifications
- Synced media
It is useful to cache this state because you don't want to pull it down all the time. If your app is going to work offline sometime, caching the data from disk in memory in redux is often useful. When some region in that state tree is changed, other interested parts of the UI can "listen" and react to those changes.
UI Backend Modularization
Just as the pure presentational components are organized into modules of specific Atoms, Molecules, and Pages. The "backend" of the frontend is also separated out into modules by feature/responsibility area. These pieces are NOT concerned with presentational concerns But are instead concerned with:
- Navigation (routing)
- Interaction with the API
- Interaction with the device (local storage, services such as bluetooth, push notifications, etc)
Modules are concerned with the management of their particular subslice of the global state (or have their own private state); and the operations against that state -- and nothing else.
- Folks can work on and concentrate on the "backend" of the app while others work on the frontend
- Folks can work on different feature modules within the backend tree
Separation of concerns
- The logical and UI layers can change without breaking each other
- The backend feature modules are less likely to have regressions when they change, as their logic is self contained with the module
- The backend modules may reuse each other using well defined contracts
- For instance we can have a module purely concerned with activity tracking
- That can be integrated with the navigation module which can record activity using the aforementioned module
- The entire functionality of a logical feature / module is easily unit testable because its possible to mock their state without having to mock out the rest of the system
Sitka is an opinionated framework built atop of Redux and Redux Saga. It encapsulates UI backend modules into classes that control both state and operations of those modules.
Sitka ticks all the items of the UI Backend Modularization section. You can safely modify module state via callbacks from the UI.
Sitka implements pub-sub mechanism:
- One module does something
- Other modules can "subscribe" and react to those
Sitka implements background "jobs" - recurring polling tasks.
Sitka is very powerful, and has been implemented in 10+ projects across multiple customers. Alternatives include redux toolkit.
This collection of tools and techniques forms the basis for fast productive UI development projects at Olio Apps. We continue to iterate and build on our toolset every day.