Where's Your Business Logic?
collectiveidea.com
collectiveidea.com
EDIT: I have to give credit to the author to bring this in to the Rails apps, he's right that Rails encourages to think in terms of controllers,models and helpers.
Well, the use case for wine today is much the same as it was in ancient Rome.
Someone needs to curate all of the pitfalls of rapid dynamic development environments into one book. This would be of tremendous benefit to developers farsighted enough to learn from history.
When models get too fat, I usually create modules that break up the bulk of the model into smaller chunks. Meaning, for example, if it has lots of validations, then maybe I'll move those validations over to a module and then extend/include the module back into the model. I haven't needed to use these modules in any other class, but less code in one place is usually easier to read than more code. If the language you're using isn't Ruby, then a module is basically a means of doing multi-inheritance.
Note though -- I didn't read the article
you develop libraries for your business logic and try to make these reusable (or may be even opensourceable on CPAN for other developers to use). These libraries will include their own test, which obviously not require you to fire your main web app and need to be tested once - when installing it on local machine.
What do not fit well into standalone libraries, goes into model (aka fat models). Again, models developed as standalone piece which could be used from command oneliners, web frontend, anything else. Tests for these often are part of web application, but testing of models should not require firing web app itself.
and last piece - controllers and views. these are integral part of web app therefore these require firing web app code to test. but controller code is very thin since it just prepare and route calls into model. views are usually just an adapter, often default scaffolded, for existing templating module on CPAN.
I bet same principle can be applied to Rails framework, but it is about community around framework which encourage you to do things in a certain way.
As it is, it's just the sort of thing OO programmers seem to create because they find nouns comforting.
This is a damn shame. Why do I say so? Because the exact same thing happened years ago in Smalltalk projects. It's easy to start and iterate quickly in a dynamic OO language and the technical debt sneaks up on you very quietly. The next thing you know, there's a quagmire of convoluted and deeply nested conditional logic.
If it was your business to curate lots of painted canvases, then you'd have an orderly and logical filing (or search) system for keeping track of those. If it's your business to curate lots of neat functionality embodied as pieces of code, then you need an orderly and logical system of keeping track of those. It's amazing how many large projects devolve into a big pile of stuff in a class for every screen.
"Enablement" or "security" or whatever you call the framework that lets particular users do particular things at particular times was one of the big wins for Smalltalk projects.
If someone asks you why user X can't do Y on screen Z, and the only way you can know this is for someone to just happen to remember or to painstakingly reverse engineer code, then you have a kind of technical debt.
Beware if your system just consists of putting in a breakpoint then reading code. There is no clear demarcation separating that from the quagmire. (The solution is to have some kind of consistent idiom/framework/something that people can learn to parse, and a way of reorganizing recurring ideas so they can be reused.)
if user && user.password == passwordInfact, the whole persistence mechanism is rather mystifying - an in memory store? What if I accidentally the power?
Isn't this a bit immaterial to the post at hand anyway?
1) your reputation in the community. I for one have never heard of you, so that leaves
2) code quality of the examples that you posted. a reader could infer that this may be good advice based on the fact that you appear to generate good code.
In this case your code is clearly not very well thought out, so why would the reader put trust in your unsubstantiated opinions?
In case you weren't aware, samples that don't require a ton of context are a particularly hard problem for informational posts like this. If you have feedback on the ideas I presented I'd be glad to hear them but I still fail to see how nit-picking an obviously early in-progress application proves anything.
I, too, keep finding myself in utterly painful Rails code. Now, if I may use your metaphor: Most of it is due to the blind leading the blind, per se. Programming novices discover some new rails thing, ruby thing ("method_missing" is the worst offender), or even a new programming pattern such as Command, and think it's the most incredible thing they've ever experienced, so they write a blog post about it. Other programming novices read the blog post and then go off on a rampage, overusing that concept and writing all the shitty rails code that I am currently maintaining.
There you have the ruby community in a nutshell.
action.run(params[:login], params[:password])
it is clear that the password is stored in plain text.At that level your tests should be executing business test cases. If a functional test fails there is either a corresponding unit test failure or the failure of the interaction between the methods rolled up into the business logic (functional test).
Functional testing is related, but it's not really the point of the article. In the context of the article, functional testing is actually one logical step above his Interactor—the functional test would end up effectively testing the interactor code (which includes all the model, etc code) plus the controller code to make sure the session is properly set (i.e. now that I'm logged in, was I properly redirected?). The latter is outside the context of the "business logic" of logging the user in.
The point of the article is in organizing the business logic of use cases into their own objects—"business logic" being defined, presumably, as anything non-web and non-persistence related. This is done in order to avoid the spaghetti that real world "thick model" applications tend to accrue; or similarly the spaghetti that some developers leave in controllers.
There have been a spate of articles on this topic in recent years. Service objects, interactors, DCI, etc, etc. One or more of them is probably good advice for large projects. :)
The article sucks pretty badly to be honest but the foundations are solid.
A much better solution is to use the command pattern over a rigid domain model. The rigid domain model encapsulates your business domain and logic and your commands describe different ways to mutate the domain.
This could be classified as CQS or if you use a bus to deliver your commands CQRS.
Unfortunately, and I'll probably get flamed for it, by rails is a stinking turd when it comes to architecture. I've never seen anything which isn't trivial CRUD done without causing uber spaghetti. Also to do proper domain modelling, you need a more powerful ORM such as sqlalchemy or hibernate.
It's easy to get a lot of followers by creating a framework that lets a new user create something small very quickly. Keeping it well organized as time goes on is much harder. It has been this way for decades, and still people haven't learned.
There's a huge problem of how to teach people good, responsible software development, and this article is a part of my attempt to help educate people towards even knowing about better software practices. People aren't going to just suddenly get it, they have to learn from somewhere.
Two awesome places to learn shit:
http://martinfowler.com/bliki/
Both of those are available as books (EIP + PoEAA). Buy them, read them, weep.
Yes they are C# and Java but that's where most of the formalisms were developed (for a reason!).
A large portion of any industry ignores established best practices and makes a mess every generation.
Yes, and many of them described in books in particular languages. Not every language community that could have benefitted had the right book written using their language.
Like I said, a recurring condition and an opportunity.
Much as SICP is applicable to a lot of languages that aren't scheme.
Although I question demonstrating the principle with a login given that those tokens are usually application specific and little to do with business rules.
As for the login token, I feel you may be defining "business rules" differently than I am. I'm using "business rules" as "the rules in which the application functions", and one of the rules is that you need an authenticated user to do things. The term is an effort to use a word or phrase that intentionally leaves out the framework you're using, but yes it can get confusing depending on what definition you're use to using. The other phrase, "use case" can at times be too limiting, but I don't know of any better term for what I'm talking about.