Sunday, February 3, 2008

Client-side MVC

I'm going to describe my view on the client-side development, today. Under client-side, instantly I mean a complex of html/css/javascript which represents the user's interface in the web applications.

In general there's nothing new, this's just a slightly different point of view on the stuffs, which I've worked out for myself and which helps me to implement more complex and controllable solutions.

What is MVC.
MVC is one of the most well known software-programming pattern, originally, as I know, described by GOF. This pattern describes a point of view on any programming application as on a system which contains three main parts Model, View and Controller. Which mean in general the application data, application look'n'feel, and application logic. And if you keep the parts separated and don't mix them, you're good boy(girl) and keeps the things safe.

If you had no idea what MVC is before reading the article, you'd better proceed to same wiki for more details before reading further.

Preface.
You can meet this pattern almost in any good server-side system. Say same Rails (and all the clones), Django, TurboGears. All the modern web-frameworks follow the MVC rules. They have got a domain model which tied to the database structure, controllers which handle the users requests, and html templates which in the case are the view.

But when the people come to the client-side development, they usualy screw everything up, and began to produce a holly merry mix of all they have. And if a system is complex enough they soon come to problems.

The idea.
Among that, the idea of MVC in client-side development is on a surface. That's simple:

Your html/xhtml markuping - is a model,
Your css layer - is a view and
Your javascript - is a controller.

Yes, that's imple, but interesting not that, interesting the inquests you may learn out of this point of view on the system. Instantly if you are following the MVC idea, you should keep the parts as much separated as it's possible. In our case that means the following.

1) The markuping rules
Keep your markuping as much simple and clean as possible. That means no style="" attributes. Use as much suitable tags as it possible. UI for lists, TABLE for real tables, DIV for page blocks, span for inline elements, H1.. for your titles, etc. Try to be as much closer to the original tags meaning as it's possible.

Look at your markuping like on a real data-model. Your nodes should tell for themselves. Try too keep it with a minimum of class and id attributes. Don't use <div class="title" if you may use <h2> tag, etc. Remember you may make it look just as you need later. And read that fucking html manual at last! 8) I bet you'll find many rarely used tags which may replace many of yours divs with classes.

Try to not think about how you'll paint it later. Just make it have a resonable structure and look without any stylesheets.

Try to insert as less images as it possible. Use the <img tag only if you need to input a real image, like a photo or a diagram. If you need an icon, or a background or a design element, make it with a <div tag.

The main idea of all those tries, is to make your markuping the way that you won't need to change a single tag on a further redesign. Even if you're not going to make any redesign, such approach may safe you lot of time when you'll write your css and javascript.

2) The CSS layer rules
Put in your css layer as much design related stuffs as it's possible. Look at your css as on a thing which represents the application view. Put all colors, background images, icons, hover effects etc, here. If you followed the rules from 1) and keep your tags deversified, you'll have lots of abilities to paint your application just as you need.

The main idea here is that css-layer may be simple overloaded by additional stylesheets. If you keep all your design stuffs separated and one day one of your customers will ask you for a special logo for him or for a lovely another icons bunch, you'll be easy to do so just adding the customer specified css file without touching any of the original files.

The images in stylesheets worth an a special word. You may meet many goods and bads about keeping images such as icons and logos in css. But my own experience says me that it's a good idea and for a simple reason. One day it may be jpeg, another png, then gif. Then the sizes of images may be different, etc. If you have the images described in the css-layer, you may change it from here, otherwise you'll have to change the markuping.

And one more point. Keep in your css layer view of different states of the things as well. You'll probably need to define some additiona classes to represent different states of page elements, do so. Do not leave the things on your javascript, this is a metter of view and should be described in css.

3) JavaScript rules
When you writting your javascript always keep in mind that this is your controller and you are implementing the logic. Try to not put in javascript any element style changes. If you call a .style attribute that usually means you behave wrong and mix the things. If you need to change an element view, use your classes system from the css layer, use the addClassName and removeClassName methods. If you don't have an appropriate class in your css layer, create it there. Even if it will contain only one string, in further it will allow you to keep the things clean and controllable. All styles are metter of the view part of the system, do not change them directly from javascript.

And stupid but important, choose good names for the ids and classes in your markuping the way they were talking for themselves in your javascript code and you could always easily understand what's going on.

A simple example
For example you're implementing a dynamic menu. Write a simple and plain structure, like this

--- html ---

<ul id="main-menu">
<li><a href="home">Home</a></li>
<li class="current">
<a href="http:work">Work</a>
<ul>
<li......
</ul>
</li>
<li>
<a href="hell">Hell</a>
<ul>
<li.......
</ul>
</li>
</ul>


Then describe your menu view in your css, include the hover effects and current menu element related states.
--- css ---

#main-menu {....}
#main-menu li {.....}
#main-menu li a {.....}
#main-menu li a:hover {.....}
#main-menu li ul { display: none; }
#main-menu li:hover ul { display: block; }

/* represents the menu state */
#main-menu li.current a {......}
#main-menu li.current a:hover {.....}
#main-menu li.current ul { display: inline; }


Then write some plain javascript which will handle the menu states by switching the classes.
--- javascript ---

var Menu = Class.create({
initialize: function(element) {
$(element).immidiateDescendants().each((function(li) {
li.observe('click', this.choose.bindAsEventListener(li));
}).bind(this));
},

choose: function(event, li) {
// removing the 'current' class from all the li elements
li.up('ul').immidiateDescendants().each(function(element) {
element.removeClassName('current');
});
// adding the 'current' class to the clicked element
li.addClassName('current');
}
});
var menu = new Menu('main-menu');


This is a very dummy example, it won't probably impress you with the power of the principles, but it displays the idea. Having the stuffs separated you may change them independently. Say having a good css-classes system which covers all the view points, you may change your model structure, add new elements and you always have a pretty simple structure which easily understable. Having a good deversified and smart structured model, you may change your css and change make your view look like you need. Having a good API of css class-names you may concentrate on logic in your javascript not worring how it will look later.

So, that's it, hope you had some interesting reading.

4 comments:

cip said...

actually it's quite interesting.

I didn't read about this before, bu this must be because I don't read enough ...

quite an interesting perspective....

did you find this somewhere or you just figured it out ?

Nikolay V. Nemshilov aka St. said...

did you find this somewhere or you just figured it out ?

Yes, I didn't see such an appying of MVC on client-side development as well. But once i've figured it out, it started to help me quite much

cip said...

i've worked quite a bit in client side web devel and I must say that the appoach seems a bit extreme at first .. But when you think about it .. it could make sense ..

I am thinking now about improvements to the view level (css) it's cool to think about completely formating pages without thinking about the html content .. The only thing that might be interesting is making the css a bit smarter .. somehow interpretable ..
The ideea is to make the controller as view-agnostic as possible. So maybe some aspect related issues could be programable by automatic eval of specific css elements...

Nikolay V. Nemshilov aka St. said...

The only thing that might be interesting is making the css a bit smarter

Yes, you're right, this may make your css code look a little bit more complex. And probably you'll think that there are become more of the styles that it was, but in really it's not like that. It's just you have put all your styles in one place.

But on another hand, this will provide you a more opportunities to optimize and better organize your styles. In really this will make your css more systematic and after some time will improve your css-design skills.

But there's not all such a beautiful, this works just perfect when you use CSS2/3 level. When you need to support old CSS level one browsers (damn IE6 include). You may meet some problems with such an approach. And again 'but' this will make you think about your system simplicity and will force you to search for better solutions 8)