The Amber Framework is a young and growing web framework written in our favorite language, Crystal. It shares many similarities with Rails, but - like Crystal itself - compatibility with Rails is not a design goal.
Here are a few reasons why I <3 Amber:
- Familiar framework design
- Compile time checks that save your sanity and maybe even your soul
- Open and welcoming framework development team
- Raw Speed
Familiar Framework Design
Amber projects follow similar design to Rails and other MVC focused web frameworks. It borrows organization and concepts where they’re successful and builds on that foundation where developer efficiency or simplicity can be improved.
Rails veterans will recognize many of these files and folders immediately:
.. (up a dir) </repositories/offline_pink/ ▸ db/migrations/ ▾ src/ ▾ controllers/ application_controller.cr user_controller.cr ▸ mailers/ ▾ models/ user.cr ▾ views/ ▾ user/ new.slang show.slang
Models, views, controllers, and migrations are all right where you’d expect them. You’ll feel right at home. Environment config files follow a familiar style and a working asset pipeline is available right out of the box, if you want it (thanks to webpack).
Compile Time checks
Thanks to Crystal, a large portion of an Amber project is evaluated at compile time. Never again get an email from production complaining about something so mundane as a
controller#action missing, or
Undefined method .downcase for nil:NilClass.
Amber even parses and compiles templates and layout files which not only verifies that the code is calling methods and getters safely, it saves a lot of time during a request.
Crystal does a great job of complaining when a method call on a variable isn’t valid for all possible types of that variable. Amber uses that power to ensure the application isn’t going to break at runtime wherever possible.
Observe what happens when compiling an Amber application with this broken template:
- if domain.nam.blank? p No domain name
The compiler complains, notifies you of the problem, and even suggests a correction:
in macro 'macro_4598546880' expanded macro: embed:1, line 1: > 1. if domain.nam.blank? 2. __kilt_io__ << " 3. " 4. __kilt_io__ << "<p" 5. __kilt_io__ << ">" 6. __kilt_io__ << HTML.escape(("No domain name").to_s).to_s(__kilt_io__) 7. __kilt_io__ << "</p>" 8. end undefined method 'nam' for Domain (did you mean 'name'?)
These compile time checks can save your sanity when an accidental typo slips its way into your routes file, or accidentally forgetting to commit a view template.
Open and welcoming dev team
The Amber project is active. Development on the tools, framework, libraries, and documentation is constant. Yet I’ve felt welcomed into the fold as an Amber contributor as the core team readily reviews and merges my pull requests, discusses framework direction and goals, and openly accepts suggestions and contributions from casual contributors as well as frequent benefactors. This picture is from the Github Pulse and shows how active the project has been this month:
Last but certainly not least, thanks to Crystal, Amber is fast. The compiled web is real, and it’s far more friendly now than ever before.
Check out this log excerpt from a project I’ve been working on:
10:49:15 Request | Started 2018-01-11 10:49:15 -07:00 10:49:15 Request | Status: 200 Method: GET Pipeline: web Format: html 10:49:15 Request | Requested Url: /domain/30 10:49:15 Request | Time Elapsed: 17.52ms
This particular request is slow by Amber standards, but it checks all the boxes:
- SELECT queries across several tables1
- validating logged-in user session, and authenticating access for the request2
- rendering html views (not just JSON)3
Compare to a page with similar database and rendering overhead in a Rails 5 application:
processing by BookmarksController#index as HTML Completed 200 OK in 251ms (Views: 217.9ms | ActiveRecord: 15.9ms)
That’s right. Thanks to the speed of Crystal, Amber can complete an entire request in about the same amount of time it takes Rails to query the database. That means each server can handle more traffic, is more resilient to denial of service, and every page is more responsive4.
For a real sample of speed, this excerpt is from a basic Read route such as this:
def profile user = current_user render "show.slang" end
01:19:11 Request | Started 2018-01-11 13:19:11 -07:00 01:19:11 Request | Status: 200 Method: GET Pipeline: web Format: html 01:19:11 Request | Requested Url: /my/profile 01:19:11 Request | Time Elapsed: 1.75ms
Or even faster, serving a static file:
01:19:11 Request | Started 2018-01-11 13:19:11 -07:00 01:19:11 Request | Status: 200 Method: GET Pipeline: static Format: 01:19:11 Request | Requested Url: /dist/main.bundle.js 01:19:11 Request | Time Elapsed: 329.0µs
Amazingly, because Amber views are compiled in, rendering a template and layout can be significantly faster than serving static files when the application is configured for it5:
01:45:15 Request | Started 2018-01-17 13:45:15 -07:00 01:45:15 Request | Status: 200 Method: GET Pipeline: web Format: html 01:45:15 Request | Requested Url: / 01:45:15 Request | Time Elapsed: 371.0µs 01:45:16 Request | Started 2018-01-17 13:45:15 -07:00 01:45:16 Request | Status: 200 Method: GET Pipeline: static Format: js 01:45:16 Request | Requested Url: /dist/main.bundle.js 01:45:16 Request | Time Elapsed: 80.01ms
No matter what your application is doing, Amber can do it faster.
A lot of software is written for the web today. Ruby and Rails showed the world that development doesn’t need to be painful for developers. Crystal is a language where development ease meets speed, and Amber is a framework built on that tradition. Developer friendliness meets raw speed and power, for the web. Or to borrow from Amber’s tag-line: Productivity. Performance. Happiness.