Originally posted on notmagic.org, reposted here for discussion.
I've spent the bulk of my time the last few weeks working towards the Pakyow v1.0 release. While not a from-scratch rebuild, I'm revisiting every single aspect of the design, starting with how Pakyow Apps run within a process.
One of the things that previous releases got wrong was managing application state. Nearly all of an application's state was contained in singleton classes, which, like most bad ideas, seemed like a good idea at the time.
It worked great up to the point you wanted to run more than one Pakyow app within a single process, which you simply couldn't do. Nearly every project I've worked on over the last few years has started as a monolith that's eventually broken down into two or more separate apps. Making the transition has been a painful process every single time.
Changing how app state is managed would let us implement different features as independent apps and run them together in a single monolithic process. You get the ease of creating a monolith, while the framework enforces separation between features so they can later be moved into standalone apps or plugins.
Just yesterday I finished working on a new runtime environment for Pakyow. The entire goal was to make it possible to define, mount, and run multiple apps alongside each other inside of a single process. And it works!
Here's what it looks like:
mount Pakyow::App, at: "/"
Here we use the main
Pakyow object to configure the environment and mount a single app at the root path. Next we setup and run our environment in development mode.
Mounting is implemented as a lightweight layer on top of
Rack::Builder, which already supports mapping requests to multiple endpoints. Building on top of Rack kept the size of our implementation fairly small, weighing in at 719 LOC.
The Pakyow Environment is pretty simple, but it has some advantages. Perhaps the biggest advantage is that concerns of the environment are shared across every app that runs within it. For example, every app runs on the same host and port and inherits a common request logger.
Pakyow also loads a default middleware stack for the environment. Out of the box all apps support things that most apps need, like
HEAD requests and JSON request bodies. There's no configuration necessary.
We've effectively separated the concerns of the app itself from the concerns of the environment that runs it. Admittedly, it's a subtle distinction, but the consistency it brings is really nice.
If you're interested in seeing more of the implementation, it's all pushed up to the environment branch on Github (environment is in
Something else that I'm excited about is that the public api for the main pakyow gem is fully documented! We are also sitting at 99.75% test coverage, thanks to the shiny new test suite. This part of the framework feels ready for v1.0.
Keep in mind that core, presenter, mailer, realtime, and ui (okay literally all the other main gems) are broken on the environment branch. This change touches everything and there's still quite a bit of work left to make the rest of the framework compatible. That's all in progress