Вы находитесь на странице: 1из 4

Implementation Details

The task was to implement the single page interface using as less libraries as possible and do a good (reusable) coding.

Approaches
There are two main approaches for implementing dynamic interfaces: Server & HTML driven approach, when you render all the content of your page on the server side and then use JS to add interactivity; and Browser & JS driven, when JS is responsible for content rendering. In this exercise I was using the JS driven approach. It is becoming more popular nowadays because it allows to develop complex & fast interfaces which require less interaction with server. There are some drawbacks of this approach like first page time loading or SEO, but there also are some ways to overcome it.

Project Structure
/index.html - the entry point /xml/ - XML task data /xsl/ - XSL templates /js/ - JavaScript modules /css/ & /images/ - some basic styling and images

HTML, XML, XSL and CSS files are pretty basic so I will mainly talk about JavaScript architecture in this document.

JavaScript organization
For organizing JavaScript Im using a Module Pattern. Since JavaScript doesnt have any encapsulation features, this pattern implements it:
var MODULE = (function(){ function private(){} returns { public : function(){ private(); } } })();

A good example of encapsulation in this task is FRAMEWORK module, which hides all the configuration and publishes just two views for user to work with. There are 4 modules in my exercise: DOM, XML, FRAMEWORK & APPLICATION. The first two handle browser incompatibilities using the Facade Pattern, choosing the implementation which is available in current browser and hiding it from the user of the library, there are also some helper functions there.

Framework
If you really need the reusable and maintainable architecture you usually come to using a framework. There is a number of them in the wild: Sencha ExtJS, BackBone.JS, Google Closure & Angular, Yahoo YUI and others. In my exercise I decided to implement a simple framework. I will be implementing Model - View Template (MVC Pattern variation) framework with events based communication.

The Model
The Model usually is an object that holds our data. In our case it will be XML object. It can also be a JSON object or some JavaScript object that encapsulates XML/JSON data and provides some methods for getting & setting.

The Template
For Templates we are using the client-side XSLT. There is also a number of client-side template languages: Google Closure Templates, Underscore.JS template function, Handlebars.JS.

The View
The View is the main part of the framework. It is responsible for creating an element in DOM, rendering a data from Model using the Template into the element, handling browser events for that element.

Framework architecture
The framework code in stored in framework module. If we open it, we will first see two helper functions. The mixin function implements a Mixin Pattern which allows you to copy methods from one object to another, its used inside the inherits function, which implements the Prototype Pattern. These functions provide inheritance for the framework views. Lets look at base view:
var View = function(options){ this.options = options || {}; this.element = document.createElement(this.tagName || "div"); if(this.className){ this.element.className = this.className; } this.xml = this.options.xml; this.render(); }

The view constructor function is pretty simple: it takes [options] as a parameter and saves it as a property. It also creates a DOM element, and saves it to [element] property. You can configure its [tagName] and [className] in the extended views. After configuration it calls [render] method. There is also [template] method which will take [xml] & [xsl] properties of object and pass them through XSLT and insert into [element].

Last important feature is [events] property which stores the event manager, its based on Observer and Mediator patterns. The events manager is the interface through which different views communicate with each other. Acting as a central point it helps in decoupling the system and improving component reusability. For example we have two components A & B. The [events] object has two methods: [subscribe] to which component A passes the event topic & function that will handle it, and [publish] component B calls it to trigger some event by passing an event topic & parameters.
A.events.subscribe(alert, function(parameters){ alert(parameters); } B.events.publish(alert, B is calling);

Application architecture
After we got the overview of our framework, lets see how it works in a real application. The main principle of architecture is composition of views.

Here we can see two states of our application: [NewsListView] and [ArticleView]. Lets look at the [NewsView] declaration to see how it is working:
var NewsView = FRAMEWORK.View.extend({ tagName : "li", xsl : "xsl/news.xsl", render : function(){ var self = this; this.template(); DOM.on(this.element, "click", function(){ self.events.publish("showArticle", XML.getChildValue(self.xml, "id")); }); } });

Here we see, that [NewsView] is extended from the [FRAMEWORK.View]. In its configuration we can see <li> as a [tagName] and news.xsl as a template. To render such view we can call:
var view = new NewsView({ xml : someXml}); document.getElementById(list).appendChild(view.element);

As we can see here a component is quite independent and can be even tested using a browser console. You can even write unit-tests for it. Inside the [render] function there is also a DOM event listener for click on the [element]. So when someone clicks it, the showArticle event is published through [events], passing article id from [xml] as a parameter. The [ApplicationView] is subscribed to this event and renders [ArticleView]:
this.events.subscribe("showArticle", function(id){ self.element.innerHTML = ""; self.element.appendChild(new ArticleView({ "headerXml" : DATA.getNews(id), "bodyXml" : DATA.getArticle(id) }).element); });

Since [ArticleHeaderView] and [ArticleBodyView] just render the template we also extended our [FRAMEWORK.View] with a [FRAMEWORK.TemplateView] so we dont have to write same render methods for this views.

Disclaimer
Browser compatibility
Ive tested this application in latest Chrome, Safari, Firefox & Internet Explorer 7+. There are some issues with local testing, because Chrome security model doesnt allow you to load XMLs locally using XMLHttpRequest. You have to run Chrome with --allow-file-access-from-files parameter.

Framework complexity
I was trying to balance on features vs simplicity. For example, instead of making a separate [ArticleView] I could make a [NewsView] more complex, but this could make reviewing my exercise more hard. So I tried to concentrate on the concepts and patterns I usually use while developing client-side JS application and I hope that I managed to demonstrate them. I would gladly discuss the ways to improve my solution on the technical interview, if there would be one.

XML, XSL, XSLT


I dont really have experience with XSL & XSLT technologies. I generally used other template languages: JSP in Java, ERB in Ruby, Underscore.JS in JavaScript and PHP in PHP :) As for XML, I usually work with it as a configuration format for Java applications or as a transport format for Web-Services (SOAP/REST). Here I was using XSL/XSLT just as a simple templating engine - maybe my usage wasnt something you were expecting.

Вам также может понравиться