Skip to main content

· One min read
Nick Tchayka
STATUS - DRAFT

This BEEP will contain the index of all Booster Evolution Enhancement Proposals, known as BEEPs. BEEP numbers are assigned by the BEEP editors, and once assigned are never changed.

In the future, the BEEPs will be listed here by category. For now, use the sidebar on the left.

A good starting point is BEEP 1, which describes the BEEP process itself.

· 2 min read
Nick Tchayka
STATUS - IN PROGRESS

What is a BEEP?

BEEP stands for Booster Evolution Enhancement Proposal. It is a document that describes a change or addition to Booster.

Statuses of a BEEP

A BEEP can have one of the following statuses:

STATUS - DRAFT

This status indicates that the BEEP is still being written and is not ready for review.

STATUS - IN PROGRESS

This status indicates that the BEEP has been accepted but is still being implemented.

STATUS - INTEGRATED

This status indicates that the BEEP has been implemented.

STATUS - ACCEPTED

This status is for informational BEEPs that have been accepted.

STATUS - REJECTED

This status indicates that the BEEP has been rejected.

How to contribute to the design process

Everyone is welcome to propose, discuss, and review ideas to improve Booster in the #proposals channel of the Discord server.

Note that the project is in a very early stage, and the contribution to the design process is not well defined.

As some general rules for now, take this into account before submitting a proposal:

  • No "What about if Booster does a 180-degree turn and instead does this completely unrelated thing?". These kinds of proposals are seen as completely out of the scope of the Booster project and will be instantly dismissed.
  • Use constructive criticism. Instead of "remove this, I don't like it", take a moment to think and give actual reasons like "I believe that this function in the standard library is not clear enough, someone could understand this in a wrong way"
  • Is the problem being addressed impactful enough to warrant a change to Booster?
  • How does this impact the Principle of Least Astonishment of the project?
  • How does this impact the Principle of Developer Happiness of the project?
  • How does this impact the Principle of Least Effort of the project? Both externally for the users and internally for the maintainers.
  • Does this proposal fit well with the feel and direction of Booster?
  • What other libraries/languages got you inspired to submit this proposal? How does this compare to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Please state explicitly whether you believe that the proposal should be accepted into Booster.

· 3 min read
Nick Tchayka
STATUS - ACCEPTED

Introduction

This document defines the target audience and user persona for the Booster Framework project, aligning it with its current usage and user base.

While maintaining a focus on guiding the design and development process of the Booster Framework, this definition is not an exclusionary rule but a strategic tool for decision-making. The framework is inclusive and welcomes a diverse range of users, though particular emphasis is placed on specific user groups in design and functionality.

Target Audience

The primary target audience for the Booster Framework is developers in large-scale enterprise environments, familiar with enterprise technologies like Java, .NET, or similar. This includes those working in Fortune 500 companies, especially those transitioning from traditional enterprise technologies to TypeScript in complex projects such as financial transactions.

Additionally, the Booster Framework is gaining traction among hobbyist developers for personal projects, thanks to its ease of use and efficient learning curve. This secondary audience appreciates the framework for its quick setup, minimal configuration, and straightforward deployment, which are ideal for smaller-scale, personal projects.

Who's not the target audience

  • Developers deeply invested in exploring advanced theoretical concepts in programming without practical application.
  • Those who prefer frameworks with a steep learning curve or require extensive configuration.

User Persona

Primary Persona: Enterprise Developer

  • Name: Aarya
  • Role: Senior Enterprise Software Developer

Actions, Motivations, and Pains

  • What do I do?
    • Work on large-scale TypeScript projects, transitioning from a background in traditional enterprise technologies.
    • Develop robust applications for sectors like finance, requiring high security and reliability.
  • Why do I do it?
    • To apply my experience in enterprise technologies in new, dynamic environments.
    • To contribute significantly to business-critical projects.
  • What do I want?
    • A framework that bridges my existing knowledge with modern development practices.
    • Tools that ensure efficiency, security, and compatibility with enterprise standards.
  • What's stopping me?
    • Adapting to new technologies while maintaining high standards of enterprise development.
    • Balancing rapid development with regulatory and security requirements.

Secondary Persona: Hobbyist Developer

  • Name: Navin
  • Role: Hobbyist Developer

Actions, Motivations, and Pains

  • What do I do?
    • Develop personal projects in my spare time, exploring new technologies and ideas.
    • Seek tools that enable quick and easy project setup and deployment.
  • Why do I do it?
    • To learn new skills and stay updated with the latest technology trends.
    • To bring personal project ideas to life efficiently.
  • What do I want?
    • A user-friendly framework that doesn't require extensive setup or configuration.
    • Resources that help me quickly understand and apply the framework.
  • What's stopping me?
    • Overly complex tools that require significant time investment to learn.
    • Lack of clear, beginner-friendly documentation and community support.

Conclusion

This document outlines the dual focus of the Booster Framework's target audience and user personas. Our development and design efforts are directed towards supporting both the enterprise developers transitioning from traditional technologies to TypeScript, and the growing community of hobbyist developers seeking an accessible and easy-to-use framework for personal projects. This approach ensures the Booster Framework remains versatile and relevant across different scales and scopes of software development.

· 4 min read
Nick Tchayka
STATUS - ACCEPTED

Introduction

This document lays out the design principles guiding the design and implementation processes of the Booster Framework. These principles are crucial in steering both high-level and low-level decision-making within the project. They are pivotal in ensuring that the project remains focused on the correct aspects of design and implementation, always keeping in mind the target audience and user persona, as they are the most important stakeholders of the project.

Principle of Least Astonishment

The Principle of Least Astonishment, also known as the Principle of Least Surprise, is a fundamental guideline in user interface and software design. It stresses the importance of creating systems that behave in ways consistent with user expectations, minimizing surprise and confusion. This principle is crucial in the Booster Framework, ensuring that the framework's components and functionalities align with the conventions familiar to both enterprise and hobbyist developers, thereby enhancing their experience and usability. It is particularly relevant in a context where developers are transitioning from traditional enterprise technologies to modern TypeScript-based environments, as it aids in reducing the learning curve and preventing user astonishment.

Examples

  • Favoring JSON or YAML for configuration over more complex formats, aligning with common industry practices.
  • Integrating with popular version control systems like Git and widely-used platforms such as GitHub or GitLab.
  • Recommending mainstream IDEs like Visual Studio Code, which are familiar to a broad range of developers.
  • Ensuring that the framework's functionalities and syntax are intuitive and align with common programming practices.

Principle of Developer Happiness

The Principle of Developer Happiness is centered around creating an environment and culture that aligns with developers' professional and personal expectations, thereby enhancing satisfaction and retention. This principle is key in the Booster Framework, focusing on an engaging experience and a supportive culture where developers, regardless of their background, feel valued and connected to the project's mission. It also involves using efficient tools and technologies to streamline the development process and saving time, along with continuously assessing developer efficiency and satisfaction.

Examples

  • Comprehensive Documentation: Providing clear and user-friendly documentation with practical examples for both enterprise and hobbyist developers.
  • Active Community Engagement: Encouraging participation and collaboration within the open-source community.
  • Transparent Decision-Making: Keeping language development and framework enhancement decisions transparent.
  • Inclusive Onboarding: Offering learning resources and support for developers of varying skill levels.
  • Acknowledgement of Contributions: Recognizing and valuing contributions from the community, regardless of their scale.
  • Open Feedback Channels: Maintaining open channels for feedback, suggestions, and issue reporting from users and contributors.

Principle of Least Effort

The Principle of Least Effort emphasizes the idea that entities will naturally gravitate towards the solution that requires the least amount of work or complexity. In the context of the Booster Framework, this principle is applied to create systems and interfaces that are straightforward, easy to comprehend, and simple to interact with. This reduces the cognitive and operational load on users, particularly those transitioning from different technology backgrounds. For developers, it encourages the creation of code and architectures that are clean, efficient, and easy to understand and modify. By adhering to this principle, the Booster Framework aims to offer user-friendly applications and sustainably maintainable codebases, promoting efficient interactions for all users.

Examples

  • Intuitive Syntax and Features: Designing the framework with a simple, intuitive syntax that reduces cognitive load, particularly for those new to TypeScript.
  • Streamlined Documentation: Providing clear, concise documentation that helps users quickly understand and utilize the framework.
  • Robust Standard Libraries: Including comprehensive standard libraries that simplify common development tasks.
  • Effective Error Handling: Implementing user-friendly error messages and handling mechanisms for efficient problem-solving.
  • Strong Community Support: Building a supportive community for knowledge sharing and collaboration, reducing the effort needed to overcome challenges.
  • Simplified Version Management: Facilitating easy version management and updates for seamless adoption of new features and improvements.

Conclusion

The design principles outlined for the Booster Framework serve as a guiding light for the project's development and implementation processes. The Principle of Least Astonishment ensures system behavior aligns with user expectations, enhancing usability. The Principle of Developer Happiness focuses on creating a fulfilling environment for developers, while the Principle of Least Effort promotes simplicity and efficiency. These principles collectively ensure that the Booster Framework remains attuned to the needs of its diverse user base, from enterprise developers to hobbyist programmers, ensuring a user-centric, efficient, and developer-friendly journey throughout its development.

· 3 min read
Nick Tchayka
STATUS - ACCEPTED

Introduction

In the context of the Booster Framework ecosystem, we adopt the Semantic Versioning (SemVer) schema. SemVer is a system of rules and guidelines for assigning and incrementing version numbers within our software development process. By using SemVer, the Booster Framework aims to manage the complexities of dependencies as the ecosystem evolves. The primary goal of implementing Semantic Versioning is to ensure that our version numbers are transparent and informative, effectively communicating the nature of changes in our software to both enterprise and hobbyist developers.

Impact on Principle of Least Astonishment

Semantic Versioning positively impacts the Principle of Least Astonishment. It is a widely recognized and used schema in numerous open-source projects. Adhering to a clear and consistent version numbering system (Major.Minor.Patch) reduces confusion and surprise for developers and users alike. This predictability in versioning enhances the user experience and facilitates the management of software dependencies.

Impact on Principle of Developer Happiness

Semantic Versioning aligns with the Principle of Developer Happiness by offering a systematic and standardized approach to versioning. This method simplifies the process of releasing and updating software packages, allowing developers to confidently implement changes. Knowing that version numbers accurately reflect the impact of changes reduces the stress related to dependency management and enables developers to concentrate on innovation and software improvement.

Impact on Principle of Least Effort

Semantic Versioning supports the Principle of Least Effort by making the management of software dependencies more straightforward. By adhering to SemVer, developers can introduce backward-compatible changes without needing new major releases, thereby minimizing the effort needed for maintaining and updating software. Additionally, the clear documentation of public APIs and the use of version numbers to indicate compatibility simplify the integration of dependencies, reducing the effort needed for seamless software interactions.

Usage of SemVer in Early Development Phases

During the initial development phases of Booster Framework projects, the major version will remain at 0. This indicates that breaking changes are likely to be frequent as the project evolves. Once the project achieves a stable state, the major version will be incremented to 1, signifying a reduction in the frequency of breaking changes.

Standardizing the Use of SemVer

We advise using the Semantic Versioning schema as a standard across all Booster Framework projects. This uniformity will ensure coherence within the ecosystem. The Booster CLI tool should facilitate version management by inspecting exported functions and types, suggesting the next version based on the changes made.

Considerations

It's important to note that changes in the implementation of a function, even without altering the API, can produce different results and are considered breaking changes. These should be reflected in the version number accordingly. For more information and examples, please refer to this GitHub thread.

· 4 min read
Nick Tchayka
STATUS - DRAFT

Introduction

This document proposes a significant reorganization of the Booster Framework's folder structure to address current challenges in codebase management and to align with the principles of modularity and scalability. The current structure, src/{commands,events,entities,read-models}/*.ts, while functional, has shown limitations in managing complexity as the framework and the team grow.

This proposal introduces a new structure based on the concept of "Agents" in event sourcing/event-driven systems, aiming to bring conceptual clarity and improved organization to the codebase. It can be thought as the microservices approach, but more tailored to the event-driven nature of Booster Framework.

Current Challenges

The existing folder structure in the Booster Framework presents several challenges:

  • Lack of Modularity: The mixed nature of components (commands, events, entities, read-models) in a flat structure leads to difficulties in isolating specific functionalities or use cases.
  • Scalability Concerns: As the team and the codebase grow, the lack of hierarchical organization makes it increasingly challenging to manage and navigate the codebase.
  • Interdependency Issues: The current structure does not clearly delineate dependencies and relationships between different components, leading to potential conflicts and complexities.

Proposed Folder Structure

The new folder structure is organized around the concept of "Agents", where each use case is encapsulated within its own subfolder. This approach mirrors the modular and event-driven nature of the Booster Framework.

Structure Overview

  • src/
    • agents/
      • agent-name-1/
        • commands/
        • events/
        • entities/
        • read-models/
      • agent-name-2/
        • commands/
        • events/
        • entities/
        • read-models/
      • ...
    • shared/
      • common-entities/
      • utilities/
      • ...

Guidelines for Naming Subfolders

  • Reflective of Use Case: Each subfolder (agent) should be named in a way that clearly reflects its specific use case or domain.
  • Consistent Naming Convention: A uniform naming convention should be adopted across all agents to maintain consistency and readability.

Benefits of the Reorganization

  • Improved Modularity: Each agent acts as a self-contained module, enhancing the clarity and separation of different aspects of the codebase.
  • Enhanced Scalability: This structure supports the growth of the team and the codebase, allowing for easier navigation and management.
  • Facilitated Collaboration: Teams can focus on specific agents without interfering with others, simplifying collaboration and reducing the risk of conflicts.
  • Repository Splitting: The modular nature of this structure allows for splitting the codebase into separate repositories if necessary for better scalability and management.

Addressing Potential Challenges

Interaction and Communication Between Agents

  • Well-Defined Interfaces: Clear interfaces and communication protocols between agents must be established to ensure smooth interactions.
  • Shared Resources Management: The shared/ folder will house common entities and utilities, accessible to all agents while maintaining their independence.

Technical and Implementation Considerations

  • Incremental Transition: A phased approach to migrating to the new structure is recommended to minimize disruption.
    • The team can start by putting everything in the shared/ folder, then gradually move to the new structure.
  • Documentation and Communication: The team should be in charge of having documentation and communication sessions in order to ensure that everyone is on the same page and responsibilities are not duplicated.

Additional Ideas

Integration of AI Agents

In line with the event-driven architecture of the Booster Framework, an intriguing extension to the proposed semantic codebase structure is the incorporation of AI agents. These agents, mirroring the structure of traditionally-programmed agents with commands, events, read-models, etc., would have their internal logic powered by Large Language Models (LLMs).

This integration aligns with the scalable and modular design of the framework, allowing AI agents to autonomously handle specific tasks or workflows within their domain. The use of AI agents could significantly enhance the framework's capabilities in areas such as:

  • Automated decision-making
  • Predictive analytics
  • Personalized user interactions

Each AI agent would operate within its designated subfolder, ensuring a clear delineation and manageable interaction with regular agents, while adhering to the same communication protocols and interface standards established in the overall framework.

This innovative approach opens new avenues for efficiency, creativity, and advanced functionalities within the Booster Framework ecosystem.

Conclusion

The proposed semantic codebase structure for Booster Framework aims to address current challenges in codebase management while aligning with the principles of modularity and scalability. This reorganization, centered around the concept of "Agents", offers numerous benefits, including improved code separation, easier collaboration, and the potential for scalable codebase management.

· 3 min read
Nick Tchayka
STATUS - DRAFT

Introduction

This document proposes a novel solution to address the challenges encountered by the team following the restructuring of Booster Framework codebase into distinct agents and separate repositories. The primary challenge involves enabling easy importation of types and classes from other agents without relying on traditional package managers. The proposed solution introduces a new endpoint, /inspect, in Booster services, coupled with an extension to the TypeScript compiler through a specialized plugin (transformer). This approach aims to streamline development, ensure access to up-to-date type definitions, and facilitate seamless agent interaction.

Context and Challenges

After splitting the project codebase into individual agents and repositories, the team faces the challenge of efficiently importing types and classes across these divided entities. Traditional methods, such as package managers, are not optimal in this scenario due to their complexity and the additional maintenance they require. There is a need for a more agile and integrated solution that aligns with the dynamic nature of Booster Framework.

Proposed Solution

Introduction of /inspect Endpoint

  • Functionality: The /inspect endpoint in Booster services will provide direct access to .d.ts files of all project components, organized by agents. This will include types for commands, events, read-models, and other relevant components.
  • Benefits: This endpoint simplifies development by offering an organized and up-to-date source of type definitions, ensuring consistency across different agents.

Extension of TypeScript Compiler

  • Plugin Development: A custom plugin for the TypeScript compiler will be developed to recognize a special import syntax, such as import FooEvent from 'booster://agent-name/events/FooEvent'.
  • Dynamic Importing: This plugin will dynamically fetch the corresponding .d.ts file from the /inspect endpoint, streamlining the import process.
  • Advantages: This system allows seamless interaction between agents, enhancing the developer experience and negating the need for traditional package management complexities.

Addressing Potential Concerns

Security and Access Control for /inspect

  • Implementation of Security Measures: Appropriate security measures and access controls will be implemented to protect sensitive information within the .d.ts files accessible via the /inspect endpoint.
  • Restricted Access: Access to the endpoint may be restricted based on user roles or project settings, ensuring that only authorized personnel can retrieve type definitions.

As the first version of this feature, these security concerns will be mitigated through making this feature opt-in. It would be only available for environments where the flag has been enabled. For example, it should be enabled in the local development, testing, and staging environments, but disabled in production.

Integration with Existing Workflow

  • Seamless Integration: The proposed solution is designed to integrate smoothly with the existing development workflow of the Booster Framework.
  • Addressing Challenges and Dependencies: Potential challenges, such as network latency or downtime, will be addressed through robust error handling and fallback mechanisms.

Naming Convention and Format

  • Import Syntax Convention: The booster://agent-name import syntax will follow a clear and consistent naming convention, aligning with the overall structure and nomenclature of the Booster Framework.
  • Agent Naming Guidelines: Specific guidelines and constraints for naming agents will be established to ensure clarity and avoid conflicts in the import process.

Conclusion

The introduction of the /inspect endpoint and the extension of the TypeScript compiler with a custom plugin represent a significant step forward in addressing the challenges of remote imports in Booster Framework. This solution not only simplifies the development process but also enhances the modularity and flexibility of the framework, ensuring a smooth and efficient experience for developers working across different agents and repositories.

· 7 min read
Nick Tchayka
STATUS - DRAFT

Introduction

This document proposes an enhancement to Booster Framework, introducing a new component integration mechanism. This enhancement aims not to overhaul the existing architecture but to provide an incremental upgrade, allowing the Framework to retain its current functionality while adding new, more efficient capabilities. This proposal details the transition to a system where components, written with clear interfaces using Effect, can be directly injected into the Booster project, offering improved efficiency and customization.

warning

This component system is not meant to be used by all Booster users, but rather by it's power users who want to extend their apps in ways that are not possible with the current system, as well as Booster contributors who want to add new features to the framework.

Current Mechanism and Its Limitations

The Booster Framework currently relies on users specifying packages to be loaded (like Azure provider or filesystem components) in a JSON configuration, which are then dynamically imported by the framework. While functional, this approach has limitations in efficiency and customization.

Enhancement Overview

Interface Definition and Inversion of Control

  • Interface Definition: We propose to define explicit interfaces for CLI commands, runtime operations, and post-compile activities.
  • Inversion of Control: Shift from dynamic imports to a system where users inject components directly into their Booster projects.
  • Effect Integration: Utilize Effect for writing components, ensuring robustness and type safety.
    • This part is crucial, because it enhances the component system with:
      • Dependency injection: Components can be automatically injected into other components, allowing for a more modular design.
      • Implicit structured logging and monitoring: Components can log and monitor their own operations, and the framework can log and monitor the operations of the components.
      • Better concurrency management: Components can be run concurrently, and the framework can manage the concurrency of the components.

Maintaining Existing Functionality

  • Gradual Transition: The new system is designed to coexist with the current architecture, allowing users to transition at their own pace.
  • Backward Compatibility: Ensures existing Booster applications continue to function without mandatory modifications.

Benefits

  • Efficiency: Reduces the overhead associated with dynamic imports.
  • Customization: Offers users greater control over their applications.
  • Type Safety: Enhances the robustness of applications through type-safe component development.

Design and Implementation

warning

This is a draft of the design and implementation of the new component system. It is not final and is subject to change. It hasn't been tested against a compiler, tried in any way, let alone implemented. It is an "off the top of my head" design.

The key idea of the component system is to allow defining transient run-times, which allow specifying the behavior of a component during a specific run-time. We're writing run-time and not runtime, because a component can run during different moments that is not the runtime of an application.

You can think on this as the npm scripts that define the behavior of a package during different moments of the life of a package, like preinstall, postinstall, prepublish, etc. but for components.

The initial defined run-times are:

  • CLI: The component is executed during the execution of a CLI command.
  • Runtime: The component is executed during the execution of the application.
  • Verification: The component is executed after the compilation of the application. It is called verification, because at this point it allows us to perform additional validation and verification of the application.

Of course, this list is not set in stone, and we can add more run-times in the future.

Because the component system is composable, it allows us to define components that are composed of other components. Here is when the run-times become crucial. If a component uses another one, when a run-time of the parent component is triggered, the same run-time of the child component gets triggered too. This is a bit of a tongue-twister, so let's take a look at a more concrete example.

Example: Event File Generation Component

Imagine we're defining a component called EventGenerator that allows us to generate files for events. Yes, this is an already existing feature of the framework, but it will serve us an example.

Let's assume that there's an already existing component called FileGenerator that allows writing an arbitrary string to a file that will be placed inside of the project src folder. This component would be defined like this (pseudocode):

// This interface allows the users to provide different implementations for the components
interface FileGenerator {
generate(
folder: string,
filename: string,
content: string
): Effect<...>
}

// Concrete implementation for FileGenerator, could do whatever
// as long as it fulfills the contract of `FileGenerator`.
// Could be a mock one, a remote one, etc...
const FileGenerator = defineComponent<FileGenerator>({
// The actual method
generate(folder, fileName, content) {
// Here we specify that the block inside should only be executed during CLI-time
during(RunTimes.CLI, () => {
// ... actual code to generate the file
})
}
})

Now, if we were to define the EventGenerator component, if we used FileGenerator. We wouldn't need to specify the CLI time, because that's already done at the FileGenerator component:

interface EventGenerator {
generate(
name: string,
fields: Array<[string, string]>
): Effect<...>
}

const EventGenerator = defineComponent<EventGenerator>({
// Effect.gen allows us to define custom async/await syntax that is extensible
// instead of an async function we use a JS generator function,
// and instead of await, we use the `_` helper and the `yield*` JS keyword.
generate: (name, fields) => Effect.gen(function*(_){
const content = ...// generate the content of the file

// We ask the dependency injection mechanism for the FileGenerator component
const fileGen = yield* _(FileGenerator)

// We run the generate method in the file generator component
yield* _(fileGen.generate("events", `${name}.ts`, content))
})
})
info

The generator function might impress at first, but it is regular JS syntax, and it is a 1:1 mapping to async/await. Even though it introduces a bit of friction, we believe that the advantages outweight the friction by far. You can check the async/await comparison example on the Effect site.

In the example above, we just used the FileGenerator component, and because that one already defined the CLI-time behavior, we didn't need to do it ourselves.

This is an extremely powerful idea, because with a little subset of primitive components, we allow extending and customizing Booster apps in inimaginable ways. Power users could define their own database component that allows them to configure, deploy and use a database in their app with a single function call.

How to execute the different run-times?

These components would get injected into the Booster.config block for now, as it gets loaded when the application starts.

If a Booster application is configured with some components, it's main executable will get extended with an additional CLI flag --exec that allows specifying the run-time to execute.

To maintain backwards compatibility, if --exec is not specified, it will run the run-time by default, as it is what happens when one runs a Booster app nowadays.

This way of working allows taking responsibility out of the Booster CLI tool and allow users to create a regular boost (or any more descriptive name) script in their package.json file, allowing to execute the CLI components right with pnpm (or their preferred Node package manager):

$ pnpm boost event:generate --name AccountCreated --fields 'amount:number'

Considerations

  • Compatibility Measures: Ensure the new component system aligns with the existing Booster Framework.
  • Learning Curve: Address the potential learning curve associated with Effect through detailed documentation and community support.
  • Error Handling: Leverage TypeScript's compiler for improved error handling and runtime safety.

Conclusion

This proposal lays the groundwork for a progressive enhancement in Booster Framework's component integration mechanism. This proposal balances the need for advanced functionality and efficiency with the necessity of maintaining existing systems, while giving power users a great extensibility tool, and most importantly, increasing the robustness of the framework overall.