There will be no controllers. Purpose-built classes will support pages, forms, and components.
Accepted
CreatedContext
In an MVC context, a controller receives HTTP requests and dispatches to domain logic. While this is fine in theory, controllers end up being a magnet for a bunch of logic that can be hard to factor and manage. Given that Brut will organize apps by pages and forms, it makes sense to codify how those are handled more explicitly.
Concerns or Issues
When serving up a page, it's often necessary to assemble data from various sources to create the page's dynamic sections. When processing a form, there is often a need to coerce a hash of strings into something safe and useful. Lastly, organizing a complex page into potentially re-usable sections of markup can be challenging.
Decision
All pages will .html.erb with a specific instance of a page class as the binding. All forms will be defined by a specific form class, and all form processing will be handled by a specific handler class. For example, a page that lists widgets will be rendered by creating an instance of a WidgetsPage class. This class can expose any data needed to make the page work. A form to create a widget will be defined by the class NewWidgetForm. That form, when submitted, will be sent to the NewWidgetHandler for processing. Pages can be decomposed into components
that work the same way. The WidgetsPage may defer some of its rendering to a WidgetTagsComponent.
Options Considered, but Not Chosen
Controllers were rejected as being both too flexible and too inflexible. The rails way of controllers, ivars, and views is clever and ergonomic, but complex apps end up requiring stuff like presenters, view components, view models, and other abstractions. It seems easier to create a single abstraction for the code backing a dynamically-rendered view, and to also create abstractions for forms and form processing.
System Qualities or Desired Consequences
This should create consonance across the view layer. The /widgets page in the browser is the WidgetsPage component. The form action="/new_widget" form is defined by the NewWidgetForm and handled by the NewWidgetHandler. There will be a clear mapping from the browser to the code, without additional abstractions or indirection.
Downsides
There will be more code than the equivalent way of doing this in Rails. The code, however, will be more explicit, easier to test, and easier to follow. It can also be generated such that the characters a developer must type will be on-part with what they would do in a reasonably-sized Rails app.
Additional Rationale
Decades of MVC app development have shown that controllers aren't sufficient and that a more object-oriented approach might be metter.
Refinements
| Title | Status | Date |
|---|---|---|
| Phlex will be used for HTML templating | Accepted |