
Rails is half of your application - sickill
http://ku1ik.com/2014/03/13/rails-is-half-of-your-application.html
======
programminggeek
It's been over a year since Obvious Architecture came out and over a year
before that when Uncle Bob gave his talk on Ruby Midwest. People seem to just
now be catching on.

I've gone really deep down the rabbit hole on these kind of highly decoupled
design patterns in Obvious, clean architecture, functional programming, TDD
and all of that and I realize now that Ruby is not the optimal language for
this style of development and DHH and Rails' purpose is not the same purpose
of clean architecture.

I go back and think about the original build a blog in Rails demos, which are
great BTW, and I feel like Rails' strength is standing up an application quick
and getting stuff done. Yes it can do TDD and clean architecture and all of
that fun design stuff, but to be completely honest, it doesn't fit the
community or the language as much as it should.

Ruby gives you a lot of amazing tools, but there are a lot of things that make
clean architecture way nicer that you end up bolting on to Ruby. Stuff like
immutability, type checking, and strong interfaces are not the norm in
Rubyland. That is perfectly fine, but by the time you build all those tools,
it's hard not to look at a language like Scala or Kotlin and see a lot of
those things built in to the language along with a compiler and nice IDE
support.

I love Ruby and I use it every day. I live in a Rails app most of the day and
I've found ways to make to make the code beautiful, but fundamentally I don't
think the Ruby community will ever truly get behind clean architecture. It
really flies in the face of the reasons why most people use Ruby in the first
place.

~~~
clienthunter
I think what you say about Rails is true. Rails isn't a framework, it's a
lifestyle.

I also started to question whether Ruby's type system was just too loose for
serious work and was yearning for something as pleasant as Ruby but with at
least some type safety. Then yesterday I read this relatively old post
[https://www.ruby-forum.com/topic/217617](https://www.ruby-
forum.com/topic/217617) about adding static typing to Ruby. There's a lot of
recognisable names in the thread, but the posts from Eleanor McHugh nearer the
bottom really helped me understand the power and utility behind the apparent
simplicity.

~~~
programminggeek
I would love a compiled, statically typed Ruby, but I don't think the Ruby
world wants it. I think Ruby is a fine tool in its current state.

I think there is a need for a different language that makes clean architecture
natural, well accepted, normal thing. Ruby is great, but trying to change the
community and language doesn't seem to be the right approach.

~~~
infraruby
> I would love a compiled, statically typed Ruby

[http://infraruby.com/](http://infraruby.com/) is a compiled, statically typed
subset of Ruby, compatible with Ruby interpreters.

~~~
clienthunter
Is this actually type safe, or type safe up until you include an untyped gem
and the whole thing becomes indeterminate? Does the typing actually improve
performance over straight jRuby?

Can it handle method_missing and *_eval?

Also why is it closed source?

edit: sorry I didn't mean to sound aggressive. please interpret the stream of
questions as extreme curiosity.

~~~
infraruby
> Is this actually type safe

The type system is roughly the same as in Java, and, as in Java, there are
ways around the type system.

> or type safe up until you include an untyped gem and the whole thing becomes
> indeterminate?

The compiler requires type annotations; you can't include an untyped gem!
InfraRuby syntax is compatible with Ruby interpreters, so you can still use
your code while you write type annotations for it.

> Does the typing actually improve performance over straight jRuby?

Yes. The compiler is written in Ruby, and uses JRuby to bootstrap. The
performance of the compiled compiler compiling the compiler is about 7x JRuby.

> Can it handle method_missing and *_eval?

No. The subset of Ruby supported by InfraRuby excludes metaprogramming and
reflection.

> Also why is it closed source?

Because 1. give away your work 2. ??? 3. profit! is not compelling :-p

------
hcarvalhoalves
In my experience, projects written in frameworks like Rails an Django have a
tendency to end up with business logic sprinkled everywhere:

    
    
        Persistence + Business <-> Frontend + Business
    

You end up with business logic in ORM code, POST validation, Javascript form
validation...

You usually want:

    
    
        Persistence <-> Business <-> Frontend
    

That way you can extract a business API and be transparent whether it's making
SQL queries, talking to a webservice, a file, or something else.

Another mistake IMHO is going crazy on OO and having, e.g., an `Order` object
encapsulate everything like validation, persistence, reporting, serialization,
etc... You end up with an object that retains so much state that it's hard to
test. By coupling data and function you also end up in a corner trying to do
bulk operations efficiently, falling into an awful idiom of iterating objects
and calling a method on them, leading scalability issues with N*M queries, and
so on. The testable/scalable route is following a functional approach and
designing your business API from the start around functions that deal with
sets and take all the necessary state as a parameter, or data structure that
represents the current state.

~~~
mercurial
It's a general problem with poor programming practices. When you see people
subclassing controllers to modify behaviour, it's clear something went wrong.
On the other hand, splitting out your business logic (which should take clean
data structures) and putting your persistence system in its own layer, you get
a clean, decoupled system, which you may or may not reuse elsewhere, but that
is certainly easier to understand and test than when "good design" means
accessing the database in a controller or in a view.

Framework or no framework, you'll get the same design from programmers who
stare blankly when somebody says "separation of concerns".

------
fideloper
I find it really interesting and awesome that Rails and PHP are both (at the
same time) in the process of (re)discovering the architecture described in
Evan's DDD and Fowler's PEAA.

What's old is new again! Rails has existed long enough to have a need (and a
vocal chunk of the php community has matured enough) to think of apps
architecture with a longer term in mind.

I think devs are seeing frameworks as a tool to implement an application
instead of being the application itself (as originilly conceived before Rails
revolutionized RAD).

Great!

~~~
camus2
> I find it really interesting and awesome that Rails and PHP are both (at the
> same time) in the process of (re)discovering the architecture described in
> Evan's DDD and Fowler's PEAA.

uh? It has nothing to do with PHP or Rails. everything to do with mediocre
developers,you must be born yesterday. And you can even do that in JS...

------
clienthunter
Not sure I agree with the idea that `Rails == UI`. A lot of the time I'm
trying to fight Rails on this as decoupling HTML means refactoring HTML which
isn't fun.

I use Rails as a thing that controls boundaries, a glorified CGI really. It's
a router, input sanitizer, and general plumbing that spurts out JSON every now
and then. It's a mid-level wall in a fortress: server + OS deal with TCP,
Rails + Rack handle HTTP, Rails handles raw user input, proxy objects handle
Rails, the actual business logic handles proxy objects.

This is the only workflow that allows me and Rails to be long-term friends:

When a request comes in to the API (say, change password) the controller will
sanitize and confirm presence of the right params and collect things like the
current user. It'll then pass these off to a proxy object e.g.
`CustomerPasswordUpdater.update!(user, new_pass)` which will validate length,
entropy, etc and perform any necessary crypto. Then that data gets passed off
to another proxy object which abstracts over ActiveRecord e.g.
`UserPersister`. There's literally nothing inside the model itself. The core
`Customer` object is nothing but a decorated window on the relevant data
(accessed through unambiguous proxies e.g. `UserReader`, never directly
through the model).

This may seem a bit framework-inside-a-framework but the result of this
approach is that specific chunks of logic - _your_ logic, the stuff you write
on a whiteboard - is clearly identifiable in these small unambiguous classes.

The grand upshot is that I can plan my application on a piece of paper, write
all _my_ logic in plain old Ruby with plain old RSpec and plain old gems at
breakneck speed, and there's no stupidity like tests hitting the DB or 40
minute test runs in sight.

Once all that's done wiring it up to Rails takes a day or two. At any point I
could write a few new proxy objects and drop the whole thing in to
Sinatra&Sequel/ Sinatra&Neo4j/ Sinatra&PStore/ Whatever&Whatever. At no point
does the logic that defines and encapsulates the actual _business problem_
that needed solved need to be touched.

------
jaunkst
We use an interactor pattern with organizers to keep domain logic dry and
reusable. Skinny models and controllers.
[http://collectiveidea.com/blog/archives/2012/06/28/wheres-
yo...](http://collectiveidea.com/blog/archives/2012/06/28/wheres-your-
business-logic/)

------
jaunkst
Don't restrict yourself to MVC. It's a phenomenal start to any given project
but ultimately your going to have to do what real engineers do. Example, lets
say I'm building a game. The underlying framework is object oriented and
adheres to a type of MVC pattern to manage view states. We use a component
entity system to manage game entities and logic. The same goes with Web stacks
it's the framework, but not limited to the underlying pattern. Extend your
domain logic out from the MVC. It's not rails job to do everything for you. I
feel the developer is at fault more than rails. Buck up and break the pattern
it's not beyond reason.

------
pearjuice
Half? More like 1/5th or even less. Ruby is the real horse power.

~~~
sadfnjksdf
I know your point is that Ruby is where it's at, but do this:

In the top line of config/boot.rb above EVERYTHING else, put this:

    
    
        require 'tracer'
        Tracer.on
    

Now, start Rails. Wow that's a lot, huh? Stop again. Now try replacing those
two lines with:

    
    
        set_trace_func proc { |event, file, line, id, binding, classname|
          printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
        }
    

Start it again. Lot going on there...

~~~
pearjuice
Are you implying I even use that pile of turd?

