Piotr Jaworski
Ruby on Rails

Hanami – Ruby Web Framework [Review]

   Back to list

If you think that Rails and Sinatra are the two most popular Ruby web frameworks, you’re probably right. Thanks to a big community and numerous gems, Rails is the biggest and most popular Ruby framework for now. Sinatra is also quite popular… but generally for smaller web apps. If you have ever tried to build something with it – it’s quite hard to build something big.

There are also two less popular frameworks – Pardino and Lotus. Well, Lotus is no longer Lotus – now it’s called Hanami. I thought, that since Lotus changed its name, maybe they also added a lot of new features and improvements and maybe we can begin to count it as a Rails rival.

In this article, I want to compare Hanami to Rails and write a little about its features. I also wanted to share my feelings after spending some time building a test application.

What is Hanami?

First of all – what is Hanami? Hanami is a full-stack Ruby web framework built by Luca Guidi, made up of simple, small Ruby libraries. As the Hanami Team writes on their page, Hanami’s goal is to build lightweight apps which consume less memory than other Ruby web frameworks (they probably had in mind Rails).

Let’s look up at Hanami’s core. It’s built of 9 main parts:

  • Hanami::Model – Persistence with entities, repositories and data mapper
  • Hanami::View – Presentation with a separation between views and templates
  • Hanami::Controller – Full featured, fast and testable actions for Rack
  • Hanami::Validations – Validations mixin for Ruby objects
  • Hanami::Router – Rack compatible HTTP router for Ruby
  • Hanami::Helpers – View helpers for Ruby applications
  • Hanami::Mailer – Mail for Ruby applications
  • Hanami::Assets – Assets management for Ruby
  • Hanami::Utils – Ruby core extensions and class utilities

As you can see, these parts look similar to the Rails core:

  • Hanami::Model -> ActiveModel
  • Hanami::View -> ActionView
  • Hanami::Controller -> ActionController
  • Hanami::Validations -> ActiveModel::Validations
  • Hanami::Router -> ActionDispatch::Routing
  • Hanami::Helpers -> ActionController::Helpers
  • Hanami::Mailer -> ActionMailer
  • Hanami::Assets -> The Asset Pipeline
  • Hanami::Utils -> ActiveSupport

Architecture

First of all, there is a physical separation in a file’s structure between what happens on the front-end and the back-end. Controllers, which are responsible for processing requests, manage response logic and provide data to views. They are included in apps/web.

Views are also stored there, but we can divide them into templates and views. Templates are normal .html.erb views, while views are something like helpers. You can write a helper which builds a full HTML form and include it in a template. Moreover, under the web/config folder, you can find a router which includes all routes.

Also, as in Rails, all assets like images, javascript files, and CSS files are located under web/assets folder.

Everything that is connected to the back-end logic, like models and mailers, are stored in the lib/app_name folder. It’s pretty logical.

What’s more interesting is that models are divided into two classes – entities and repositories. Entities are plain, Ruby objects which define all instance methods, while repositories are classes responsible for defining database associations, scopes, query construction and defining a connection with the database.

What’s more, Hanami allows you to create many applications under one application. What does it mean? For instance, you have an application for admins and users, different dashboards and actions – you can create them under one app. Admins’ app will be located under the lib/admins, while users’ app under the lib/users. In Rails, we can achieve it by using namespaces.

Generators

Hanami has built in generators like Rails. A lot of things also look similar, for instance:

Also, we can run a console, server or database console using the hanami command:

But if you want to migrate a database, you don’t need to run Rake, instead use:

Code-reloading

In Rails, we have a great feature which reloads our code in a background without needing to restart a server. Hanami also has the same feature. It uses a gem called Shotgun to auto-reload any code modifications in the background.

Models

What is different and maybe even better in Hanami? First of all, in Rails, a database table is represented as a model. By default, everything is there and should be defined there. As I mentioned before, in Hanami, models are divided into Entities and Repositories. Moreover, they are located in the lib folder, not an app like in Rails.

What is the difference and for what are they used? Well, Entities are pure Ruby object which collects data returned by a repository from a database. You can’t establish a connection to a table while calling a model like MyModel.create. If you want to do so, you need to use a repository.

Repositories are objects which get data from a database and as a result, return a collection of models. For example, if you want to get data from the database, you should run MyModelRepository.new.all. Every time when you want to access the database, you should create a new instance of a repository object.

Moreover, in repositories, we keep all logic connected with a database – queries, scopes and associations, like:

What is funny? The fact that, by default, something like MyModelRepository.new.count doesn’t work – you need to define the count method in order to get COUNT(*), like in the code above. In models, everything stays connected with objects – like instance methods.

Honestly, IMHO this division is a great thing, the two layers of logic connected with models are separated and the code is cleaner. We know where we should put a new logic.

What is bad? In the following beta version, the Hanami Team added new relations like belongs_to, has_one and has_many :through. For me it’s like a base for models, without this it’s really hard to define any relation in a database – and yes, the live version doesn’t have it yet.

Controllers

Controllers look similar to the Rails’ – they are stored in the web/controllers folder. What is different? Well, in Hanami there isn’t a single controller for an each resource, like BooksController. Also, all actions connected to a resource aren’t in one file. Each action of the controller has its own file. This file and class name equal to the an action name. There is only one method called call – which handles all logic.

There are a couple of important things. First, each file should be in a controller namespace, like: Web::Controllers::Home. Second, instance variables are not shared between views, to access it in a view, you’ll need to expose it, using the expose method, like:

Views

As I said before, views are divided into two types – templates and views. Templates are ordinary .html.erb files, where you can keep the complete HTML, while views are like Rails helpers. You can define their Ruby methods which can be accessible in a template. Like controllers, each action has its own template and view.

This is how a template looks:

This is how a view looks:

Well, this structure looks very organized to me. Each action has its own separate file, so everything looks clear and files aren’t too big. That’s the plus for Hanami! But on the other hand, this division isn’t something new, we have it already in Rails divided into views and helpers.

Migrations

Like Rails, Hanami also provides database migrations which help manage any changes in a database table. They look pretty similar to Rail’s migrations but IMHO they are more clear – their syntax.

My thoughts and feelings

I tried to make a sample application in Hanami to check how this framework really looks. You know, in the documentation everything can be beautiful and easy. I gave myself a 6-hour limit to create something that really works.

I wanted to create an application which searches for flights by specified departure and arrival airports and also by a date. A flight can be booked by a passenger. Everything is saved in a database. Well, I’m not saying that it’s easy to achieve in 6 hours but I think that a similar MVP in Rails is creatable in 6. You just create all models and a search method which looks for a specified flight in a database (you have dummy data) and later you can book it. Yeah, it’s not so complicated and we try to keep it as simple as it could be. Of course, we don’t add any custom styles and tests, just plain Bootstrap. And before we start, a database schema is ready, so we know all associations.

So here is my story about how it looked like in Hanami. First of all, I started from creating models. That was really easy – I created all needed migrations, entities and repositories. Migrated everything together and created a service, which seeds my database with dummy data – in Hanami there isn’t something like rake db:seeds in Rails.

When I had everything ready, I started creating the main controller, which is responsible for getting all available airports from the database and creating a search form. That wasn’t so hard but here I learned that instance variables are shared with views. You need to explicitly define which variable is shared with a view. I also learned here, that you can’t think like in Rails, you need to get data from a model’s repository, not directly from a model – what is more, we don’t have them in Hanami. I also added the first method in an entity, which was responsible for formatting data and was shown on the front-end. Wohooo, I used all models mechanisms that Hanami provides!

I also learned here, that you can’t think like in Rails, you need to get data from a model’s repository, not directly from a model – moreover, we don’t have them in Hanami. I also added the first method in an entity, which was responsible for formatting data and was shown on the front-end. Wohooo, I used all models mechanisms that Hanami provides!

After this part, I started defining associations in the repositories and defining the scopes. The first weird thing was the fact, that Hanami doesn’t provide built in count method, you need to define it by yourself. Ok, I thought that it’s not something hard and bad at all, you can define it in 10 seconds. But the next weird thing was the fact, that Hanami doesn’t provide the belongs_to association. I was digging in the source code and other libraries, like Sequel to find out why that doesn’t work. Yeah, Hanami doesn’t have belongs_to or has_one associations (one to many!).

Another thing was the fact, that without it, it’s hard for me to query needed fields – you need to write a pure SQL query to get it. Yeah, you use a library to use pure SQL – pretty normal, right? What’s more, for me their documentation at some level really sucks. There are like one or two examples and that’s everything. You need to guess how to use a function or dig into the source code to check all available options. Imagine how much time you will waste when you need to research every function like this, its behavior etc.

What’s even funnier, is the fact that in a simple SQL query I needed to use a Sequel method, to get what I needed.

When I was somehow done with this part, I moved on to the views. I had some problems defining a route in a form, and yes, I followed the documentation. All the time I was getting the same error, the route is not found. I was googling and digging in the source code without any success. Then I realized that I spent like 2-3 hours to get what I needed. Yeah, at this point I saw that simple things in Hanami took too much time.

Conclusion

For me, Hanami is a great project and idea! Its architecture is planned really well and it’s really clear. But there is a big problem – for now, it is a lack of really good documentation with more complex examples. What’s more, the community isn’t big at the moment, so if you think that you’ll find an answer for your problem on StackOverflow or in Google or in the documentation, you’re probably wrong.

The biggest problem is the fact that the most Ruby gems aren’t created or designed with Hanami use in mind. So if you want to create a fast MVP and you don’t have a big budget or long timeline, you probably shouldn’t create an app with Hanami. As for me, it’s not ready for big production apps yet. You can build simple apps like a blog or something similar.

I hope that you like this article. Remember one big, important thing! I didn’t spend a lot of time developing web-apps with Hanami so I might be wrong, but at the first sight, I would still choose Rails and for me, it’s not well-documented yet.

Looking forward to hearing from you!

  • Pakyow is also interesting (https://www.pakyow.org) as far as a realtime / reactive perspective is concerned.

  • What is funny? The fact that, by default, something like MyModelRepository.new.count doesn’t work – you need to define the count method in order to get COUNT(*), like in the code above

    I actually like this very much, because it forbids you to leak ORM-specific code outside of the repository class, you can only call methods that you defined yourself (with ActiveRecord it’s very easy and common to break the law of demeter). This makes database queries easier to test, because everything is in the repository.

    In the following beta version, the Hanami Team added new relations like belongs_to, has_one and has_many :through. For me it’s like a base for models, without this it’s really hard to define any relation in a database – and yes, the live version doesn’t have it yet.

    Yes, it’s definitely convenient to have those, but is it really that difficult to write it explicitly? Isn’t user.products just Product.where(user_id: user.id)?

    Each action has its own separate file, so everything looks clear and files aren’t too big. That’s the plus for Hanami! But on the other hand, this division isn’t something new, we have it already in Rails divided into views and helpers.

    Hanami’s views are obviously superior to Rails’ view helpers, because the former are encapsulated objects, while the latter are just global macros which have access to everything.

    Well, I’m not saying that it’s easy to achieve in 6 hours but I think that a similar MVP in Rails is creatable in 6.

    I don’t think that’s an entirely fair comparison, because you’re already familiar with Rails. I first started Ruby development with Sinatra, because my brother told me it’s a good start. Through time I realized that most questions and answers are Rails-specific, so I decided to switch to Rails. Man, Rails was so overwhelming after Sinatra, I don’t think I could’ve done anything in 6 hours then besides trying to grasp all of the things that Rails has generated.

    Another thing was the fact, that without it, it’s hard for me to query needed fields – you need to write a pure SQL query to get it. Yeah, you use a library to use pure SQL – pretty normal, right?

    That doesn’t sound true, Sequel practically never requires you to write pure SQL, especially for something that simple. ActiveRecord is the one that often requires you to write pure SQL, because its query API isn’t that good (at least when compared to Sequel).

    What’s even funnier, is the fact that in a simple SQL query I needed to use a Sequel method, to get what I needed.

    You could write it like this:

    It’s great that ROM and Hanami expose the underlying Sequel query API, because there is no reason to hide it.

    The biggest problem is the fact that the most Ruby gems aren’t created or designed with Hanami use in mind.

    That’s the problem of the Ruby ecosystem, not Hanami. Notice that a gem doesn’t need to be designed with a web framework in mind, it’s usually enough that it isn’t Rails-specific (many Rails-specific gems don’t need to be Rails-specific, it’s just a convenience which becomes inconvenient when you’re not using Rails). But it’s improving, we are getting great replacements for Rails-specific libraries (dry-validation instead of ActiveModel::Validations, Rodauth instead of Devise, Mobility instead of Globalize etc).

    So if you want to create a fast MVP and you don’t have a big budget or long timeline, you probably shouldn’t create an app with Hanami. As for me, it’s not ready for big production apps yet. You can build simple apps like a blog or something similar.

    If all you’re creating is an MVP, then by all mean use Rails. The downside of building apps with Rails isn’t getting started quickly (that’s actually the main upside), the downside is long-term development and maintenance. And that is what interests me the most. Anyone can build an MVP, you don’t necessarily have to use good development practices to build one. But you have to when you’re maintaining an application long-term, and this is the part where you learn the most.

  • Hi. Thanks for taking the time to try and write about Hanami.

    If you don’t mind, I want to clarify some points of your article:

    > Hanami allows you to create many applications under one application.

    We use “project” to indicate the whole product you’re developing (eg hanami new bookshelf), and “application” to indicate a subpart of it like the frontend, the admin area, the API etc..

    > Every time when you want to access the database, you should create a new instance of a repository object.

    In the future, it will be instantiated only once at the boot of the app. May I ask you what’s wrong with instantiating an object?

    > What is funny? The fact that, by default, something like MyModelRepository.new.count doesn’t work

    “count” is a SQL concept, but hanami-model will be able soon to connect to more type of databases, so #count can’t be exposed as default method in Hanami::Repository.

    > For me it’s like a base for models, without this it’s really hard to define any relation in a database

    Can you please expand this point?

    > That’s the plus for Hanami! But on the other hand, this division isn’t something new, we have it already in Rails divided into views and helpers.

    Hanami views aren’t Rails helpers. I’ll write soon a post regarding this topic.

    > Well, I’m not saying that it’s easy to achieve in 6 hours but I think that a similar MVP in Rails is creatable in 6.

    Every time you try to do something with a new tool it takes more time than doing the same thing with the usual tool.

    It takes more time for me to speak Spanish than English, and I’m slower with English if compared with my native language: Italian.

    You can’t compare habits formed in years with something completely new for you.

    > I had some problems defining a route in a form, and yes, I followed the documentation. All the time I was getting the same error, the route is not found. I was googling and digging in the source code without any success.

    What’s the error specifically? You’re bashing at other’s people work is not helping OSS nor Ruby. What is constructive and polite instead, it’s at least open an issue on GitHub.

    > The biggest problem is the fact that the most Ruby gems aren’t created or designed with Hanami use in mind.

    It’s true. There are plenty of gems specifically targeting the Rails “walled garden”, this is a huge problem for the Ruby ecosystem, because it enforces that monopoly/monoculture.

    As Ruby citizen what you should claim is more diversity of choice in the ecosystem, more Ruby (not Rails) friendly libraries.

    That being said, every Ruby/Rack gem can be used with Hanami. We’re collecting them here: http://awesome-hanami.org/

    Luca

    • Piotr Jaworski

      >> For me it’s like a base for models, without this it’s really hard to define any relation in a database

      > Can you please expand this point?

      You can leave without associations defined in a model but it really makes your life easier to have an access to an object’s associations. It’s much easier to have the access to all associations on the framework lever, rather than writting raw SQL queries to access an object.

      >> Every time when you want to access the database, you should create a new instance of a repository object.

      > … May I ask you what’s wrong with instantiating an object?

      Everything is fine! But on a code level, I think that it’s faster, more intuitive and easier to write one and short line of code instead of initializing an instance and then calling methods on it 🙂

      @jodosha:disqus, I really appreciate your great work for Hanami but I wanted to write my own opinion and how I see things around Hanami 🙂

  • Tiago Cardoso

    It seems to me that you don’t like hanami because it’s not rails. Your text refers a lot to rails-specific concepts you’re very familiar with (url helpers, associations…) and how hanami failed those, instead of questioning these or understanding the novel approach.

    I’ve never used hanami, and I can give you that at this point it might be underdocumented, but assuming that a rails competitor will have to reimplement rails paradigms “but this time well” isn’t really fair.

    • Piotr Jaworski

      I can’t agree with you – I’m not a big fan of Rails and I don’t defend it at all. It’s normal when you try something different, like Angular or React and previously you used jQuery for the frontend logic – everything is different and you need time for it. I just told that Hanami isn’t production ready yet and it’s under documented.

  • Abdelkrim Tabet Aoul

    Hanami is a good framework, the only downside is the documentation and lack of more advanced exemples

    • Piotr Jaworski

      Yeah, that’s true.