When building a modern frontend framework, the goal is to allow developers to focus on creating features instead of being constrained by specific use cases. A well-designed framework gives developers flexibility, freeing them from bundling concerns, DevOps processes, and runtime or standalone hosting issues.
Below is a list of essential questions that guided the creation of such a framework, addressing real-world challenges developers face today.
For practical insights into the process of framework design, check out the article: “Why You Should TRUST Frameworks (And What It Takes to Build One From Scratch)”.
Index of Key Questions
- How can we share features written in React with non-React applications, like Angular?
- How do we enable communication between features hosted in iframes and the host application?
- How can we avoid treating runtime features like UFOs?
- How do we manage independent module deployment and usage?
- How can we bundle features for consumption as a package, at runtime, or as a standalone application?
- How do we maintain loose coupling between features while still offering tight integration?
- How can we seamlessly integrate features into customer applications we don’t control?
- How do we provide productive documentation and code samples?
- How do we manage shared runtime assets like themes and languages across features?
- How do we deliver new versions of features while ensuring backward compatibility?
- How do we overcome dependency version conflicts?
- How do we support features that operate at different cadences and use different dependency versions?
- How do we scaffold a project that provides all the tools a developer needs from the start?
- How can we offer unified diagnostic tools across multiple features?
- How do we allow the discovery of features at runtime and enable customization?
- How do we streamline collaboration between teams working on different experiences?
- How do we handle state management across features?
- How do we optimize performance while consuming features at runtime?
- How do we design a framework that can solve problems we haven’t anticipated yet?
Key Questions the Framework Aims to Solve
1. How can we share features written in React with non-React applications, like Angular?
Challenge: Many developers today write new features in React but maintain legacy applications in Angular or Vanilla JS. Reusing React components in these environments can be tricky due to differences in lifecycle and architecture.
Solution: The framework should provide tools or abstractions to integrate React components seamlessly into non-React applications, minimizing the need for rewrites or reliance on iframes.
2. How do we enable communication between features hosted in iframes and the host application?
Challenge: Iframes often isolate features, limiting interaction between them and the host application.
Solution: The framework should enable communication mechanisms like postMessage
, shared states, or event-driven systems to allow real-time interaction between iframe-hosted features and the main application.
3. How can we avoid treating runtime features like UFOs?
Challenge: Runtime features can feel disconnected from the host, negatively affecting user experience.
Solution: Rich infrastructure based on services that cover aspects like shared data storage, pub-sub mechanism, runtime discovery and others will allow tight integration in a loose environment.
4. How do we manage independent module deployment and usage?
Challenge: Independently developed modules need to work together without causing version conflicts or dependency issues.
Solution: The framework should support independent module deployment while maintaining compatibility across versions, offering tools to manage dependencies and updates without breaking the system.
5. How can we bundle features for consumption as a package, at runtime, or as a standalone application?
Challenge: Features may need to be consumed in multiple ways, whether through NPM packages, runtime loading, or standalone deployment.
Solution: The framework should allow developers to write features once as React packages and provide smart wrappers to deploy them as standalone apps or runtime modules, ensuring flexibility and reducing redundancy.
6. How do we maintain loose coupling between features while still offering tight integration?
Challenge: Features may need to communicate without being tightly coupled, which can make scaling difficult.
Solution: The framework should support pub/sub models or service-oriented architecture, enabling features to interact dynamically without direct dependencies.
7. How can we seamlessly integrate features into customer applications we don’t control?
Challenge: Embedding features into third-party applications with different tech stacks can cause compatibility issues.
Solution: The framework should offer embeddable components or runtime widgets that adapt to any tech stack, making integration simple and compatible.
8. How do we provide productive documentation and code samples?
Challenge: Developers need clear, easy-to-use documentation and code examples to get started quickly.
Solution: The framework should include well-maintained documentation and live code samples that demonstrate how to integrate and use features effectively.
9. How do we manage shared runtime assets like themes and languages across features?
Challenge: Sharing assets like themes and languages across independently developed features is difficult.
Solution: A centralized asset management system should allow themes, languages, and other shared resources to be easily distributed and updated across all features.
10. How do we deliver new versions of features while ensuring backward compatibility?
Challenge: Updating features without breaking existing functionality is crucial, especially for long-lived applications.
Solution: The framework should support versioning strategies that allow multiple versions of a feature to coexist, with clear migration paths to update without disrupting applications.
11. How do we overcome dependency version conflicts?
Challenge: Conflicts between different dependency versions, such as React or Material UI, can break applications.
Solution: Dependency isolation techniques like module federation or smart bundling mechanisms should help manage conflicting versions, allowing features to use different versions of the same dependency.
12. How do we support features that operate at different cadences and use different dependency versions?
Challenge: Some features may require frequent updates, while others remain static for long periods, leading to version misalignment.
Solution: The framework should allow independent versioning of features, supporting different dependency versions as needed.
13. How do we scaffold a project that provides all the tools a developer needs from the start?
Challenge: A poorly scaffolded project can slow down development by omitting critical tools and workflows.
Solution: The framework should offer an opinionated project scaffolding system that includes testing, bundling, state management, and deployment workflows out of the box.
14. How can we offer unified diagnostic tools across multiple features?
Challenge: Debugging fragmented features with separate diagnostic tools can become complex.
Solution: A unified set of diagnostic tools (e.g., logging, performance metrics, error reporting) should be available for all features, simplifying the process of debugging and optimization.
15. How do we allow the discovery of features at runtime and enable customization?
Challenge: Developers need to discover and customize available features dynamically.
Solution: The framework should offer a runtime discovery mechanism (e.g., feature registry or API) that allows developers to query available features and customize their behavior.
16. How do we streamline collaboration between teams working on different experiences?
Challenge: When multiple teams are working on different features, they need to ensure their work integrates smoothly.
Solution: The framework should provide standardized tools and workflows, such as shared testing environments, CI/CD pipelines, or common module formats to ensure seamless collaboration.
17. How do we handle state management across features?
Challenge: Managing state across multiple features without tight coupling can lead to performance bottlenecks.
Solution: A centralized state management system should allow state sharing and synchronization across features while preserving their independence.
18. How do we optimize performance while consuming features at runtime?
Challenge: Loading features at runtime can introduce performance issues like slow load times and memory overhead.
Solution: The framework should support lazy loading, code splitting, and efficient caching to ensure runtime features don’t negatively impact performance.
19. How do we design a framework that can solve problems we haven’t anticipated yet?
Challenge: It’s impossible to predict every future requirement or use case.
Solution: A future-proof framework should focus on flexibility and extensibility, using a modular design that allows new features and integrations to be added without disrupting existing functionality. Loose coupling between components ensures that changes in one area don’t break the entire system.
Conclusion
By addressing these key questions, the framework is designed to empower developers to focus on building flexible, scalable, and adaptable features. The goal isn’t just to solve today’s challenges but to create a foundation for solving problems we haven’t even thought of yet.
To dive deeper into the philosophy behind this approach, check out the article: "Why You Should TRUST Frameworks (And What It Takes to Build One From Scratch)".