loading...
Cover image for Explaining the hype around Booster Framework πŸ”₯😈
Booster

Explaining the hype around Booster Framework πŸ”₯😈

nickseagull profile image Nikita Tchayka ・8 min read

Let's all agree on one thing: Writing backends is hard, and we suck at it.

Yeah, sure, we're all great at creating our Express server, with our MongoDB or MySQL attached to it, but what comes after?

Are you sure that your dedicated server is ready for when your app starts being successful? Yeah, you could optimize your server, harden your Linux, remove unnecessary packages, stop services, etc. Still at some point, you'll need to scale up your server, buy a more expensive one. But what if that is needed for only that moment when a high influx of users come into your site? Do you downscale to keep your budgets down? Do you keep paying for the server? Have you even thought about adding a load balancer?

The solution is obvious: Serverless and the cloud!!!!1!one!

Sadly, this is not the reality. Why not? Because it's just more stuff to learn, and it's not like learning a new library/tool, it's a ton of info. Have you considered your cloud already? AWS, Azure, Google Cloud Platform?

Let's suppose you chose AWS, here are some more questions: Will you use DynamoDB? Or Aurora? Do you know how to query those databases? Are there any ORMs available for your language+database combination? Are you deploying all of this infrastructure manually? Or are you using something like Terraform or Serverless? By the way, how comfortable are you with YAML? πŸ˜‚

Not only that, now your code gets executed in separate functions. Don't try packaging your entire Express server into that. Well, at least if you value your wallet πŸ˜…

Did you think already about the architecture for your app? Will you communicate the different parts of your app through a queue? Will you do direct calls? Are you gonna store stuff in the database directly? Or is it gonna act more as a cache? πŸ€”

Also, remember that you have to create a proper SDK on the frontend to interact with your backend.

OH! I nearly forgot! Are you gonna add analytics to your app? Because it'd be good if you thought about that in this moment, where you can start gathering data right from day one.

And as a final note: Good luck maintaining it. πŸ‘Œ

man throwing himself out of the window

You might be one of those people who see the text above and think "And what's the issue with all of this? It's part of the journey, I'm okay spending 95% of my time learning all this stuff and maintaining it, I'm a developer".

Sorry, but in that case, you're missing a lot of good stuff.

I think that we all agree that tinkering with pointers and registers is not something from nowadays' daily development scene. Sure, there is this small percentage of people that do this in order to optimize the speed of their system, but it's not the vast majority of us. Why? Because of speed of development.

The usage of those things have been abstracted for us, so we write less code that doesn't matter, and write more of the code that matters: The one that makes our app different

Same stuff with fonts, you don't design a font each time for your application, but rather, you just choose the one that fits best for the use-case.

What if I told you that there's a way to abstract all of this hard stuff regarding to backend development, and just focus on what matters in that code that makes your app different?

Enter Booster framework

Booster is this TypeScript framework distilled from years of experience working with companies like eBay, PayPal, Rent the Runway, or Zara. The folks at The Agile Monkeys got tired of reinventing the wheel constantly, and created the ultimate backend framework.

The premise is simple: Make developers' lives easier.

So, what makes Booster special?

It:

  • Requires no prior knowledge of backend development.
  • Frees you from thinking about servers.
  • Eliminates the need to configure your database.
  • Avoids having to configure endpoints.
  • Deploys to your favorite cloud, without having to read their docs thoroughly.
  • Removes any costs for your deployed app while you’re not using it.
  • Has built-in analytics data gathering for your app.
  • Is extensible with plugins in case you really want to tweak something (we call these rockets).

Also, you don't have to be thinking in architectures, Booster has thought that already, extracted from the enterprise projects above and many others.

Ok, how does one use it?

I'm not gonna get too deep into actual usage, because this is not a tutorial, but I'll show you enough to see what's going on when you work with Booster.

When you use Booster, you interact a lot with the boost CLI tool that comes with it. Booster has a tiny bit of boilerplate code, but you don't want to write even that one.

I DONT ALWAYS WRITE BOILERPLATE CODE, BUT WHEN I DO I USE BOOST CLI

How does one configure their app? That's the magic, you don't! The only thing you have to do is write your app around the following concepts:

Commands

A command is a class with some fields that represents an order to your system, along with a handle method that will validate those fields, registering some events (we will talk about them in the next section). Examples of commands are generally the continuation of the sentence "A user can...", e.g.:

  • A user can deposit money
  • A user can send a message
  • A user can create a chat room

How does a command look in practice? Just TypeScript code, and the best part, is that most of it is autogenerated! With a command like boost new:command DepositMoney --fields accountId:UUID amount:number you'll get a file under src/commands
with the following contents:

@Command({
  authorize: ...
})
export class DepositMoney {
  constructor(
    readonly accountId: UUID,
    readonly amount: number
  ) {}

  public async handle(register: Register): Promise<void> {
    register.events(...)
  }
}
Enter fullscreen mode Exit fullscreen mode

You would now specify who can execute this command in the second line, write your validation code inside of the handle method, and register the events. THAT'S IT! No HTTP methods, no routing endpoints, deep controllers, or whatsoever, just the important code.

Events

Same as commands, events' code is autogenerated with a command in your terminal, they are a regular TypeScript class as well.

Remember when I said that your app integrates already the data gathering for analytics? It's because of events! Instead of changing your database, performing queries, etc. You just represent that change as an event. Booster will store all these events infinitely, meaning that at any time, you can check what steps did a user do in order to trigger that bug, see if those users are dropping your registration process due to UX or a bug, think in how to optimize new features, and much more!

Examples of events are facts that you can state after a command, many of them are pretty obvious:

  • Deposit performed
  • Message sent
  • Room created

(Note the ed)

A newly created Booster event looks like this:

@Event
export class DepositPerformed {
  public constructor(
    readonly accountId: UUID,
    readonly amount: number
  ) {}

  public entityID(): UUID {
    return this.accountId
  }
}
Enter fullscreen mode Exit fullscreen mode

Entities

Entities are the internal state of your application, but you don't modify it. Instead, Booster does something like an Array.reduce to this infinite list of events that you have, to convert them into a tangible object. Entities have many uses, but the most important one is snapshotting, so your backend is FAST.

Examples of entities are concepts in your app, stuff like:

  • Bank account
  • Conversation
  • ChatRoom

Here's an entity that calculates its balance from the DepositPerformed event, initializing balance to 0 in the case that the account doesn't exist yet:

@Entity
export class BankAccount {
  public constructor(
    readonly id: UUID,
    readonly balance: number
  ) {}

  @Reduces(DepositPerformed)
  public static reduceDepositPerformed(event: DepositPerformed, current?: BankAccount): BankAccount {
    const currentBalance = current?.balance ?? 0             //    ^--  Note how this is optional, because at the beginning of your app, the account doesnt exist
    return new BankAccount(
      currentBankAccount.id,
      currentBalance + event.amount
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

Read Models

Read models are the way you expose your entities to the public. Read models act as a cache to make sure that your app gets the data ASAP. Also, they allow you to combine different entities, and transform the data in a way that it makes sense for your frontend. Again, a regular TypeScript class:

@ReadModel({
  authorize: ...,
})
export class AccountReadModel {
  public constructor(
    public id: UUID,
    readonly balanceMessage: string,
  ) {}

  @Projects(BankAccount, 'id')
  public static projectBankAccount(entity: BankAccount, current?: AccountReadModel): AccountReadModel {
        let message = "Broke"
    if (entity.balance > 1000) {
      message = "Has sum money here, yo"
    } else if (entity.balance > 10000) {
      message = "Hey, this person is saving for sumthin'"
    } else if (entity.balance > 100000) {
      message = "Whoah, they gonna buy a house or what?"
    } else if (entity.balance > 1000000) {
      message = "They got a shit ton of money, yo!"
    }
    return new AccountReadModel(entity.id, message)
  }
}
Enter fullscreen mode Exit fullscreen mode

That's it!

Now, to deploy this, you just write boost deploy -e production.

AND THAT'S IT. PERIOD.

old woman performing a dab

No configuration, no control panels, no YAML, no anything! Just press one damn button, and you have your app deployed to the cloud

You get your cloud properly configured, with all security measures, architecture, interconnection of services, etc.

Booster spits out a URL which is a GraphQL endpoint for you, and that's it.

Right, but how do I connect this to my frontend?

Because it is GraphQL, you can perfectly use a library like Apollo in order to connect it.

Using React? Vue? Svelte? Elm? No problem, just use the Apollo adapter for one of those. No need to write SDKs/services for talking to the backend.

Commands can be executed through Mutations, Read Models can be queried or subscribed to. That's it, no need to encode URLs, remember parameter orders, create API documentation with Swagger, etc. Just use what you coded.

This is too good to be true, it must cost a lot, right?

Nope, the framework is absolutely free to use and open source. If you are worried about the costs of the cloud, all Booster projects
are eligible for the AWS free tier, and even without it, for 40.000 (that's forty thousand, btw) requests in one month, you'd pay less than one dollar.

(No, the team doesn't get any cut from cloud providers, we are just fed up with tools that create problems instead of solving them πŸ˜‰)

Ok, what to do now?

If you reached so far, congratulations, and thank you! Nowadays frameworks appear every day, and people just roll their eyes. Booster is truly different and groundbreaking. For learning more, checkout the project's website, where you can find links to documentation, demos, and much more.

I also recommend you to join the project's Discord server and challenge it with your ideas, thoughts, and questions. A project is nothing if it stays in the same place, and by challenging it, you are already helping!

Booster is also part of Hacktoberfest, in case you want to contribute wink wink; nudge nudge. And even if not, a star in our GitHub repo would mean a lot.

Stay tuned for more!

May your day be awesome, and your backends easy πŸ˜‰,
Nick

jake peralta saying peace out homies

Discussion

pic
Editor guide
Collapse
xyn profile image
Mydrax

You will still have the maintenance struggles and the complexities you described because from what I understand by reading your article, its just another backend framework.

Loopback, Nest, Adonis etc more or less do this and at best they get rid of the need to write and maintain the high level abstractions that are common to most backends.

If at any point you have some kind of case-specific requirement you'll have to do it yourself don't you? So its kinda misleading to say you dont have to write configuration files or at the very least backend code, don't you think?

Collapse
nickseagull profile image
Nikita Tchayka Author

Not really, you don't have to maintain a server, because the code is being executed in lambda functions (or the equivalent of your cloud provider), database management is not needed, as Booster relies on on-demand databases that autoscale. You just write your domain logic following the patterns described :)

In the frameworks you say, you still have to write routing, middlewares, adding models, rely on repositories, etc... On top of that, you still have to figure out with them how to endue scenarios, with, say 3000 requests per second, without a failure, while Booster does this out of the box.

As you say, those are still backend frameworks because they maintain somewhat high level abstractions, but Booster takes this a step further, and abstracts infrastructure and the orchestration/architecting of it for high throughput scenarios.

Case-specific requirements, like say, for example, static hosting, are handled by Booster rockets, which essentially are plugins to extend your app written in Booster. So for example, you need to host a static site, you install the rocket, and the deployment will reconfigure itself adding that static site hosting you need.

Yeah, it could be that you might need something very specific, and would need to write your own rocket, but you truly don't need to write configuration files or backend code in the 90% of the cases.

It is as misleading as saying that for webdev no one uses pointers/registers, yet there are some case-specific requirements that make people optimize their apps to that point :)

I'd really recommend you to try it, because it's very different :D

Collapse
davidcdthor profile image
David Thor

In the frameworks you say, you still have to write routing, middlewares, adding models, rely on repositories, etc...

It looks like you did all the same with the booster framework too - you just didn't use the same words. Annotations like @Command is similar to @Get() and @Post() in NestJS, the authorization keyword used in several command examples is pretty much identical to middlewares, models and entities are the same thing, and repositories are optional abstractions in many ORMs.

What this really looks like is a much more opinionated framework rather than a different one. I can only use GraphQL, only use your choice of DB (not even sure what they use by default), only use your authorization API (also not sure what powers it), and of course can only deploy to serverless platforms. Don't get me wrong, opinionated frameworks can be extremely beneficial and can help developers build things they otherwise wouldn't be able to, but if you add too many opinions it can come at a long term cost.

you still have to figure out with them how to endue scenarios, with, say 3000 requests per second, without a failure, while Booster does this out of the box.

This was a bit of a stretch since this value is from the serverless cloud platforms, not Booster itself. Just because you can deploy to more than one platform doesn't mean this value is achieved because of the framework.


Overall nice design for the framework. Even if I'm not yet sold on it being significantly different than some other frameworks, the choices to focus on commands instead of controllers, enable easy event pub/sub, and abstract data storage via entities hit the vast majority of devs needs for sure. Certainly looks easy to approach!

Thread Thread
javier_toledo profile image
Javier Toledo

Hey @davidcdthor , thanks for your great comment, positive criticism about the framework is always welcome! I agree with many of your points and things like replacing our embedded auth API by support for standard JWT issuers, and composability of the cloud implementation via plugins (for instance, to use Aurora instead of DynamoDB or HTTP endpoints instead of GraphQL) are currently in our immediate roadmap. You definitely hit the nail on these concerns.

While it's true that you could easily map concepts like @Command to a @Post request or a @ReadModel with a @Get, we are firm believers that using words that are closer to the business domain, could make a difference in the way teams communicate and ease the overall development process (Nothing new here, just borrowing DDD/CQRS ideas). Most frameworks nowadays are based on MVC + ORMs, which are terms that don't really map with real-world concepts, they're developers'-only representations of the system. Booster inspiration comes from DDD, CQRS and Event-Sourcing.

To illustrate the concept for less familiar with DDD folks: The words we use matter. When someone in a meeting claims "I want to send an email to the customer every time that an order is completed", the experienced developer will immediately figure out how to map that into code no matter the implementation, but when they explain the plan, it's easier for everyone in the team to understand when you say "I'm going to create an event handler that sends the email to the customer every time that it receives an order completed event" than saying "I'll create a hook in the model that triggers a function every time an order is persisted by the ORM and the state of the order is completed that send an email to the customer". Both can be understood and explained, but the first is closer to facilitate understanding.

Making Booster easy to approach has been always a key for us. We want to allow people to learn, use, and deploy it in minutes, removing everything that we can from their way. That's why it's so opinionated, and that is by design, understanding that it won't work for a good chunk of situations (Like choosing Event-Sourcing as one of the main design pillars, which is definitely not for every problem but has some nice implications over traditional state persistence). As you said, the benefits for the cases where this specific arrangement of technologies and design work are huge, saving a ton of time and enabling people to build things that otherwise they wouldn't have time to build.

The preference for serverless also comes from this way of thinking: we want developers to start very quickly, but this is not actually a restriction. the way the code is run in the framework has been fully abstracted into provider-specific separate npm packages. Currently, the best support is for AWS, because it's the one we use more often, but there is also progress done in the Kubernetes package using Microsoft's DAPR, and nothing stops us from creating a package that uses Terraform to deploy the application to your custom setup, or why not, a package built on top of Architect.io which would benefit of its building blocks and deployment features πŸ˜‰. The nicest benefit about the way it's implemented is that you can switch from one provider to another with no code changes (apart from switching the provider object in src/config/config.ts), so it could be possible to start using serverless and switch to other implementation in the future if the project succeeds the costs go crazy (vendor lock-in is always the elephant in the room regarding serverless). It's not really that you can't decide, but that we hide it from the developer if they don't need to decide.

Booster is still a very young framework. Of course, there are other fantastic frameworks out there that solve other things better. I don't think it's here to replace anything but to become a nice sidekick that boosts team productivity when implementing event-sourced highly-scalable services on the cloud as fast as possible. And you know, it's open-source, so it'll become whatever we want it to be. We have a small but welcoming community eager for ideas!

Thread Thread
davidcdthor profile image
David Thor

Great response! For what it's worth, I think the initial set of "opinions" I saw were solid, and I generally agree with a lot of the design decisions that have been made. I'm excited to see how the extensibility progresses!

Thread Thread
javier_toledo profile image
Collapse
javier_toledo profile image
Javier Toledo

I loooooved the article Nick, I think you managed to put together a very good and inspiring summary of Booster! Onwards and upwards! πŸš€

Collapse
jithinks97 profile image
Jithin KS

This is really awesome. So technologies like these will be what come after the age of serverless computing right?

Collapse
nickseagull profile image
Nikita Tchayka Author

Yes, I truly think of the cloud as the next-gen computer that will run our apps without being that lowlevel :)

Collapse
papaponmx profile image
Jaime Rios

This is so great!

Thanks for sharing this tool with us πŸ€“

Some comments have been hidden by the post's author - find out more