--- name: primary-slide class: primary-slide .strong[.footer[@schwad_rb]] ??? --- template: primary-slide class: left, middle # Ruby Archaeology: Forgotten Web Frameworks ??? はじめまして Hajimemashite (Nice to meet you) --- template: primary-slide class: center, middle # 👋 🕵️♂️ ??? Good morning, I'm Nick. I am a senior production engineer at shopify on the ruby and rails infrastructure team. And I am incredibly grateful to the encouragement I get at work from my team to research things like this. I have a keen interest in historical ruby. * pastrubies newsletter * reviving old gems and old ruby patterns that should still be used today. --- template: primary-slide class: center, middle # In the 2000's everyone was writing a Ruby web framework 👩💻 ??? There was a time in the newer days of ruby, particularly when you couldn't easily get a paid job writing it, when there were a tremendous amount of web frameworks coming and going. People would debate design patterns, configuration and modularization vs convention, and what was the Ruby Way to write the web. --- template: primary-slide class: center, middle # What I'm looking to achieve ??? I want to have a higher level discussion about these frameworks. To remind people that there was a time when everyone was seriously experimenting with these. And that we should take that same experimenting spirit into the future. I will do this by talking you through three frameworks and one standardlibrary gem that I think have been forgotten and are worth looking at. For the record, I did run these by a ruby core team member and they do seem to work. <<<<<<<
>>>>>>>> --- template: primary-slide class: center, middle # CGI ??? CGI: > The Common Gateway Interface, or CGI, is a set of standards that define how information is exchanged between the web server and a custom script. A simple way to think about this if you're not familiar. You've probably heard of writing your own ruby framework sitting on top of Rack. CGI is a lower-level alternative that people were using before Rails become ubiquitous. This is a standard that you can install on your unix system and defines how your scripts can talk to these HTTP requests. Because of this ruby stdlib has a CGI library that people can use to this day. --- template: primary-slide class: center, middle # TL;DR - Perl ✨ ??? Or the TL;DR is this is another rubyism that we've inherited from Perl --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/cgi/images/1.png)] --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/cgi/images/2.png)] --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/cgi/images/3.png)] --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/cgi/images/4.png)] --- template: primary-slide class: center, middle ## This was actually used .left[![:scale 100%](./frameworks/cgi/images/5.png)] .right[_-Kirk Haines, IOWA maintainer, July 2009_] ??? Throughout my readings of ruby history this does appear to be a frequently referenced option amongst rubyists around 2001-2008 at least. --- template: primary-slide class: center, middle ## Assessment 📒 ??? You can legitimately do this today. You just need to configure this along with a server like apache on a unix system. From here your only limits are ruby. As with anything else this is bare-metal enough you are quite limited to have to roll everything yourself. It would be fun for a sandbox project but definitely not something I'd see as a viable solution unless I was just trying to sneak some ruby on as a lightweight handler for requests on a server. <<<<<<
>>>>>>>>> --- template: primary-slide class: center, middle # nitro ??? This takes us to our first web framework, nitro --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/1.png)] ??? 1--- Nitro intro landing page image Inspired future frameworks last release in 2009, but peaked just before 2007. (1 img) First version October 2004 George Moschovitis (it appears was the main maintainer) and Trans --- template: primary-slide class: center, middle ## Description from docs: .left[ > Nitro provides everything you need to develop professional Web applications using Ruby and Javascript. Nitro redefines Rapid Application Development by providing a clean, yet efficient API, a layer of domain specific languages implemented on top of Ruby and the most powerful and elegant object relational mapping solution available everywhere. Nitro is Web 2.0 ready, featuring excellent support for AJAX, XML, Syndication while staying standards compliant. ] ??? --- template: primary-slide class: center, middle ## RubyTalk in 2006: .left[ > I've built applications in both Rails and Nitro. They're different enough that both are worth knowing. > I believe that Nitro was underway at the same time as Rails was getting going; both are frameworks extracted from actual applications built to solve real-world problems. The projects may or may not have copied ideas from one another (though I assume all good projects steal from everything they can), but neither is a wannabe. > I find that Nitro lends itself to a different way of thinking about Web and application development than Rails, and Og (the O/R part of Nitro) is better suited for certain data and object persistence needs than ActiveRecord. > The best part, of course, is that it's not an either/or choice, and if you're serious about Web development in Ruby you owe it to yourself to spend some time with Nitro, IOWA, Rails, and Wee, for starters. > Ruby gives you choices. Pick the best tool for the job. ] .right[_-James Britt, July 2006_] ??? Read quote. Then say. Let's dig into what nitro actually was now. below are notes: * Best link for intel https://web.archive.org/web/20080619051450/http://www.nitroproject.org/ * screencast is there under videos but I can't find information * seems closely married to "og" for db: https://rubygems.org/gems/og * another nitro site: https://web.archive.org/web/20041119021640/http://www.navel.gr/nitro/ * great rubytalk thread at 0.31.0 version https://rubytalk.org/t/nitro-ann-nitro-og-0-31-0/29230/11 * https://github.com/nitroproject/og * https://github.com/nitroproject/raw * https://github.com/nitroproject/nitro * Nitro chat archives: https://web.archive.org/web/20070821192046/http://rubyforge.org/pipermail/nitro-general/ * https://web.archive.org/web/20061023142317/http://repo.nitroproject.org/ <- repo --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/2.png)] ??? 2--- Nitro consists of four libraries in one dependency. Raw, og, facets and jquery (2 img) --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/cgi_native.png)] ??? 3--- One remarkable part of this application is it pre-dates rack. So it has its own framework implementation sitting atop CGI that we just referenced. So if you want to look at a full ruby application built without Rack as a dependency, this is the one. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/4.png)] ??? 4--- You could write your app as you want. PHP style _automatically transformed into ruby code by nitro_; or traditionally MVC pattern. Nitro appears to have taken to the extreme _not_ being opinionated and very much being Opinion over Convention. I avoid saying configuration over convention because I'm unsure if it actually had a prohibitive amount of configuration despite supporting a lot of different permutations (4 img) --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/5.png)] ??? 5--- Nitro Supported fragmented/action based templates that would support componentization (5 img) --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/6.png)] ??? 6--- And additionally supported including those fragments at compile time or runtime (6 img) --- template: primary-slide class: center, middle # everything and the kitchen sink 🚰 ??? MoreFeatures--- So much more! (no img) Nitro also utilized the DRb library to provide distributed sessions when running your application over a server cluster, Included scaffolding mechanisms to speed up development, Brought over the facets rubygem which was quite popular in this era, adding a lot of extra features to ruby. also jquery which gave people javascript power --- template: primary-slide class: center, middle # 🚨🕵️♂️💎🚨 # `og` ??? The most interesting of all of these I think is its closely coupled dependency: og --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/7.png)] ??? 7--- Its most notable dependency, packaged as a separate gem altogether, was `og`. "ObjectGraph". It made a lot of bold claims about its features (7 img) Particularly, looking at line 1 from the docs, automatically mapping standard ruby objects to schemas. Let's have a look at it in action --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/11.png)] ??? 11--- Object level 2 (img 11) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/12.png)] ??? 12--- Object level 3 (img 12) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/14.png)] ??? 13--- And this is how you set up og, give it a config and have it setup (img 13) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/9.png)] ??? 9--- Og actually does create a schema upon `Og.setup`, connecting and transforming with an existing data store. It's really quite unbelievable. (img 9) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/10.png)] ??? 10--- evolve handles things like column addition and removal, and it also handles rename (img 10) --- template: primary-slide class: center, middle # 🧐 ??? ?--- Is this feasible, scalable or sane? I'm not exactly sure. But what I can tell you is that this is conceptual compression on steroids and I LOVE IT. Write your vanilla ruby objects with just a tiny dash of extra information around typing and boom, there it goes. I'm unsure how it worked with validations but since this is raw, pure ruby you can do whatever you want --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/15.png)] ??? 14--- one of the problems I ran into: example code is referenced a lot in the docs, but not available in the code on github. annoying! and there are only four publicly available commits. so the options you have are to rip download older versions from rubygems.org OR in this case go to the pre-rubygems repo website and find the code directly with archive.org (img 14) We need to remember not only is this running on an old version of ruby but its heydey was pre-rubygem.org, a lot of discussion about it is really lost. --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/16.png)] ??? 15--- but I was able to dig up a hello world document hello world (img 15) --- class: center, middle, code-slide .center[![:scale 60%](./frameworks/nitro/images/17.png)] ??? and also a traditional blog example where we can see the directory structure here 16--- directory structure (img 16) (models are as we've seen before on og) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/18.png)] ??? 17--- controllers don't seem particularly controversial (img 17) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/nitro/images/19.png)] ??? 18--- additionally templating does seem to support componentized partials as well (img 18) --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/nitro/images/20.png)] ??? 19--- I could not find many references to the power of scaffolding and using PHP etc. that was mentioned in the original documentation which was frustrating. (img 19) --- template: primary-slide class: center, middle # Assessment 📒 ??? Assessment--- Nitro has a lot of powerful concepts. It is heavily limited by being tied to ruby 1.8.2 so you'd need specified tooling to be able to use it. It's even harder if you're on an M1 which many people are. Og is worth a second look in 2022. Nitro the framework itself, for all its promises, is hard to surface. The original code is not on rubygems. The examples don't appear to exist anywhere and weren't archived full on `archive.org` (except for one unrevealing `hello_world` example). The existing testing isn't revealing enough to be interesting. This is a shame. The mailing list seemed relatively active for four years which is a long time in ruby terms. People were using the framework. It seemed to have novel ideas with scaffolding and supporting variable approaches like PHP. It was referenced for years on linklists as a "way to write ruby for the web". For the purposes of a future talk, somebody could invest time solely working through the existing code to first get it running in 2022, then explore example use cases to see if there's anything more interesting. But this is okay - because Nitro laid the groundwork and inspiration for our next framework we're going to explore, which is much more documented and preserved in 2022. <<<<<<
>>>>>> --- template: primary-slide class: center, middle # Ruby Waves 🌊 --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/1.png)] ??? Introduced February 2008. Dan Yoder at AT&T interactive. As a curiosity this place seemed to be the hub of ruby at the time, also hiring Aaron Patterson and Ryan Davis. Mostly dead by 2009. Very quick life. (img 1) Emphasis on "Resource Oriented Architecture" and thinking about the shift to the cloud which we now sort of take for granted. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/27.png)] ??? this was presented at rubyconf 2008 (lacon, goruco, lonestar ruby as well) - some of my slides here will actually be direct screen grabs of the unveiling at rubyconf 2008 and therefore will be of diminished quality --- template: primary-slide class: center, middle # 🚨🕵️♂️💎🚨 # `functor` ??? I want to take you in straightaway here to my favorite waves dependency. Functor was a foundational dependency for waves and very much influenced a critical part of its unique architecture. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/13.png)] ??? immediate discussion about functor --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/24.png)] ??? Method pattern matching without method_missing --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/25.png)] ??? Can also use functor directly to implement matching like seen here for fibonacci --- template: primary-slide class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/26.png)] ??? you can even define your own matchers as seen here with a lambda. now functor _does_ have a performance cost but it alleviated that with some good, built-in, configurable caching. Now what made this dependency so critical to ruby waves and how was it used? --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/15.png)] ??? Here it is in action in an app gave pattern matching in ruby many years before in stdlib --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/16.png)] ??? simple example how it works in waves --- template: primary-slide class: center, middle # Hello, World example ??? Let's see this in a little hello, world app --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/waves_hello_world.png)] ??? Here you can see, simply, the map class which acts as a request router delivering us our hello world. in a larger application that would pitch requests to their resources which would then leverage functor to hit the appropriate methoc. --- template: primary-slide class: center, middle # Architectural/Design Concepts ??? resource delegation. look at enough of the request to tip you off what resource you're going to. (subdomain, etc.) Waves has this idea of using ResourceClasses instead of routing. 1. resources are ordinary classes so he can leverage full power of ruby like inheritance, mixin, modular, encapsulated code design. not a special construct just instance methods on resource classes. 2. If you've ever dealt with large applications in route-based frameworks is after a while it starts to get really difficult to weild and manage the routes, knowing what thing matches what request. It's evident there in "map". 5-15 request functors in a resource, then you can decide to decompose resource into further functors. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/17.png)] ??? MAP class to send to right resource. then: Utilizing the functor pattern matching to route requests to the appropriate part of the module but uses a map class to get it where it needs to go --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/20.png)] ??? layers and foundations let you include what you need. e.g. there's an mvc layer. and if you look really closely, you'll see a certain dependency mentioned here called- AUTOCODE! (next slide) --- template: primary-slide class: center, middle # 🚨🕵️♂️💎🚨 # `autocode` ## better autoloading --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/2.png)] ??? Like our previous examples, waves as well has a really intriguing dependency packaged in. AutoCode. (img 2) released and subsequently included in the waves organization, it has not received a commit since 2009 but remarkably works perfectly fine on Ruby 3.0. Also allows you to match resources with desired paths --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/3.png)] ??? Say we have my given model here, model in my schwad app called fish with one instance method (img 3) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/4.png)] ??? and then I go into my application loader file here. I require in the dependency, include it and use this method to autoload everything in that directory. (img 4) --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/5.png)] ??? We put a slight modification to the file here to prove it's not loaded until it's invoked --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/6.png)] ??? and voila! it only gets loaded when it's called. This is intended as a much more elegant version of autoload --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/7.png)] ??? It also gives you additional methods to reopen classes or modules without clobbering on reload. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/8.png)] ??? However, the ruby community now have a massively powerful world-class solution in Zeitwerk, so perhaps this solution is no longer tenable. --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ruby_waves/images/10.png)] ??? I _had_ to try out this example on a benchmark though to see if they were comparable --- template: primary-slide class: center, middle # 🏃♂️💨 .left[![:scale 100%](./frameworks/ruby_waves/images/9.png)] ??? And, unsurprisingly, zeitwerk was 3.6 times faster. --- template: primary-slide class: center, middle # 🏎💨 .left[![:scale 100%](./frameworks/ruby_waves/images/11.png)] ??? As a side note that was on a ruby 2.x.x version, the gap widens above 4 times faster on ruby 3 --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ruby_waves/images/22.png)] ??? Lofty roadmap which was never achieved. future roadmap items. many of these never happened. --- template: primary-slide class: center, middle ## Assessment 📒 ??? Never fully got off the ground. 2008 RubyConf talk was more like "this is in progress" and steam seemed to come out of it by 2009. Could it be that it was hoovered up by Merb for all the people that wanted a popular alternative framework? It offered modularity but Merb seemed to be better at that. Also this might have been a one-key-man passion-project. also it was coming at a time when market share was getting incredibly crowded by merb which was taking off and another popular ruby framework. And it seemed to end when merb made the decision to merge with that other framework. Was there a community-wide decision in 2009 to abandon alternative web frameworks and this was one of the casualties? Why isn't this popular today? Well I'd have to say that despite all the work in modularity over the years, if I spin up a library's webapp I generally _do_ include all the bells and whistles. Even if I don't need them. There's next to zero overhead in keeping them (unless I'm making a hyper performance application) and there is pain/overhead if I need to include them later. It's best to keep webapps as similar as possible (think about rubocop for example) for others to be able to access it. Modularity may have been a 2008-2014 developer fantasy that never panned out. There were four talks given. la ruby, gotham ruby, lone star ruby and rubyconf. where it ended seems there were still a lot of vastly different proposed ideas that died off. <<<<
>>>>> --- template: primary-slide class: center, middle # Ramaze 🤩 ??? ## About it Unveiled in November 2006. Marketed to be a middle ground between Merb and Rails. Modular but still MVC. Inspired by Nitro --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/19.png)] ??? 19 This is not rails --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/20.png)] ??? 20 debut on RubyInside --- template: primary-slide class: center, middle # IT WORKS! 🎉* ??? spoiler alert __(< Ruby2.7 but may work on edge Ruby with a little massaging)__ <
> ``` ruby -v #=> 3.1.2 gem install ramaze ramaze create blog #=> The application has been generated and saved in blog ``` --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/2.png)] ??? Ramaze homepage is still up and kicking. This is the most "alive" framework of anyone I will talk about today. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/22.png)] ??? Rubytalk in '09 allege ramaze took up where nitro left off --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/21.png)] ??? Last ramaze ref I could find was in 2012 though it seems to have fallen off a bit before that. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/4.png)] ??? ramaze mission statement --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/3.png)] ??? quick example with hello world. all you need is a controller with an action, routing is baked in as well and you get going which is quite nifty core. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/6.png)] ??? page working locally! --- class: center, middle, code-slide .center[![:scale 60%](./frameworks/ramaze/images/7.png)] ??? Something you see repeatedly is that despite the divergence of frameworks a few things remain the same like relying on rack and this style of directory structure --- template: primary-slide class: center, middle .left[![:scale 110%](./frameworks/ramaze/images/8.png)] ??? This is one of the most interesting things you'll see about ramaze (ties in with waves) - once again the concerns about routing in the controller with map "/". This is similar to rubywaves having this concern in the controller. I think that perhaps you could mold both concepts. A map method to "get" into the controller and then functors to pattern match from there. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/9.png)] ??? Further discussion from the docs on view mapping --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/10.png)] ??? list of template engines it supports. I do not know all of these. That will maybe be my next archaeology talk. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/12.png)] ??? "provide" controller syntax to handle various typess like json. (TODO: read more into this!!!) --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/18.png)] ??? it was all built on a core innate dependency. think like merb but instead of totally modular it started with this one core. wtf was innate? example app --- template: primary-slide class: center, middle # 🚨🕵️♂️💎🚨 # `etanni` ??? Beyond that "map" approach etanni I find to be the most interesting dependency of ramaze. It is within a core dependency called "innate", which is the raw-stripped-down heart of ramaze. Interestingly enough, this templating engine was never made into a gem and has been largely forgetten about. --- template: primary-slide class: center, middle .left[![:scale 100%](./frameworks/ramaze/images/13.png)] ??? Now have a look at this syntax for etanni. It starts with default ruby-style interpolation in the HTML. And its own flavor for raw ruby code. But if you look at this cut off statement they allege it's faster. So let's test it. --- class: center, middle, code-slide .left[![:scale 100%](./frameworks/ramaze/images/15.png)] ??? Not counting the integrations and caching this is etanni and this is what we test with. You'll have to read through a gist on your own time to fully get to grips with it --- template: primary-slide class: center, middle # Fastest template engine? 🏎️ * .center[![:scale 70%](./frameworks/ramaze/images/fastest.png)] --- template: primary-slide class: center, middle .center[![:scale 100%](./frameworks/ramaze/images/hbbm.png)] --- template: primary-slide class: center, middle # @k0kubun && @noah_gibbs ❤️ ??? Credit to kokubun, who has done so many things for our community including maintaining erb and haml, for helping me look into this. --- template: primary-slide class: center, middle .center[![:scale 100%](./frameworks/ramaze/images/kbm.png)] *_maybe not in reality_ --- template: primary-slide class: center, middle # 🎉 .center[![:scale 100%](./frameworks/ramaze/images/etanni_gem.png)] ??? If you would like to assess this yourself, I have published it as a standalone rubygem! --- template: primary-slide class: center, middle # Assessment 📒 ??? Now let's assess its feasibility in 2022. This could be today's biggest winner because I was able to run it on an m1 with ruby 2 with little to no trouble. Additionally, the `innate` core could let you strip even more out. Etanni is worth pursuing although I'm suspicious that in a real-world environment it may not be the fastest ruby templater. But I have gemified it just in case. <<<<
>>>>> --- template: primary-slide class: center, middle # So many more! .left[ * wisteria * vintage * iowa * maveric * cerise * halcyon * arrow * coset * wuby * unicycle ] ??? --- template: primary-slide class: center, middle # What will _you_ build? 👷 ??? --- template: primary-slide class: center, middle .tc[ # Let's connect! 📩 ## Follow me @schwad_rb 🐦 ] ??? ---