Building Scalable Frontend with Composable Components
The internet has become an essential part of our lives, with over 5.4 billion users – a staggering 67% of the global population. Since 2018, this number has skyrocketed by 45%, and the pace is only accelerating.
This explosive growth isn't just about numbers, it's about a fundamental shift in how we interact with the digital world. Users are becoming increasingly demanding, expecting seamless, intuitive experiences delivered at the click of a button. The rise of AI-powered content creation further fuels this demand, with users generating and consuming personalised content at an unprecedented rate.
This isn't just a technical hurdle, it's a strategic imperative for businesses to remain relevant and competitive. The future belongs to applications that can anticipate needs and deliver exceptional, personalised experiences, all while scaling rapidly.
However, the challenges present an exciting opportunity for those who embrace agility and composable solutions. We've entered the age of composable scalability, where modular, adaptable building blocks empower developers to craft future-proof applications. These innovative components don't just survive ever-changing user demands; they embrace them, constantly evolving and adapting to deliver experiences beyond expectation at an unprecedented scale.
Scalability in Atlassian’s Products
Atlassian's trajectory offers a compelling case study in scaling and evolution, vividly illustrated by its ever-expanding product suite. Founded in 2001, the company launched two flagship products: Jira in 2002, designed to streamline project management, and Confluence in 2003, fostering seamless collaboration and knowledge sharing. Far from remaining static, Atlassian has consistently shown remarkable flexibility and agility in adapting and scaling its offerings to meet the evolving needs of its users.
Jira’s evolution over the years exemplifies this adaptability. To date, there are seven versions of Jira, each designed for specific workflows and industry requirements. Jira Service Management, launched in 2013, was created for IT service desks. Jira Work Management, introduced in 2020, was developed for business teams. This diversification is a direct result of Atlassian's commitment to adapting its products to meet the modern worker where they are and anticipate their future needs.
Atlassian's scaling prowess extends beyond features and functionality, deeply ingrained in its ability to support a vast and ever-growing user base. Atlassian proudly serves over 260,000 customers worldwide, with 85% of customers adopting its cloud platform as of 2023. This widespread adoption underscores Atlassian's expertise in data scalability, confidently managing the demands of diverse workflows and massive data volumes with unwavering reliability and performance.
What is Scalability?
“When a company scales, its products and tools need to scale right along with it.”
Here's a closer look at the three key dimensions of scalability that we prioritise to ensure Atlassian tools evolve with your business:
As products scale, they demand multidimensional scalability: operational efficiency for growing workloads, strategic alignment with evolving markets, technological advancement to stay competitive, ecosystem integration for broader IT compatibility, and enhanced security against emerging threats and compliance demands.
Scaling products involves addressing different aspects at various times and with varying intensity. While there are well-known strategies for scaling backend aspects like APIs, databases, and hosting services, scalability in the frontend presents its own unique challenges. How does this concept of scalability translate to the frontend of product implementation? This question often leads to exploring different approaches and solutions specific to frontend development.
Scalability in Frontend
Scalable front-end components in web development refer to the elements of a web application that can efficiently adapt and perform under varying conditions, primarily in two key aspects:
In summary, scalable front-end components are those that can grow in terms of features and data handling capacity while maintaining high performance, usability, and code manageability. This adaptability is crucial in today's dynamic web environment, where user needs and technological capabilities are constantly evolving.
Scalable Component Design
To build applications that can grow and adapt, implementing core guiding principles is pivotal. These principles provide a foundation for teams to develop components that are scalable, maintainable, and performant. They act as a blueprint, ensuring solutions evolve sustainably as products and their data requirements expand.
Guiding Principles
Principle 1: Strive for self-contained components. Each component should include everything it needs to function properly, including its code, data, and any necessary assets.
Rationale:
Implications:
Principle 2: Unified way of Data Handling.
Rationale:
Implications:
Principle 3: Promote Component Discoverability
Rationale:
领英推荐
Implications:
Principle 4: Enforce unidirectional data flow and parent-child isolation
Rationale:
Implications:
Examples from Atlassian Products
Few examples of how we, at Atlassian, follow these guiding principles to create Scalable frontend components.
Issue Fields
At the core of Jira's functionality are the Issue View, Issue Create, and Issue Transition features. These are powered by a variety of Issue Fields such as the Project Field, Assignee Field, Reporter Field, Due Date Field and many more. Jira provides a vast selection of fields, over 80 different types of fields, enabling users to tailor their interfaces to their specific requirements.
Each Issue Field is designed to be intuitive: they present a read-only view on the Issue View by default, which can be transformed into an editable state with a simple click. Conversely, during Issue Creation or Transition, these fields are editable from the outset. The fields themselves are diverse in their design, accommodating a range of inputs from text fields to selections made via dropdown, radio buttons, checkboxes, and cascading selects, along with date-time pickers. The Assignee Field, for instance, is enriched with avatars for each option and a typeahead feature to swiftly locate people.
To prevent redundant development and maintain a consistent user experience, our approach focuses on creating modular Issue Fields as discrete components. They encompass all necessary functionalities internally, such as:
Breaking down further, each field type caters to specific interactions: Edit Only for data entry, View Only for display, Inline Edit for dynamic toggling, and Form Field for structured input.
/* This is a basic skeleton example of Edit Only Select Component
* with its query to fetch options
*/
const SingleSelectEditOnlyField = () => {
const suggestionsData = useLazyLoadQuery<SingleSelectEditViewQueryType>(
graphql`
query singleSelect_suggestionsQuery(
$id: ID!
) {
node(id: $id) {
... on JiraSingleSelectField {
edges {
node {
value: id
label: value
optionId
isDisabled
}
}
}
}
}
`,
{ id: props.fieldId },
);
return (
<Select
options={suggestionsData.node.edges}
/>
);
}
As shown in the above example, the SingleSelectEditOnlyField defines the Data Schema and the UI associated with it, within the component.
Individually, these components function effectively for their intended purpose. Collectively, they form a composable architecture that aligns with the scalability and performance needs of Jira. This design allows for individual components to be developed, maintained, and enhanced independently, underpinning the seamless and efficient evolution of Jira's capabilities.
As shown in the above example, the SingleSelectEditOnlyField defines the Data Schema and the UI associated with it, within the component.
Individually, these components function effectively for their intended purpose. Collectively, they form a composable architecture that aligns with the scalability and performance needs of Jira. This design allows for individual components to be developed, maintained, and enhanced independently, underpinning the seamless and efficient evolution of Jira's capabilities.
Validation Engine
The Validation Engine stands as a cornerstone in data migration processes, meticulously designed to scrutinise and validate the diverse landscapes of data transfer before initiation. It is equipped with a dynamic range of Validation Checks, Reporting, and Remediations, each attuned to the specific requirements of different migration projects. With the growth of our product suite, the intricacies of these migrations intensify, necessitating a Validation Engine that can dynamically scale and adapt to these intricate ecosystems.
To meet these demands, the engine is built on the principle of composability. Each component is self-contained, ensuring easy integration and scalability. This modular design allows the Validation Engine to evolve alongside our products, maintaining efficiency and reliability even as migration challenges become more complex.
The architecture of the Validation Engine is an example of the principle of composability in complex systems. Central to this architecture is the Validation Engine Core Component, which operates as the orchestrator, integrating configurable modules to suit the varied data migration needs of the feature teams.
This core is where the selection and configuration of modular Validation Checks take place. Teams can choose from an array of checks, such as space conflicts or public access validations, and couple them with corresponding Remediation and Reporting components.
In practice, this means that feature teams can compose a version of the Validation Engine that precisely matches their feature’s requirements. The engine's modular components not only streamline the validation workflow but also scale with the product, adapting effortlessly to the increasing complexity of data migrations. This modular and scalable approach underpins the engine's capability to support our evolving product suite while preserving performance and reliability.
In the above two examples, each element is crafted to perform autonomously yet integrates seamlessly when synchronised with others. This integration offers unmatched versatility — components can be modified or interchanged without disrupting the system's overall functionality. Such adaptability is key to the system’s longevity and is instrumental in supporting the increasingly complex needs of our Products, ensuring that the engine remains an integral asset for our migration teams.
What next?
As the digital landscape transforms with interconnected devices, virtual worlds, and personalised experiences, user expectations will soar. Applications must be more than functional; they need speed, adaptability, and the ability to meet individual needs. This demands a fundamental change in how we build products.
The answer lies in composability and performant scalability. Building applications from pre-tested components unlocks agility and innovation. Imagine apps constructed like Lego sets, with features that fit together seamlessly, evolve easily, and perform flawlessly as they grow.
Composability empowers rapid innovation, real-time adaptation, and faster value delivery. Performant scalability ensures applications handle increasing data and user demands without sacrificing responsiveness. This keeps our creations robust, future-proof, and adaptable.
In this dynamic future, we must adopt these building blocks for a better digital experience. Let's prioritize composability and performant scalability – not just for technical prowess, but to create adaptable, maintainable, cost-effective, and future-proof applications. By doing so, we create a world where technology bends to our needs, not the other way around.
As we look towards the digital future, let us remember: Scalability isn't just about size; it's about agility, efficiency, and the freedom to evolve alongside our users. By embracing composability and performance, we can build applications that not only survive the future but thrive in it.
Digital Creative Designer | Researcher | Prompt Engineer | Staff Engineer
1 周Interesting read Prithveesh Goel. When we consider validation with respect to data integrity, do these checks kick in at both the point of data entry and data storage to ensure integrity is preserved throughout the flow of a data point in the system ?
Frontend Engineer 1 at Amazon
6 个月This is pretty good read. Just one query: don't you think composing components can make it difficult to pass props sometimes. E.g. if hierarchy increases props drilling situation may occur. Second, when we compose components into parent and child there can be situations that parent has multiple children but props passed from parent are not required by all children and in that case heavy computation children will re-render unnecessarily. Third, composability between parent and child will be direct and their relation will not depend upon abstractions right so I suppose it violates dependency injection principle. Let me know your views on the same.
startups enthusiast
6 个月Pretty useful insights , the guiding principles will help the developers for sure. Shared this article with the team...nice article Prithveesh Goel , thanks
Software Engineer at Nike | AWS cloud, Spring Boot, Java, Microservices
6 个月Considering unified data management, if components collaborate and share data, would that not act as a bottleneck for other components in cases such as locks where in one components bombard db instances with multiple hits?