Entry dated 2015-05-09
I stat down to write a very thin HTTP abstraction after talking with Piotr on design and Thrift influences. After a few hours barcelona was born. I don’t know how to really describe it so I call it an HTTP <-> object mapper. It wires path names to method calls with encapsulated HTTP semantics. Sure I had created it, but I hadn’t used for anything. I considered using it for the Tracelogs experiment but I don’t see continuing that effort in Ruby. Luckily Piotr and I came up with an idea that proved be a useful test bed. It’s a simple ruby application built the new way ™.
This is my structure for creating ruby web applications:
- Barcelona for mapping HTTP to my object(s)
- ROM for persistence
- Mustache for views
- No environments!
- Write all executables yourself (Take back ARGV!)
I had an idea of how these things could fit together but I wasn’t quite sure. I started out using Cucumber features to specify the application’s behavior (because that’s all I could reason about) and used that to drive out object design and collaboration. It started a bit shaky at first, but as I wrote more code things got better. It turns out this arrangement is pretty damn nice!
This was the first time in years that I done any web development outside of a larger framework so that was interesting. This was also the first time using mustache without any integrations. It was much nicer this way! It also tears down some barriers since it’s obvious how a view class turns into HTML. I was also able to solve the annoying layout problem using simple OOP. Templates are one the biggest bullshit things about web development so it’s nice that I could solve this problem in a clean way. I’m absolutely confident this layer will scale without problems while maintaining transparency (much more so than I felt inside Sinatra).
I’m also quite happy writing my own executables; now I’m back in
control of how my code is loaded and how various blocking foreground
things (like servers) are configured and started. Most importantly
there is no
rackup bullshit! Feels great. All the options that could
ever be are exposed as options flags and the appropriate thing
happens. Want to reload code before each request? Use
some junk data? Provide
--dummy-data. Most importantly it gives me a
single place to collect all the object wiring that has to happen.
There are a few things I’m still on the fence about–they’re mostly barcelona concerns (so not specific to this codebase). Barcelona needs a route generator. This is the only way to say on the same side of the abstraction. Right now the processor object has no clue what HTTP route is, but naturally you need to create them in templates. So that must be addressed.
I’m also curious about removing inner presenter classes from the view
classes and extracting those as entities. ROM can map relations to
different classes so such a thing may be possible, but I’m unsure of
how this would come out in practice. It probably makes more sense for
data heavy models and not objects requiring a bunch of view decoration
(e.g. timestamp formatting). I’m mostly on the fence about this one
because Piotr leans this way but I don’t really see problem with
creating a bunch of
DelegateClass to handle all view specific
presentation. I bet this is highly problem domain dependant not a
general case thing.
Then there’s the global configuration object. I’m most curious how to
construct the system where such an object is not possible. I mentioned
wiring objects together. This is a natural thing when there’s
collaborating classes. The program must take
--data-store=sqlite://tmp/db.sqlite3 and turn that into an object.
Then in turn other objects in the system will need that object. I
ended up with a constant called
SYSTEM that collects all these
objects. It’s a simple class instance with some extra methods tacked
on. In practice I find that this object is not needed inside
application code. It’s only needed in tests. I think that’s because
test code is different than the general path (in some ways). I don’t
know if the existence of such a constant is good or bad thing but
right now this is the only way I can construct these programs.
Regardless of it’s implementation the existence of the class has
proven vary useful! The
System class has methods for everything the
system can do. There’s not need to coordinate use cases across
multiple objects. This means there’s only one way to do things and the
outcome is the same every time. This has proven most useful in tests.
For example the system has a
clear method. That method will clear
all things that need to be cleared (like a background queue, data
store, or any thing else). All in all I’m quite happy with this
All in all the result of this experiment is promising. It’s shown
enough promise to continue in this direction. I’m also starting to
consider how to expose HTTP semantics through
Barcelona::Response. Things like sessions, files, and various other
information is much cleaner like this than with rack itself. So good
things coming for future ruby web work!