Raindeer is a new web framework using the dynamic features and latest async improvements in Ruby + some weird ideas, to build a new breed of web application. Each Raindeer component can be used individually in your exisiting application, or all together as a cohesive framework. Deer to be different.
LowType introduces the concept of "type expressions", allowing you to add inline types in your code, only when you need them. LowType is an elegant type checking system with the most minimal DSL possible. It looks like if Ruby had native types; def method(var: String).
LowLoop is an asynchronous event-driven server that ties into LowEvent to create and send events from the request layer right through to the application and data layers. Finally you can see and track events through every step of your application.
LowEvent represents events of all kinds; Raindeer uses RequestEvent, RouteEvent, RenderEvent and ResponseEvent. Plus you can extend with your own event types. Events can be observed with Observers.
The RainRouter accepts RequestEvents and directs the request to the appropriate observers. Simply add observe 'path/:id' to a LowNode and now it will be called every time a request is made to this route.
LowNodes are the flexible building blocks of your application. They can respond to a route request, or they can be called by another node. They can render a return value, or they can create an event. They are designed to be specific enough to observe events and return values, but generic enough to be split up to represent a complex application with its own patterns and structure. Nodes can render HTML/JSON directly from the Ruby class (via RBX, similar to JSX) and render other nodes into the output using Raindeer's special Antlers syntax; <html><{ ChildNode }></html>.
Instead of the model defining relationships and associated queries to the database, LowData follows the repository pattern with a twist; Expressions. An expression like data(Table[:username] > Table[:title | :body)] builds a SQL query to RIGHT JOIN the user table into the articles table and results in a list of articles with the user's username in each row.
Raindeer pulls it all together with a router, pipelines and JS integrations. It's decoupled and event-driven via observers in a way that's deceptively simple whilst catering to the needs of complex applications with scalable architectures.
Anything that just "is how it is" can be made simpler. It may take lots of time to find a way how but it's worth it. We should really care about people new to a framework; they shouldn't have to learn much. One way to do this is by removing things, things you held dear and thought you needed are the best things to remove. Complexity can be hidden in a way where the surface is simple.
Some of the things we removed:
- Namespaces - Namespace are confusing to new and old developers alike and the
::syntax just doesn't look right. You can add them in later and they are still used internally by Raindeer, but not exposed to the application layer. - Heredoc - If you want to write multi-line HTML then you can just write it directly into a LowNode via RBX, Raindeer handles the technical hurdles
- MVC - You shouldn't have to learn the 5 places to put particular files in and the order in which they're called. Just
observean event in a node and render output, or call more code
Your files should just work out of the box. Internally this can create a "less clean" isolation between concerns, but with a bit of extra thinking we can still isolate these "mixed" concerns. Frameworks are here to make application developers lives easier, not our own.
An application is a living organism and so is the framework below it. Raindeer does a lot of dynamic processing of previously static elements; from type checking and expressions to parallelisation of low nodes via Antlers syntax. This is okay, the framework should do more and feel alive. That being said, dynamic doesn't mean "magic". Methods and classes should be compositional, so that you can understand their hidden complexity by drilling down into them as they go, rather than calling one magic method that does a bunch of things that you don't know about.
Install instructions coming soon... for now just clone this repo and play around with the lib/system folder, which is an internal Raindeer app inside the framework itself.
- Clone the repo
- In your terminal run:
bin/server