[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)