Working on Elm has changed my perspective on several subjects. The first and most obvious one was about front-end development. To the past-me (big surprise), it was no longer a nightmare nor did it require me to invest lots of effort at mastering Javascript. Six years into running Elm sites in production, I feel similar to how I did in the beginning: “Me and the compiler - we’ve got this.”
After over a decade with a large Drupal community, the second shift was that having a small team/ a single project lead has its place. At times I wished there were more community members to speed up development; but Elm has reached enough maturity - at least from my perspective - and I enjoy the slower pace that Evan Czaplicki, the Elm project lead, is taking to explore the next steps.
Finally, and related to that, I’ve learned that there’s also a benefit in terms of both employees and new projects. There are so few Elm shops out there that finding talent is relatively easy compared to other technologies such as Drupal or React, with a bigger talent pool, but a higher demand. Similar to that, we are lucky to get an inquiry about building an Elm project every few months. I wouldn’t build my entire business around it, nor does it come close to the revenue we get from Drupal - but it’s always fun to get those projects.
So with the above explanation, it shouldn’t come as a surprise that we’ve decided to augment our toolbox with IHP - a Haskell web framework. It’s not going to replace anything, and Drupal is still our weapon of choice. However, even a powerful CMS like Drupal can’t - and shouldn’t - solve all types of challenges. One example would be our online-auctions product. The website that shows the catalog will remain in Drupal, as it clearly benefits from content management. However, the bidding server could benefit from really really fast responses.
I’d like to emphasize that I don’t think IHP is the Rightâ„¢ solution for every webshop. However, since many of our developers already know Elm, embracing a backend solution with similar concepts and syntax seems right from a business and technical perspective.
IHP isn’t free of problems, and I’d attribute those to the fact that it’s relatively new. However, it’s being actively developed, and so far, I’ve already received many solutions, quick PR reviews, and help from project lead Marc Scholten. With IHP, I know that we’ll be able to build better solutions for our clients. Having a powerful type system and compiler has already proven to be of the utmost value for the frontend, and I’m happy there’s a viable backend option.
Demo Web App
I’ve created an demo application for this blog post. It was so much fun, and I admit I’ve polished it a bit more than I intended. It’s also worth mentioning that writing this web app uncovered some missing functionality or bugs, so by working on it, I hope I was able to help pave the way for a better framework for us and others.
The purpose of the web app is to simulate a simplified seat reservation system. Every venue can have multiple events, and then a person would enter some fake numerical ID, and if there’s a free seat, it will be assigned to them. There’s no access control implemented, so you can CRUD all the entities. What’s nice is that you can play with it, without having to install anything thanks to GitPod integration. So go ahead, and click the badge, and see it in action.
After GitPod spins up, make sure to allow it to open the 8000 port URL.
Once you see it working you can click around, or go directly to /ShowEvent?eventId=7a7e856f-8475-48f5-977b-21bb85133a88
.
When an attendee wants to register a seat, it’s vital that we don’t assign the same seat twice. That would require some kind of locking or queueing. We’ve tried locking in the past, but that didn’t scale well. A better solution would be to queue the reservation request and process it as a background job. Something like this:
In our Reservation controller, if a request is valid, we save the Reservation with a Queued status. It doesn’t have a seat yet, but we’ll respond to the user that the Request for a seat was accepted.
Right after that, we create a ReservationJob that references the Reservation. The actual seat assignment - or rejection if none is found - is done in this background Job. Normally IHP will process jobs in parallel, however in order to avoid race conditions and assigning the same seat twice, we tell it to run it sequentially. By the way, if you are familiar with Elm, the seat assignment code should look quite familiar.
Finally, we send a mail to the attendees. Since it’s Haskell, we can do it async, making sure that sending the mail isn’t stalling the process of the Job. We’ve integrated Mailhog into the Gitpod installation, so you can click on the link that appears on the event page, and view the HTML emails sent.
The subject of the mail will change based on the status of the Reservation. With the type system in place, the compiler makes sure we that do not forget any possible case.
Testing is also part of any good development, so here’s how it looks.
If you are curious about performance, you can copy/ paste the curl command from the event page, and run it locally or from Gitpod. It uses parallel
to run concurrent requests. In our testing, we’ve seen 50 requests received by the server in about 2 seconds, and then about 1.5 sec more to finalize their processing and assign the seats.