Remember: MVC for the Web, may not be MVC™.
I just recently gave two talks at the first Japan Perl Association, and one of the things I didn't focus on was design of your Catalyst application. I opted to not talk about this, because I feel it to be a subject beaten to death. In hindsight, I guess it isn't as a lot of people don't take the initiative to search through mailing list archives, and there needs to be some more public discussion on the matter (outside of mailing lists).
First, please try to forget the concept of MVC if you aren't already familiar with it. Without a lot of thought, you're possibly going to go down the wrong path. Instead, you need to think about what things are actually doing. In a way, this is a role (not in the Moose sense).
The way I see it MVC is better extrapolated as:
- User Facing
- User Input
- User Output
- Visible Output (Template Rendering)
- Invisible/Async Output (Emails, Long running jobs)
- Business Facing
- Business API Layer
- Backend Implementation
There is no longer any compelling reason to use the Business side of things. It seems a superfluous add-on without an added benefit. The reason for it isn't obvious for the simple cases, and this is one fo the reasons why I think other frameworks are met with more success. They don't use the nomenclature of a non-intuitive system, but that's just naming.
The primary reason for having your business aspect is that it shouldn't be specific to any application.
This is all great, but in practice sometimes this gets very difficult to mentally categorize. For example, to create a user account, it is tied to an application. Sort of. There are application specific rules for how an account is created, and validated. In many instances, you have to submit an email address, and then click on a verification link.
If the backend tools allow for creation of a user, it is a different path; possibly, this case is even a different application.
This is why it is important to put your business rules on what constitutes a valid user in your backend business model, to take with you between applications and use cases. Your transitory state on these objects (an unverified user) can be tracked in the controller, assuming your business layer has a simple API into the interface.
This means that code for upgrading a user to a verified user should be as simple as:
$user->verify_and_upgrade( $code );
If that throws an exception, such as a bad code, then the application needs to handle that. This is the controllers job. This means that the controller just applies its application specific rules, but all the validation and actual upgrading of the object happens behind the scenes, exposed by the very friendly "verify_and_upgrade" method attached to your user object.
To create the degraded user, there should be a different method for that. Rather than code in your controller creating a user and setting some validation flag to false, there should be a simple API method (in the Catalyst & DBIC world, this would be):
As you can see, this also keeps the controller code very simple and easy to follow.my $user = $c->model('Schema::User')->create_unverified( $data );
my $code_to_email = $user->verification_code;
The main principle here, which I think is paramount to delivering quality applications is simply:
Focus on the API
If you focus on your business layer having a very good API to do all functions, no matter how trivial, your controller and application specific has no choice but to be thinly written.Rather than try to adhere to good programming practices through will power, focus on just building an API first. Then all that other stuff just happens, for free.
Comments