Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

A Concise Example of MVC

by TedYoung (Deacon)
on Feb 22, 2007 at 02:27 UTC ( [id://601474]=perlmeditation: print w/replies, xml ) Need Help??

In my node How to build a Search Engine. I mentioned that I was maintaining a large content management system. Now I am working on revamping its internal domain management system. I realized this would make a good example as to why to use MVC, and how to make it beneficial.

I am rewriting the portion of my CMS that is responsible for setting up new domains (and in some cases, removing them). During construction of a new domain, some of the domain management system's (DMS) responsibilities include: creating system users and groups, updating the file system, creating a database, generating a virtual host config from Apache, and other virtual host stuff.

So what does the DMS have to with Model-View-Controller architecture? I want to be able to create, modify, and destroy domains from both a website (an administration console) and from the command line. Why both? The website can be used by any admin, so I don't always have to be the one to do it. The command line gives me batch provisioning capabilities that would be too much work to implement on the web for the few times I would use it.

By designing things with the MVC paradigm in mind, I can create both the web-base and command-line versions without any duplication of code!

Let's quickly review the three components in an MVC stack:

  • Model: While often associated only with data, the model should encapsulate all of your business logic and validation. In this case, the model will be a library responsible for configuring the OS for a new virtual host.
  • Controller: Responsible for controlling access to the model; authentication, authorization, work flow, etc.
  • View: Responsible for generating output to the user. The web-base interface will generate HTML, while the command-line version will generate Text.

Model:

This will be the one component shared between both the web-based and command-line versions of our DMS. First, we will have a module that represents a Domain's configuration. This may be saved in a DB, or config files; that isn't important now.

package Domain; sub load { ... } sub getAddress { ... } #etc. 1

And we will have a module responsible for installing and removing domains (virtual hosts).

package DomainManager; sub install { my ($this, $domain) = @_; # create user # create files # create db # set up apache # etc return @results; } sub uninstall { my ($this, $domain) = @_; # remove user # remove files # remove db # remove apache config # etc return @results; } 1

View:

What is @results? We could just return a list of lines of text, but we may want to format the output differently based on if it is an error or not. Also, on the web we may want errors red, and non-errors green, while on the command line (where we might not have/want color) we may want "[ERROR] ..." versus [ OK ] ...".

So, we will use an object to represent each line. Both install and uninstall will return a list of these objects.

package DomainManagerOutput; sub new { ... } sub isError { ... } sub getText { ... } 1

Controller:

Now that we have all of our business logic (both the data representing a domain and a manager to install and uninstall domains) in a central set of modules, we can use them both from a web application (CGI, mod_perl, etc.), and a command-line script.

#!/usr/bin/perl -T use strict; use warnings; use Domain; use DomainManager; # Do authentication, authorization, etc. my $domain = Domain->load(...); my @results = DomainManager->install($domain); print "Content-type: text/html\n\n"; print "<html><body>"; for (@results) { if ($_->isError) { print "<div style='color: red'>" . $_->getText . "</div>"; } else { print "<div style='color: green'>" . $_->getText . "</div>"; } } print "</body></html>"; ----------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; use Domain; use DomainManager; # Parse command line, etc. my $domain = Domain->load(...); my @results = DomainManager->install($domain); for (@results) { if ($_->isError) { print "[ERROR]" . $_->getText . "\n"; } else { print "[ OK ]" . $_->getText . "\n"; } }

Now you can see why we didn't just return a list of text lines.

On a side note, we really should go a step further, and not put HTML inside our CGI script. That should be pulled out to a template file so it too can be reused (further adhering to the MVC paradigm). But, I want to keep the example concise.

Summary:

So, how often does one create both a command-line and a web-base interface to the same functionality? Maybe not too often. But there are many other reasons to use MVC. For instance, you application could be accessed, not only via a web browser, but from a cell phone or PDA, as a web service, or via a cron script. You never know where you application is going to go, so it is best to be prepared.

Also, good MVC design has other benefits, even when there is only one mode of access. These include a centralize system of styling all output (that could be maintained by a non-programmer website designer), centralization of common controller functionality (like authentication and authorization), and in general, better code reuse through proper abstraction.

On the other side of things, there is a point of diminishing returns. How well you adhere to MVC is something that you must decide on a per-project basis. For the simplest of sites, it may not be worth the extra time, to go all out. But even keeping the fundamental principles of MVC in mind, in even these simplest applications, can save time and minimize bugs, while maximizing extensibility.

Ted Young

($$<<$$=>$$<=>$$<=$$>>$$) always returns 1. :-)

Replies are listed 'Best First'.
Re: A Concise Example of MVC
by exussum0 (Vicar) on Feb 22, 2007 at 14:46 UTC
    You have some view IN your controller. Your view objects are to have complete control over how the view works. Your controller has view data in it. Your view objects contain that and the logic for dealing with the model. Edit: Heh, you got some V in your C! I know, back to my hole...

      Do you mean to say that he should have two separate views? One for web output and one for command line output? Then his control could be simplified even more.


      ___________
      Eric Hodges
        Correct. The trick here is, the controler and model should be fairly static if you were presenting the same data via XML, HTTP+SOAP, HTTP+HTML, CLI etc. Then either your controller pushes the data to the view you somehow get a handle of, or the view pulls from the controller (through to the model) the data to present.

        Same is true of the model. If your view and controller stay the same, your model should be fairly possible to replace without too much rigmarole

      Sometimes a bad example is worth more than a good one it seems. (I am aware that vagueness is its own reward.) True: Some V is in the C.
Re: A Concise Example of MVC
by jettero (Monsignor) on Feb 22, 2007 at 12:43 UTC

    I know very little about MVC except that it's the latest thing and it was made popular by RoR — and what I read in this article. How well does the concise example above fit into the Catalyst framework?

    I've been meaning to make myself learn that for some time now, but I'm just so darn productive in regular old CGI it's hard to make myself try it.

    -Paul

      MVC does not imply a certain technology or language. I use MVC even when building desktop applications. Personally, I think Java was one of the biggest promoters of it through EE, way before Ruby on Rails.

      I develop in CGI all of the time. The above example is in CGI. If you are good at CGI, go with it. But you can still enhance your skills by understanding the concepts of MVC.

      Frameworks such as Catalyst take the tedium out of setting up a new job. They can definitely help you be more productive, but are no requirement to proper MVC design.

      Ted Young

      ($$<<$$=>$$<=>$$<=$$>>$$) always returns 1. :-)
      I know very little about MVC except that it's the latest thing and it was made popular by RoR

      That'll be the latest thing that was first named in 1978 then.

      Sheesh... kids today :-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://601474]
Approved by graff
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (7)
As of 2024-04-25 11:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found