Motivations
For users of the design system who are contributing to Kolibri product ecosystem development, two needs are in conflict:
- Rapid iteration allows the design system to rapidly respond to needs with new and improved components, new and improved design patterns, and rapid fixes
- Long-term stability allows the design system to form a stable and predictable foundation on which contributors can confidently build, with the expectation that the resulting work will not need to be revisited or break in the future
Our release process is designed to support both of these needs by being precise about what kinds of changes can happen in which types of releases, and also and facilitating an upgrade process to help all Kolibri products (specifically the Learning Platform, Studio, and Data Portal) stay up-to-date.
Semantic versioning
We use semantic versioning to help define what kinds of changes go in different kinds of releases.
Given a version number MAJOR.MINOR.PATCH
, we increment the:
MAJOR
version for incompatible or breaking changes. For example:- A previously optional prop becomes required
- New design guidance is added that contradicts previous guidance or creates a new fixed rule
- Layout updates are made to a component, e.g. a CSS
display
prop changes fromblock
toinline
or the default width changes - Clarifying question: an update would potentially require someone updating their code, e.g. renaming a component
MINOR
version for new or backwards-compatible functionality. For example:- A new component is added
- Documentation or design guidance conventions (as opposed to rules) are added
- Purely stylistic updates are made to a component or a new prop is added
PATCH
version for backwards compatible bug fixes. For example:- A minor bug is fixed
- Documentation and design guidance fixes or clarifications are made
Design patterns and APIs
The design system provides two kinds of "contracts" which may change from release to release:
- The set of design patterns and guidance describe the current UX/UI conventions and best practices
- The set of library components and their configuration options describe the current API
Significant changes to design patterns can be as important as API changes. For example, if we were to introduce strict new guidance that says "No text should ever be smaller than 11px", this would be considered a MAJOR
version change because it requires us to go through the Learning Platform, Studio, and Data Portal to ensure that this new guidance is actually being followed.
Technical details
Git branches and tags
The design system is currently developed and released from a single main
branch. Updates are made in transient feature branches, tested, and merged into main
. Specific releases (such as v1.2.3
) are represented as Github releases and Git tags.
The single-branch model does not support maintaining multiple releases in parallel – for example, releasing a new v1.2.3
after v1.3.0
has already happened. If this becomes necessary at some point we would make a dedicated release branch called v1.2.x
for the purpose, similar to Kolibri's branching model.
Update policies
- All user-facing changes for each release should be documented in the changelog.
- The unstable or develop branches of product repos should track the
HEAD
of the design systemmain
branch. It is the responsibility of the Design System Circle to make sure this happens. - The stable or release branches of product repos should be pinned to a stable, tagged version of the design system.
'Next' and 'Deprecated' components
To help smooth upgrades, the design system has a process for making both pre-release and deprecated versions of individual components available from a single monorepo:
Within a major design system release, components always have a current stable version. Components may also optionally have a next
and/or deprecated
version available, allowing access to newer or older major versions respectively.
For illustration, assume that the current stable version of the design system is 2.3.4
. All importable modules are by default the 'current' version. For example:
// imports KButton version 2.3.4 (current stable)
import KModal from 'kolibri-design-system/lib/KButton';
If (and only if) we plan on introducing breaking changes to a component, we would add a sub-directory called next
to house this work and allow people to test or even use the alpha version while they are still mostly using 2.x.y
stable:
// imports KButton version 3.0.0-alpha (next unstable)
import KModal from 'kolibri-design-system/lib/KButton/next';
An update to next
code might count as a patch release bump for the current stable semantic version. For example, we might release 2.3.5
with a changelog entry like:
Version 2.3.5: Renamed the text
prop in lib/KButton/next
to label
Once we release KDS version 3.0.0
stable, code in next
becomes stable, and stable becomes deprecated
:
Version 3.0.0: Added a new version of KButton
addressing API inconsistency
// imports KButton version 2.3.5 (deprecated)
import KModal from 'kolibri-design-system/lib/KButton/deprecated';
// imports KButton version 3.0.0 (current stable)
import KModal from 'kolibri-design-system/lib/KButton';
It's unlikely that at this point a new next
version of KButton
would also be introduced, because we want to minimize churn and and unnecessary breaking changes. However, in rare cases we might need to do this, and there be three versions all available simultaneously:
Version 3.0.1: Added a new alpha version of KButton
to address unexpected issue
// imports KButton version 2.3.5 (deprecated)
import KModal from 'kolibri-design-system/lib/KButton/deprecated';
// imports KButton version 3.0.1 (current stable)
import KModal from 'kolibri-design-system/lib/KButton';
// imports KButton version 4.0.0-alpha (next unstable)
import KModal from 'kolibri-design-system/lib/KButton/next';