Talks

Hanami::API

Hanami is a full-stack web framework for Ruby. With Luca we will learn what will be the major changes for 2.0 release.

Luca is the creator of Hanami and author of redis-store. Also a dry_rb core team member.

He also works as Back-end Architect at Toptal to envision a SOA architecture for the company.

Pivorak Conf 5.0 - Online Edition

00:00:08.290 I am happy to announce the second speaker, Luca Guidi. He is the author of Hanami and a core team member of dry-rb.
00:00:12.190 Luca has made a significant impact in the open-source community and somehow manages to build amazing projects without working on weekends. At least a year ago, he wrote about taking time to rest during workdays and contributing to open source.
00:00:21.730 He has a wonderful blog at lucaability.com, where I learned that he's exploring techno music and meditating. He uses OKRs to track both his professional and personal goals.
00:00:29.619 By the way, I'm a fan of OKRs as well. I utilize this approach for my personal and professional development.
00:00:36.010 Luca has spoken at many conferences, and this year, he mentioned meeting Matt for the first time this February in Paris after years of collaboration.
00:00:48.070 His journey with Ruby and Hanami started back in 2016 when we had a meetup dedicated to Hanami, and it was a memorable event.
00:00:57.640 Recently, the Hanami team announced Hanami API, a minimal, extremely fast framework. Let's take a closer look at what's inside together with Luca.
00:01:09.400 Luca, it's your turn. I had to say this was the best presentation ever. Thank you, Anna. Thank you for the kind words, and thank you everyone for having me.
00:01:18.050 I want to talk about Hanami API, which is a small micro framework that I would like to introduce today. First things first, my name is Luca Guidi, and as mentioned earlier, you can find my website and GitHub links in my bio.
00:01:40.510 I work remotely from Rome as a back-end architect at Toptal. Before I start, I want to explain why I created Hanami API.
00:01:49.999 There are basically two main reasons. The first one is that we are in the process of rewriting most parts of Hanami, including the router. The old version 1.0 was based on an outdated mounting library, so I had to rewrite it.
00:02:08.600 The first alpha version of the new router was released over a year ago, and after comparing benchmarks, Jeremy helped me realize how poor the performance was on that version.
00:02:29.540 As a result, I did another rewrite, which yielded significantly better performance. Thanks to Jeremy for helping me pinpoint and resolve those performance issues.
00:02:40.330 I realized this wouldn't just benefit me; the community at large could also benefit from improved performance in Hanami and other open-source projects like dry and rom.
00:03:00.059 I want to make something that the community can reuse rather than just something I add to my own garden.
00:03:17.659 In general, when you look into a router, you typically need to build something that is low-level. So, I decided to wrap it into a DSL, allowing people to create a simple product: you install the gem, write a file, and have a tiny, focused HTTP endpoint.
00:03:35.350 The second reason for creating Hanami API relates to improving the adoption of Hanami. I understand that Hanami is a large framework, and there is a business risk involved for companies when considering a switch.
00:03:51.840 Considering how popular Rails is in our community, if we can offer something with very low friction to adopt—like a single gem for a small HTTP endpoint or service—then companies might be more willing to explore Hanami.
00:04:09.190 This reduced risk allows them to understand the philosophy behind Hanami without fully committing initially. From there, they can explore other aspects of it or related libraries that integrate well.
00:04:27.570 Those are the two main reasons why I decided to create this gem DSL, ensuring developers have something that is low-risk and ready to go.
00:04:45.541 Now, let’s have a look at the syntax, which is described here in this slide. You begin by including the gem, and then you create a superclass from which you inherit.
00:05:05.610 You define routes, and there are two ways to define them. The first option is the classic Hanami style, where you specify the HTTP verb, the relative path, and the action.
00:05:23.080 The new addition inspired by Sinatra allows using a block syntax to handle routes. You can also mount any rack application, so for requests starting with a certain path, they will be routed to that application.
00:05:43.070 Another interesting feature is that you can scope routes, which acts as a prefix, allowing you to group and organize your routes without repetition.
00:06:01.590 You can also scope rack middleware, meaning only requests targeting the API will use specific middlewares while others will not.
00:06:20.919 This scoping mechanism is similar to variable visibility in programming, allowing for more organized and controlled use of middlewares and routes.
00:06:41.290 Moreover, the last line of the code reflects that it behaves like any other Hanami gem. You create objects, handle responses, and manage requests as needed.
00:07:00.540 The features of this micro-framework include obtaining parameters from requests, managing response statuses, headers, and body.
00:07:18.410 You have control over the request execution flow for redirection, rendering content, and handling mounted applications.
00:07:37.870 I wanted to keep it minimal and not bloat the framework with unnecessary features, providing developers with only what they need to get started.
00:07:55.880 Now let's discuss performance, as this rewrite was oriented towards improving it. I utilized the Jeremy benchmark tool to measure performance.
00:08:15.410 For those who are not familiar, Jeremy wrote a benchmark tool called '10k', which compares Ruby frameworks and generates apps with 10,000 routes.
00:08:32.290 It measures various metrics, including memory consumption and request handling performance.
00:08:48.790 The first important metric is memory usage, where lower memory consumption indicates a more lightweight framework.
00:09:07.839 According to the benchmarks, Hanami API ranks second for memory usage among various frameworks.
00:09:21.460 For fulfilling requests, the benchmark executes 20,000 requests targeting the last route to measure the worst-case scenario.
00:09:37.140 We noted that to complete benchmarks, frameworks like Sinatra took far longer under certain conditions, indicating outliers in the data.
00:09:54.890 Zooming in on the performance comparisons confirms that Hanami API delivers excellent results, confirming its competitiveness.
00:10:12.830 The bottom line is that while Rails is often preferred for larger web apps and Sinatra for small endpoints, there is a growing ecosystem of highly performant HTTP frameworks.
00:10:31.059 This push for performance demonstrates that developers are seeking alternatives beyond the conventional options.
00:10:48.290 Now, let's delve into the implementation details and some performance improvements I’ve focused on.
00:11:04.330 Instead of going through the minutiae of code, let me explain it with a visual analogy. Many people are familiar with the game Guess Who.
00:11:21.669 In the game, you have 24 characters, and you need to identify the correct one. If you look at them sequentially, that represents the worst-case scenario for searching.
00:11:38.290 This demonstrates inefficiency; in contrast to a manual search, approaching it with direct questions improves efficiency.
00:11:52.820 The goal is to limit the amount of data being scanned, which leads to faster searches.
00:12:09.460 In programming terms, the ideal scenario would be constant-time access, where the data structure allows immediate access to the target value.
00:12:23.640 To achieve this, I revised the data structure used to store routes, transitioning from a list to a more efficient structure.
00:12:37.830 Previously, to find the last of 1,000 routes, I had to scan through all of them. By using a tree structure, the lookup time significantly decreases.
00:13:01.840 This change led to improved performance, further validated by benchmarking.
00:13:15.050 Additionally, I partitioned the tree rather than using a single large data set. This led to faster lookups by reducing the amount of data being processed.
00:13:31.140 The second improvement addresses the difference between fixed and variable paths. Fixed paths, such as '/dashboard', are quicker to resolve than paths with variable parameters.
00:13:44.230 Variable paths require additional computation, making them less performant since they involve matching against conditions at runtime.
00:14:06.410 Using a partitioning strategy helps route requests efficiently, similar to organizing a bookshelf by genre.
00:14:23.170 This view of maintaining smaller trees within those partitions allows for faster searches.
00:14:37.370 Ultimately, these improvements lead to the conclusion that utilizing optimized data structures can have a significant positive impact on HTTP routing performance.
00:14:53.560 When looking at the benchmarks, we observe substantial reductions in execution time and memory usage post-revision.
00:15:13.560 In conclusion, I want to address a common question: is Ruby still worth learning in 2023?
00:15:26.890 My answer is that the present state of Ruby is bright, and I am excited about its future. Thank you all for your time!
00:15:45.590 Thank you!
00:15:51.890 Walk down, it's your turn to ask questions.
00:15:54.890 There is one topic I’d like to discuss. Thank you for an incredible talk.
00:16:10.890 The first question is about the comparison between Hanami and Roda. In what use cases would you recommend using Hanami, and in which situations would Roda be a better fit?
00:16:30.890 In my opinion, both frameworks serve similar markets, although Roda might offer more features that I have intentionally excluded.
00:16:50.890 My suggestion is not to take my word alone but to install both gems, read their documentation, and evaluate which one aligns better with your use case.
00:17:10.890 The next question is about Hanami API and its use in practical applications. If someone only needs a single endpoint, what would you recommend?
00:17:30.890 For just one endpoint, you might think about creating something trivial, but consider the built-in facilities available in Hanami API.
00:17:50.890 Using Hanami gives you utility out of the box, with features for params handling, JSON parsing, etc., making it more efficient.
00:18:10.890 Additionally, you can leverage the advanced features from Hanami actions, saving development overhead and benefiting from a proven library.
00:18:30.890 It’s advisable to utilize an established framework to avoid reinventing the wheel, especially when the framework already has proven functionality.
00:18:50.890 Thank you for your interesting presentation!