Status: Closed (View Workflow)
Affects Version/s: None
Fix Version/s: None
Development Team:Stripes Force
Agree and document that stripes-components should only contain presentational components, making it possible to:
- Simplify the dependency graph for modules
- Render and test all components in isolation
- Free up module developers from lock-in to specific solutions
The industry standard on design systems teams is a reusable component library containing only presentational components.
A presentational component is:
- Easy to reason about
- Context agnostic
- Independent and isolated
This means it:
- Receives data and callbacks exclusively via props.
- Has no dependencies on any stores or state management tools (Redux, Flux, etc.).
- Presentational and Container Components
- A Working Theory of Components
- Salesforce Lightning Design System docs
Almost all of the components in stripes-components are presentational. There are a handful that aren’t.
Those components cause challenges with:
The handful of components in stripes-components that aren’t presentational have dependencies on stripes-core, stripes-form, redux-form, react-redux, and redux. There are also a few utility functions intended for use with stripes-connect.
Peer dependencies are dashed
Circular dependencies are red
We haven’t been able to take advantage of the efficiency and quality benefits of our tools with components that aren’t presentational.
Not all of our components…
… can be rendered in Storybook. Storybook is built exactly for this use case - documenting a library of purely presentational, reusable components.
... can be tested by themselves. If it needs any outside context, a data store, or a back end, it won’t run in the stripes-components test suite, and it’s not presentational.
Example: the <Settings> component requires the stripes object be retrieved through the legacy React context API, so it can’t be rendered in Storybook or tested in isolation.
On the back end, the FOLIO project is fully committed to a microservices philosophy. Individual modules make their own choices about language and libraries, as long as they adhere to a limited contract.
The front end is more restrictive because of runtime needs, but front-end FOLIO module developers are still free to make their own choices about state management, server communication, and adoption of UI components.
When components are coupled to a specific library (examples: redux and stripes-connect), it limits the ability of module developers to bring alternative solutions into the ecosystem.
Example: the eHoldings developers are interested in alternatives to redux-form, but because so many form components in stripes-components don’t work outside of a redux-form, they’re locked in.
- stripes-components would not consume context from outside the stripes-components repo (this includes intl strings, locale, time zone, etc.); UI modules would consume the stripes-core context and pass it in as props to stripes-components
- stripes-components would have no dependency on stripes-connect, stripes-form, redux-form, react-redux, or redux
- every form component would work independently of redux-form (but still play nicely with redux-form)
- no routing inside components; it would be up to UI modules to handle that responsibility
A stripes-components that meets those requirements would not even have a peer dependency on stripes-core.
In an ideal scenario, the patterns in stripes-smart-components would also be refactored to have no opinions on state management or back end, and thus could be moved into stripes-components. It would be up to individual modules to use stripes-connect (or any other tools) to connect the reusable components through props.
Here’s what that same section of dependency graph for ui-users would look like with a purely presentational stripes-components.
- Agree that restricting stripes-components to presentational components is the right approach.
- Record the rule in stripes-components documentation.
- Prevent future component development from violating this rule.
- Create JIRA issues for existing components and utility functions that do not conform.
If you agree with this direction, please give a thumbs up.
If you disagree with this direction, are there alternative architectural patterns that will solve the three problems presented: dependencies, isolation, and lock-in?