Up to this point, code loading has occurred by simply loading everything in
app/lib. Deciding how the code was organized within
app/lib was up to the developer. Moving towards 1.0, I'd like to add a bit more structure and predictability to code loading.
Here's the new generated structure I have in mind:
define.rb # defines the app
# groups together related aspects of a feature
# misc code that doesn't fit elsewhere (not loaded automatically)
# custom mappers for data models
# data model definitions
# asset files (css, js, images, etc)
# view templates for layouts
# view templates for shared partials
# all the other view templates
# presenter definitions
# router definitions
# router definitions
# view definitions
environment.rb # loads and mounts the app(s)
# misc code to be reused across the environment (not loaded automatically)
You'll see some references to new features, but ignore those details for now
Loading Backend Logic
Backend logic (e.g. mappers, models, presenters, resources, routers, and views) are all loaded in a similar way. On boot, we'll navigate through each type, loading each file and performing some simple validation. The app won't boot unless validation succeeds.
How validation occurs depends on what is loaded. We want to be reasonably sure that anything we load defines valid state for the app. A loader will be defined for each type that specifies 1) where to find the files and 2) validation rules.
Here's what a loader for resources might look like: gist
Pakyow won't attempt to resolve dependencies automatically (e.g. one model subclasses another). Too much magic. Instead, the developer must require dependencies manually. We will try to provide insight on how to resolve load errors, where possible.
app/lib loaded automatically?
Quite simply, I'm not aware of an approach that 1) works predictably and 2) isn't magic. If you're doing something special it isn't much of an inconvenience to add an explicit
app/define.rb. IMO being explicit is better than the framework making assumptions and then causing problems.
View templates will more or less function as they do now, in that it's a separate step from loading the backend logic. The biggest thing to point out here is the inclusion of
assets as part of presentation. More on this soon
Okay, I saved my favorite for last. Features include all the parts to make a particular part of your app work, including routes, models, views, and assets. For example, you could implement authentication as a self-contained feature rather than alongside the other code in your app.
Why? Because it promotes a more reusable architecture:
When architected as a feature from the start, all the code that serves a common purpose becomes much easier to reuse across projects. In fact, plugins will be built on top of the same architecture! This means that to reuse code between projects you would:
- move the contents of the feature directory into a plugin
- include the plugin in the two apps
Behind the scenes, it's likely that we'll implement each feature as a separate app mounted within the same process. Doing this will help enforce complete isolation between features, which is sort of a requirement if you want to later abstract it for reuse.
I'm out of things to say here. Weigh in with your thoughts!