MVC in smaller web applications
by Matthias Willerich on June 7 2005, 15:57
The real world
Web development is, in many cases, a process where time is a crucial factor. As coding is usually the last step in the process, all things come together and prior mistakes are revealed.
"Build this so it looks the same in all browsers, works better than the IA was ever planned and can fly." Or so we hear.
With a limited amount of time, developers are often tempted to fall for quick fixes and, not only due to last-minute changes, find themselves in a huge ball of code at the end of the project.
"What does that matter, if the site is working nicely, nobody complains and it's nodded off by the client?" I hear you ask.
This attitude is something I've encountered many times, and it usually results in a second-phase disaster, be it an extension of the site, a new face or a server change.
Theory
This is where the MVC comes to the rescue. It's basically an attempt to structure a web application into three components:
- Model is generally understood as the data-administration component. In the majority of website projects, this is the data retention in a relational database system, but it could also include other persistent business objects, Enterprise Java Beans for example. Model is passive and does not trigger any actions. Data is requested independently of their representation (view); Model does not know anything about the data presentation. Model can work with one (1:1-relation) or several Views and Controllers (1:n-relation).
- View describes the visual representation of the Model. In the case of many dynamic websites, you would imagine one or two Views on the same Model: in the case of this article, one would be the public View - the way you see this article now, and another one would be where I create and edit. Of course, there are many more possibilities: different user levels, each with a distinctive set of permissions; different representations of the same website for regular users; high contrast for easier reading; a View without head and navigation for printing, and so on.
- The Controller has the entire application logic implemented. It is an active component. The application receives inquiries, passes it on to the responsible subcomponents in the system and possibly sends answers back to the user. The Controller carries out various manipulations of the Model for the execution of user actions.
So far, so good. Now that the theory is clear, we can look at how it's used in the web development process. Do I actually need it? This seems to be a very sensitive subject. While researching, I've found several approaches, most are somewhere in the triangle of determined, angry and ignorant. I'd like to point out the most obvious reasons to use it, hopefully not stepping on any toes:
- Match a thought pattern: Putting your code into a programming pattern is difficult when you try doing it while coding, but the idea is to structure the code first, in your head, on a piece of paper or, for large scale projects, with CASE-tools. With the structure documented, your code becomes more manageable, and the number of people that want to see you roast in hell (possibly you yourself in 1 or 2 years time) is decreasing. Every developer that understands MVC will find their way through your stuff quickly, you will both work on the same wavelength, because you both follow the same pattern, in code and thought.
- Reusability. This goes for any kind of modularisation, but it's an argument not to ignore: Once you have thought through and set up your model, you can reuse it many times with no or only minimal changes.
- Extendibility: With a strict modularisation, you have a defined field of work when it comes to changes of face, functionality or data storage. Depending on your web applications needs and real-world situation, you can decide which parts need upgrading.
Practice
I discovered that Jakarta Struts is a really good Java-based solution and, more recently, PHP Architect magazine offered a free download of their may 2003 issue, containing a nice introductory article with a solution based on Smarty templates. A very extensive solution incorporating the three-tier architecture (no, they're not the same) also PHP-based, can be found on Tony Marston's website along with tons of information on different design patterns.
I could stop here and leave you with one of the examples, but let me say this: I believe that the size of the project and the probability of exchanging or updating certain components should play as important a role as the reusability of the code.
Over time, Pascal and I have come up with a loose framework of PHP classes, which have saved enormous amounts of time when building medium-scale projects, thanks to their reusable subcomponents.
The Views are set up with CSS and (X)HTML, which is generated with XSL stylesheets (see Pascal's article with his five-layer structure for more detail).
In the backend PHP, classes are structured by their functionality. A db-class manages all lower-level database work: replace it or change the configuration for a database change. This class represents the Model. Your server was hacked and you need to refer to a backup db-server? It's done in 10 seconds.
A base class, meanwhile, carries all of the helper functions that are used across most projects, for things like string and date operations. It is extended by a page class, which is the first class to adapt to the project. Here, the site structure is taken care of (usually dug out of the database in one way or another, as a tree or a flat page model), functions for breadcrumbs and navigation grab the data and return the XML, and global site elements find their data. But not only that: All what's generally called business logic, calculations, workflows and so forth, can be found here as well. The class can then be extended for special purpose pages, to keep it nice and tidy. I group them as Controller. They receive all the requests, they instantiate the Model (the db class) to deliver XML, to be transformed by the View, by XSL.
But this does not strictly fit into the MVC pattern: In a clean approach, no SQL would be found in the page class. A common technique here is to set up a class for each table that contains all queries. This way, you know where to find your SQL and what classes to touch should your db-server change. Alternatively, you can extend the db-class and top it up with higher level of functions that build the SQL for you. On the upside, you only have one file to change (as opposed to one per table); on the downside, solutions tend to be developed in a complicated way, thereby making it difficult for the next developer to get their head around it. Furthermore, it may be too specific to one site and, therefore, not very portable.
With these classes set up as a starter package, you'll have incredibly quick results - and working as a frontend/backend team is a joy. Simply set up an abstract XML file with all the data you need, and each of you can work towards it from both sides: one on the xsl/html/css side, the other in the php/db department.
On several occasions, I left out the table classes as a set-up for medium-sized projects.
As an alternative, I either stuck to relational databases (usually sufficient) and coded in pure SQL-92 - although this tends to be awkward and I'm not sure if all common databases follow this standard entirely - or I made sure the db-application stayed the same throughout the lifetime of the site.
As with most things in modern digital life, sites are ever-changing, but the code hardly ever survives three years. Your budget, timeframe and the purpose of the site will determine to what extent you want to follow MVC. But it's always worth considering.
Comments
A common technique here is to set up a class for each table that contains all queries.
This actually doesn’t sound like a very good idea to me, since I work with joint queries and subselects.
But then subselects are server-specific … Ohh dear …
I gotta think about this more thoroughly!
by Pascal Opitz on June 2 2005, 18:42 #
I would disagree with you, telling that the main benefit of separation of SQL from the page presentation is an easiness of finding the proper statement in a future. While it’s also true, the main aims of design patterns (and we are talking about MVC, Facade and some other patterns) are re-usability and isolation. You have uncovered the re-usability part a bit, but isolation plays a great role too (and it’s not about SQL only).
When you have a team you can define the classes, their roles and goals. After that spend a while to create stubs and spread the job across the team. Everybody will be building its own part: SQL expert – SQL, designers – presentation, the rest – logic programming. When finished, tested and re-joined together the parts form the application. Because of clear separation no one waits for others and knows clearly from A to Z what his own part should do. It’s just one of possible use-cases.
I have more to say, but I would better stop here as it’s going to be overloaded. :) Nice article! Keep up doing great job!
by Aleksey Gureev on June 3 2005, 08:01 #
I do agree with you. Thanks for pointing out a nice example for isolation. I know it’s not only about sql, and I think you summed it up very good.
I guess it slipped my mind, as I wanted to write this up for smaller projects, which hardly ever have more than 2 people developing it. But you’re right nevertheless. Feel free to add more, or drop me a line
by Matthias on June 3 2005, 11:43 #
by berlinandree on June 3 2005, 13:28 #
The other good thing is that you always can start from writing tests for your future modules to set in stone what EXACTLY they should do (it’s called TDD – Test-Driven Development). You write scenario after scenario (generally using PHPUnit or other XYZUnit, depending on technology you are using). These scenarios should reflect the real-life problems the module is intended to solve. In example with Persistence Layer, it could be “Reading list of posts”, “Adding post”, “Adding Comment”... you got the idea. While writing the tests you add methods to your classes which help to solve your problems, group them, rename them, recognizing patterns and following them (over and over again). By the end of this process you will have the stub for your module, which is having all methods and clearly designed to solve your TODAY’S problems (nothing more, nothing less). After that you just spend some time to put in the implementation and pass all the scenarios you have set in tests. It’s all about modularity, layering and isolation.
As for me, I always try to work “from the tests” because if not, then I’m always thinking about the module from inside and doing too much assumptions, adding flexibility which is not likely to be necessary and etc. It all takes time.
Save your time, do it right. :) Some good reading on the subject could be anything about TDD, general articles by Martin Fowler (“Is Design Dead?”, for example) and of course the design patterns material. They aren’t the goal and you shouldn’t aim on using them all the time; they just help you to concentrate on real tasks instead of re-inventing the wheel.
Hope that it’s interesting and even inspiring to someone. :)
by Aleksey Gureev on June 3 2005, 14:50 #
I looked into unit-testing before, but in small/medium-ish companies, with small/medium projects, probably focussed on different things than development, it is hard to get through. But I won’t stop, obviously, and it’s good to have people around with the same opinions.
Cheers,
Matthias
by Matthias on June 3 2005, 18:16 #
Anyway, I’m happy that it was useful writing!
by Aleksey Gureev on June 3 2005, 18:26 #
here’s the article Aleksey was refering to:
is design dead?
I printed it out and will have a read.
cheers.
by Matthias on June 3 2005, 18:50 #
Watch the 10 minute setup video to get the basic idea.
by Scott Becker on June 3 2005, 21:44 #
by Mike Stenhouse on June 4 2005, 16:49 #
by Pascal Opitz on June 4 2005, 17:23 #
Pascal, of course, the evolution should take place. In most cases, you will add something new, but sometimes you will update existing functionality and very rarely remove.
When you add you create the tests suite beforehand again and try to pass it in minimum number of strokes.
When you change, it’s always best if you have a set of short examples of what the functionality does now (your current set of tests as a basis). Basing on this, you update the tests to reflect your required changes. It helps you, right as in the first time, to create a meaningful arch. and experiment with interfaces with stuff beforehand. After that you simply change what you need and you are done.
When you remove something you just don’t need the tests for that scenario any more. So, kill them.
The tests help you and your team to feel confidence about the application. When you were working a week on one module and then gave it to the other developer on your team you can be absolutely sure that he hasn’t broken any bit of code with his changes because your tests, reflecting your requirements for module, still pass. Being confident is a great feeling: you finish your working day in a great mood and, what’s also important, you can give your application to the client in a middle of the night, knowing that every piece of it is tested and proved to work.
From the first glance, it looks like you are wasting the valuable time for writing useless tests which aren’t bringing the value to your clients. It’s not true. (a) The bugs you find are absolutely different from the bugs your clients will find. At least, you will start to ask for excuses, feel sorry and etc. (b) The time you spend on writing tests is nothing against the time you spend on finding the ways to reproduce bugs, track them, fix them, propagate updates and etc. (c) your reputation goes lower and lower with growth of index in your bug tracker. Having less defects is much better than having an excellent skills in bug-fixing.
So, it’s up to you to make test or no. Just remember two rules (my own experience):
Do Not Test Everything—test only what can break or you will be really wasting time. Make the tests to be a part of your process and position it as sort of a game or invent something to make them look more natural.
If Your Tests Never Fail, They Test Nothing—at least make some adjustments to code (if you are writing tests after implementation) to prove to yourself that the tests will fail if anything will go wrong. And… never worry about the failing tests. If test fails, it means that you have caught the bug, which was going to slip into production version if you had no that test. :)
Sorry, if I sounded like having PhD in Testing. It was just my bit of experience in this are and should be treated this way only.
by Aleksey Gureev on June 6 2005, 09:31 #
Caching is super-easy in RoR and can be added to an entire controller with one line…
MVC is great!
by Jesse Andrews on June 16 2005, 05:33 #
And, if in your project the graphic designer is thinking about SQL you have problems…. hehe
by the way, Aleksey is pretty right about TEST as much as you need, but TEST hehe…
And… some interesting thing to ask is, do you have a PHP class with the queries of your system? I hope not… not exactly that! you can have many ideas on what to do with your queries and so on….
cheers
by Lucas Zingano on April 15 2006, 14:08 #
I have never succeeded to explain anything server side to a graphic designer, then again, I realised fairly quick that there’s no need. But there is a hell lot of chaotic developers out there, and MVC seems to be an easy entry point into patterns. The advantages of the modular approach are just too obvious.
I’m not sure I understand what you mean by your last paragraph. Do I have a class for sql, as in one, or as in one for every purpose?
I use a couple of classes that form the abstract use of what I’m going to build, like a list class, which I then extend with the purpose class that I need to build. This class will contain SQL.
Recently at the PHP conference UK Derek Rethans gave a nice introduction into EZ components, and I quite liked their DB class, it abstracts SQL really nicely; I might give it a try soon.
by Matthias on April 16 2006, 09:25 #
I used to use something like DB Class and it is a very interesting component that override the idea of keeping your SQL in plain string, which can be very dangerous to enable SQL Injection attacks.
I hope I made myself understood…
by Lucas Zingano on July 12 2006, 06:58 #
I used to do some dynamic websites with Java, mainly JSP and Servlets working together, and the one thing I really needed there more than in PHP is a mirrored development server. That takes the grievance off uploading a compiled class to the live server which then has a typo.
Using a class that abstracts the whole sql business… I’m not sure about it. Sure, it keeps everything in one place, but at the same time you’ll have all the work to abstract the whole of the SQL language; and that has to look at feel intuitive, too.
by Matthias on July 26 2006, 02:31 #