DEV Community

Cover image for How I Structure my Humming-Bird Projects
Rawley Fowler
Rawley Fowler

Posted on

How I Structure my Humming-Bird Projects

Humming-Bird is a very unopinionated web framework. It allows the developer to structure their projects however they like. As the creator of Humming-Bird I can openly say that this was on purpose, and takes after a few other popular frameworks.

Though this was on purpose, it can seem daunting, especially to people new to the Raku ecosystem, or new to designing web-applications in general. I hope to underline the few structures I have employed to making sure my application makes sense from a developers point of view, but also from a Raku point of view.

The Single File Service

If you find that your service will be small, you may want to consider building your system in a single-file. This is done very simply with a structure like:

App-MyService/
    ├── bin/
    │   └── my-service
    ├── lib/
    │   └── App/
    │       └── MyService.rakumod
    ├── META6.json
    └── Dockerfile
Enter fullscreen mode Exit fullscreen mode

In your META6.json you'll have:

...
    "provides": {
        "App::MyService": "lib/App/MyService.rakumod"
    }
...
Enter fullscreen mode Exit fullscreen mode

Then in your bin file you'll want to import your service, and Humming-Bird, something like:

use Humming-Bird::Core;
use App::MyService;

listen(1234);
Enter fullscreen mode Exit fullscreen mode

It is important that you import App::MyService after Humming-Bird::Core to avoid having some weird side-effects with route declarations in your service.

Model-View-Controller

Some web-apps would prefer to be elevated above the status of service, and would prefer to have a dynamic UI. This is typically done with the Model-View-Controller or MVC architecture. In a typical MVC application you separate concerns between the model, the view, and the controller by keeping them in separate name-spaces or folders.

With Humming-Bird, nothing really changes except that your views probably don't have to be individual Raku modules. I like to structure such applications like:

my-service/
    ├── templates/
    │   ├── foo.mustache
    │   └── bar.mustache
    ├── bin/
    │   └── my-service
    ├── lib/
    │   └── App/
    │       ├── MyService/
    │       │   ├── Controller/
    │       │   │   ├── Foo.rakumod
    │       │   │   └── Bar.rakumod
    │       │   └── Model/
    │       │       ├── User.rakumod
    │       │       ├── Friend.rakumod
    │       │       └── Post.rakumod
    │       └── MyService.rakumod
    ├── META6.json
    └── Dockerfile
Enter fullscreen mode Exit fullscreen mode

You'll still want the same use statements in your bin file, but this time you'll have to do a provide in your META6 file for each of the nested modules.

...
"provides": {
    "App::MyService": "lib/App/MyService.rakumod",
    "App::MyService::Controller::Foo": "lib/App/MyService/Controller/Foo.rakumod"
    ...
},
...
Enter fullscreen mode Exit fullscreen mode

Now you can layer your code nicely, having the controllers call to the models to get data, and then rendering pages based on your templates. In this example I used Template::Mustache by softmoth, but you can also user other templating languages like Template6 by the Raku Community, or RyML by the dashing tony-o.

Note: this is following an "Active-Record" approach to database management, where the sub-class of a type handles Repository type actions. You can use either. If you are looking for an "Active-Record" style database manager ORM thing, you can use Red.

Microservice

With a microservice I'm typically more focused around data and its flow, because of this, I adapt my single-file structure to also have a Repository section, allowing me to nicely package my database interactions. I also like to have a Queue or Communication module that handles talking with other service if I need to. This typically includes talking to queues, or establishing other UDP or TCP connections.

With Microservices I prefer the more fine-grained Repository approach where I can hone in on writing fast SQL vs the "Active-Record" approach that something like Red gives you. Because of this, I typically use DBIish for microservices.

My simple microservice structure typically looks like:

my-service/
    ├── bin/
    │   └── my-service
    ├── lib/
    │   └── App/
    │       ├── MyService/
    │       │   ├── Communication/
    │       │   │   ├── Queue.rakumod
    │       │   │   └── Upstream.rakumod
    │       │   ├── Repostiory/
    │       │   │   ├── Foo.rakumod
    │       │   │   └── Bar.rakumod
    │       │   └── Controller/
    │       │       ├── Foo.rakumod
    │       │       └── Bar.rakumod
    │       └── MyService.rakumod
    ├── META6.json
    └── Dockerfile
Enter fullscreen mode Exit fullscreen mode

This blog post was fairly erratic, but I hope it demystified a little bit about project structure using Humming-Bird. I'm currently writing a small MVC example for Humming-Bird, make sure to check the examples directory to see some existing apps, and check back soon to see the full-fledged MVC example.

Thanks for reading, Raku rocks!

Top comments (4)

Collapse
 
swaggboi profile image
swagg boi

Hello, thanks for Humming-Bird and these blogs explaining how it works. Would you mind writing up something on creating simple tests for a Humming-Bird app or are there already examples out there?

Collapse
 
rawleyfowler profile image
Rawley Fowler • Edited

Hey thanks! Sorry I haven't been on dev.to for a while. In the future if you need to contact me, please send me an email!

One of the next features I would like to write is a integrated testing tool for Humming-Bird, but for the mean time if you look in the t/ folder of the project you'll see how easy testing applications is. Typically you'll pull the routes from the app and pass requests by hand.

Collapse
 
swaggboi profile image
swagg boi

No worries, I did try to lurk you on Fedi/Mastodon but it looks like we haven't converted you to our commune yet! I'll shoot you an email next time. 📬

I'm excited about the testing tool. I'll take a look at your current tests in the meantime as I need to learn the 'Raku way' of doing things in general so it'll be a useful exercise for me.

Thread Thread
 
rawleyfowler profile image
Rawley Fowler

Actually I'm on here to make a new post, so make sure to check that out too :D