[HN Gopher] Brut: A New Web Framework for Ruby
___________________________________________________________________
Brut: A New Web Framework for Ruby
Author : onnnon
Score : 88 points
Date : 2025-07-08 18:03 UTC (4 hours ago)
(HTM) web link (naildrivin5.com)
(TXT) w3m dump (naildrivin5.com)
| freedomben wrote:
| Neat, this looks like it might be a good middle ground between
| Sinatra (which I adore) on the barebones/low-level end and Rails
| (which I also adore for apps that need it, but simple apps really
| don't).
|
| Looking forward to trying it out!
| duck wrote:
| Another option is https://roda.jeremyevans.net/, which I've
| found is the sweet spot in smaller projects, but can still
| scale up. The plugin system works really well to extend and the
| routing tree is really easy to work with.
| sarchertech wrote:
| >What about monads or algebraic data types or currying or maybe
| having everything be a Proc because call?! You don't have to
| understand any part of that question. But if you want your
| business logic to use functors, go for it. We won't stop you.
|
| I love this! It sounds exactly what I'd want to use for a side
| project or a project with a limited number of reasonable, senior
| coworkers.
| heeton wrote:
| Tried to login to the example site, unfortunately hit an error
| immediately after auth'ing with github.
| davetron5000 wrote:
| Author here - the example doesn't allow logins now to avoid
| abuse. I wasn't 100% sure I'd make it public and just decided
| today to do it, so it's not yet ready for just anyone to login.
|
| You can run the site locally, or view pages on the site by
| going to https://brutrb.com/adrs.html and clicking those links.
| caseyohara wrote:
| > I know, we can vibe away all the boilerplate required for Rails
| apps. But how much fun is that? How much do you enjoy setting up
| RSpec, again, in your new Rails app? How tired are you of
| changing the "front end solution" every few years? And aren't you
| just tired of debating where your business logic goes or if it's
| OK to use HTTP DELETE (tunneled over a _method param in a POST)
| to archive a widget?
|
| For your personal hobby project, go nuts. Break all the rules and
| cowboy all your own conventions.
|
| But for business applications, the conventions Rails enforces at
| least make codebases somewhat familiar if you've seen a Rails
| codebase before.
|
| At a certain codebase size, boilerplate is almost unavoidable.
| Unpleasant, but necessary. Personally, I'd rather have some
| conventions, rules, and guardrails for where the boilerplate
| lives rather than trying to navigate your homegrown pile of code.
| Good luck maintaining that spaghetti when you've got multiple
| developers.
|
| It's not clear how this new web framework avoids boilerplate
| anyway, so I don't see how this is an improvement over Rails.
| Presumably you'll still need to set up lots of stuff yourself,
| like RSpec. If the framework sets all of that stuff up for you in
| a conventional way, then you're just back to square one as soon
| as you need to fight against the framework's conventions.
| davetron5000 wrote:
| Author here. The framework does require setting stuff up. RSpec
| is not one of those things. It's the testing library you will
| use if you use this framework. I didn't create a lot of
| flexibility in the framework. For example, if you don't like
| RSpec, you will not like this framework :)
|
| You may want to examine the docs more closely. There are plenty
| of conventions and very few that can be circumvented.
|
| But day one of a new framework is not going to compete with
| Rails. Sorry!
| stouset wrote:
| To be honest, I love this framework (so far from what I've
| seen) but I do hate the choice of RSpec. I say this as
| someone who used RSpec for like a decade after it was first
| released. I "get" it. I have contributed code to it.
|
| Minitest (which is bundled with Ruby these days) is Good
| Enough(tm). It doesn't require you to learn a new DSL.
| Everything is just Plain Old Ruby. The use of RSpec these
| days--IMO--is just cargo-culting forward what _was_ the right
| decision from 10+ years ago. Having an pseudo-English style
| interface for testing isn 't worth having the additional
| dependencies nor the mental overhead of needing to know how
| the RSpec syntax is actually mapped into Ruby concepts.
|
| I'm not asking you to change it, you're welcome to have a
| different opinion than mine. But I am curious if you have
| strong reasons for requiring it. Particularly because
| MiniTest seems to be well-aligned with the rest of your
| design philosophies, _unlike_ RSpec.
| davetron5000 wrote:
| I thought hard about this decision. Every time I use
| MiniTest, I end up wanting a bit more that RSpec has and
| then switching to it. I also have been surprised over the
| years that the `expect(x).to eq(y)` seems to be relatively
| intuitive to people, despite the fact that it doesn't seem
| like it ought to be.
| stouset wrote:
| Do you mind elaborating on what more you end up wishing
| you had?
|
| Most of the additional features RSpec adds seem
| worthwhile but just end up being more
| complicated/confusing in the end, in my experience.
| Shared contexts/examples, for example. Others like let
| blocks should... just be methods.
|
| I will say the change in... I think it was RSpec 3(?) to
| the expect(x) syntax was a hugely positive change,
| particularly in not having to monkeypatch the world.
| davetron5000 wrote:
| The biggest thing is the mocking system. MiniTest's feels
| so difficult to use.
|
| I also like creating custom matchers vs. creating my own
| assert_* methods.
|
| I would agree that many features of RSpec are, honestly,
| bad: shared examples, shared contexts, etc. Excessive use
| of let! and let, plus the predicate matchers are all just
| really confusing to me.
|
| I actually thought about patching the RSpec gem to remove
| the features I didn't like :) Might still consider it heh
| stouset wrote:
| The mocking thing actually touches on another point of
| frustration for me. I think the design of Rails ends up
| causing people to reach for mocking way too often in
| order to test things. At a glance I _think_ Brut should
| avoid a lot of this by having things just be plain old
| Ruby objects.
|
| I have dealt with countless Rails projects where testing
| things conventionally was difficult or impossible so
| mocks/stubs had to be used everywhere (controllers are
| the worst offenders here). When you start digging in to
| what's actually being tested, you find that the tests
| express little more than "this method is written the way
| it's currently written" rather than actually testing
| _behavior_.
|
| Good tests should do three important things: catch bugs
| early in development, prevent regressions, and allow
| refactoring. Overly-mocked tests not only end up doing
| none of these but often actively work against these
| goals. They can't catch bugs because they reaffirm the
| current implementation rather than testing behavior. They
| can't catch regressions because any change to the code
| necessitates a change to the test. And they actively
| inhibit refactoring for both of those reasons.
|
| All that is to say that maybe having a less-convenient
| mocking system is maybe a good thing :)
|
| Also, since you're here, I want to say it also looks like
| your design encourages avoiding one of my other huge
| issues with Rails. I _hate_ that ActiveRecord conflates
| the ORM layer with domain logic. This causes an
| antipattern where consumers of records (usually
| controller methods) pierce all the way down into the
| database layer by using AR methods and attributes
| directly. While convenient, this makes doing database-
| layer changes excruciating since your table layout is
| implicitly depended upon by pieces everywhere throughout
| the stack.
|
| Better is to do what it looks like you suggest here:
| there should be an ORM layer that _just_ exposes the
| database structure, and then you should layer domain
| objects on top of that which expose higher-level methods
| for interacting with persisted objects. If you change the
| database, you only need to change the mid-level layer.
| None of its consumers need to care that the underlying
| table layout changed.
|
| From what I can tell so far I am _very_ excited about
| Brut.
| davetron5000 wrote:
| Yeah, that makes sense. Where I end up wanting mocks is
| when this happens:
|
| 1 - build first version of feature, all core logic in a
| class I can test conventionally 2 - logic gets complex,
| test gets complex 3 - Eventually, I need to create some
| layering, where the class from step 1 now delegates to
| other classes. The initial test is more like an
| integration test and gets harder to keep up
|
| At this point, there is a camp that says I should be
| using dependency injection and inject null objects for
| the dependencies. I get that idea. I am in the other camp
| that does not want to make custom objects just to satisfy
| a test. A mocking system can do that for me. So that's
| what I would do - mock the dependencies. The "real"
| versions would be tested conventionally.
|
| I definitely do NOT just start with mocking imaginary
| internals though - I guess that's a whole other camp :)
| dbalatero wrote:
| Reading test failure output is much more readable and
| usable under RSpec vs. Minitest, to my eye.
| cosmojg wrote:
| Oh man, Brut's HIPPOCRATIC LICENSE[1] is interesting! Just
| excerpting bits of Section 3.1 and Section 3.2 for example:
| * 3.1. The Licensee SHALL NOT, whether directly or indirectly,
| through agents or assigns:
|
| [...] * 3.1.12. Taliban: Be an individual or
| entity that: * 3.1.12.1. engages in any
| commercial transactions with the Taliban; or
| * 3.1.12.2. is a representative, agent, affiliate, successor,
| attorney, or assign of the Taliban; *
| 3.1.13. Myanmar: Be an individual or entity that:
| * 3.1.13.1. engages in any commercial transactions with the
| Myanmar/Burmese military junta; or *
| 3.1.13.2. is a representative, agent, affiliate, successor,
| attorney, or assign of the Myanmar/Burmese
| government; * 3.1.14. Xinjiang Uygur Autonomous
| Region: Be an individual or entity, or a
| representative, agent, affiliate, successor, attorney, or assign
| of any individual or entity, that does business in,
| purchases goods from, or otherwise benefits from goods
| produced in the Xinjiang Uygur Autonomous Region of
| China;
|
| [...] * 3.2. The Licensee SHALL: *
| 3.2.1. Provide equal pay for equal work where the performance of
| such work requires equal skill, effort, and
| responsibility, and which are performed under similar
| working conditions, except where such payment is made
| pursuant to: * 3.2.1.1. A seniority system;
| * 3.2.1.2. A merit system; * 3.2.1.3. A system
| which measures earnings by quantity or quality of
| production; or * 3.2.1.4. A differential based
| on any other factor other than sex, gender, sexual
| orientation, race, ethnicity, nationality, religion, caste, age,
| medical disability or impairment, and/or any other like
| circumstances (See 29 U.S.C.A. SS 206(d)(1); Article
| 23, United Nations Universal Declaration of Human
| Rights; Article 7, International Covenant on Economic,
| Social and Cultural Rights; Article 26, International Covenant
| on Civil and Political Rights); and * 3.2.2. Allow
| for reasonable limitation of working hours and periodic
| holidays with pay (See Article 24, United Nations Universal
| Declaration of Human Rights; Article 7, International
| Covenant on Economic, Social and Cultural Rights).
|
| [1] https://firstdonoharm.dev/version/3/0/cl-eco-media-my-tal-
| xu...
| wavemode wrote:
| All lovely ideals, but sadly means the project is not actually
| open source (by the official definition). And not compatible
| with the GPL and similar copyleft.
| mrsilencedogood wrote:
| People who try to enforce this stuff via license fundamentally
| misunderstand the nature of copyright law.
|
| Do you plan to sue people to enforce your license? Do you think
| people who are committing war crimes / crimes against humanity
| are going to not violate your license alongside all their other
| crimes?
|
| The only thing this license accomplishes is ensuring no even
| semi-serious business will touch this with a 10' pole because
| it's a completely bespoke license with no prior understanding
| by their legal counsel. But you can already basically do that
| via the AGPL, except that some companies who are well-meaning
| may actually still use it.
| davetron5000 wrote:
| I didn't come up with the license. You can read about it
| here: https://firstdonoharm.dev/
|
| I didn't want the code to be All Rights Reserved, so I chose
| the best license I could find that communicates my desires -
| I assume that's what most people do when choosing a license?
|
| I'm OK if a "semi serious business" don't want to use my
| software.
| dmix wrote:
| Usually a signal of a personal/hobby project not to be taken
| seriously.
| rorylaitila wrote:
| I like the emphasis on forms and pages. That's the approach I
| take in my apps. Forms and Links drive all interaction. Any
| JavaScript enhancements merely click an existing form (even if
| it's hidden). You can always inspect the HTML and know exactly
| the route that will handle the interaction. I think controllers
| are overused. It's really forms, models (backend) and views
| (Pages). A lot of the validation and ceremony of controllers can
| be handled more elegantly by the framework.
| MortyWaves wrote:
| Is there a reason you literally simulate a click event on the
| form instead of calling submit() on it?
| Mystery-Machine wrote:
| `requestSubmit()`*
|
| https://developer.mozilla.org/en-
| US/docs/Web/API/HTMLFormEle...
| rorylaitila wrote:
| Yeah, it's escaping me at the moment all of the reasons, but
| calling .submit() on a form element doesn't exactly have all
| of the behaviors as calling .click() on a button element in a
| form, particularly multiple buttons in a form.
| hapidjus wrote:
| Are you perhaps using the button name/value for something?
| Havent tested but i suspect that submit() does not pass
| that right?
| rorylaitila wrote:
| Yep that's one reason. I make heavy use of that.
| gavmor wrote:
| > Is this the index action of the widgets resource or the show
| action of the widget-list resource? is a question you will never
| have to ask yourself or your team. The widgets page is called
| WidgetsPage and available at /widgets.
|
| Hm, uh, seems like now we will be forever asking ourselves this
| question about /widgets.
|
| That being said, it looks good! Might get me back into ruby if I
| can come up with a project for it.
| hamzakc wrote:
| I see it is currently based on Sinatra. Just wondering if you
| have considered looking into Roda?
| davetron5000 wrote:
| (author here) It only uses Sinatra because I happened to know
| it and needed to bootstrap the low-level stuff. I don't know if
| it needs to be based on Sinatra in the long term - it should
| probably just use Rack.
___________________________________________________________________
(page generated 2025-07-08 23:00 UTC)