Archive

Posts Tagged ‘separation of concerns’

JavaScript, jQuery, and UI Frameworking

In my professional consulting career, I’ve been avoiding the UI area of software development for years, much like I tend to avoid reporting tools like Crystal Reports or Business Objects. I like poking around in the guts of systems. Everything below the surface is so much more interesting, or so I thought. Instead of working on UI layers, I tried to hire other people to do what I thought was fairly simple work. This wasn’t working. It turns out, in order to direct hired hands, you need to know what the hell you’re asking them to do. So I backed off having other people do UI work and realized I just need to strap in and learn it on my own. This includes iOS, JavaScript, jQuery, and anything else to do with building user interfaces. It turns out, there’s a lot to learn.

I’ll talk about iOS in a future blog entry, once I get comfortable with iOS, Objective C, and all the related tools. Today I’m going to talk about JavaScript and jQuery.

In a side-project called Zifmia, I’m developing a service/cloud based game engine for Interactive Fiction. I’ve been working on this in pieces for a long time. It’s morphed from WPF, to Silverlight, to Java, to iOS, and I finally realized that if I could create a service, I don’t need to port it anywhere anymore. Well, except maybe the Kindle since the Kindle doesn’t support connected services. (This makes sense. Most people use the Kindle for reading and are only concerned about connectivity when purchasing and downloading a new book or other content.) But for the web, smartphones, the iPad, iPod, and other tablets, a service/cloud engine is really the right way to go.

I start developing the service layer using RESTful web services. I used the Microsoft .NET WCF REST 4.0 template to provide the external layer for the service side functionality. This was great since WCF 4.0 REST works nearly perfectly out of the box. There’s very little “tuning” to do to make it work locally or on a server. The one major issue I had was with cross-domain ajax calls, but that’s solved by adding a header on all return calls from the server. The service allows a consuming application to register a user, login, start a session (game), send commands to a session, and various other management tasks. I plan to implement oAuth so that the service can be embedded in Facebook properly.

I then start playing with various platforms to consume the service. I played round with Windows Phone 7 (Silverlight) and that was drop dead simple. It takes an object definition and two lines of code to consume the service. I didn’t implement a full Application, but it helped work through some of the service prototyping issues.

I played around with iOS, but stalled out because I wanted the web interface completed first. I had a very committed developer working on it, but our communication wasn’t working well, and so I set that relationship aside for the time being. (I haven’t forgotten about you Dan…hope to catch up soon). I then started to work on the client side JavaScript code and realized there was a LOT of work that needed to be done before anyone could use Zifmia properly. The result of that work is the essence of this article.

I started developing the interfaces in jQuery and JavaScript, but soon realized the code (HTML, CSS, JavaScript, jQuery) was becoming quite convoluted and unreadable. I also realized it would only get worse if I continued. So I started asking around and researching how JavaScript/jQuery based client user interfaces should be organized. The surprising answer is that although there are a handful of serious solutions, there isn’t a lot of open thinking about how this should be done. The people that understand the need and have the ability to work through the problems have created tools, but haven’t really shared the process with the public. It’s a shame, since that’s the really important part to share, not just the code.

I looked at a few of these tools (like JavascriptMVC, Backbone.js, SproutCore) but found all of them to have aspects I dislike. Complexity, dependencies, and high learning curves. Instead of adopting, I chose to develop my own, trying to work through the issues. Here is what I came up with. This is a very simple methodology for separation of concerns in a javascript UI framework.

The first order of business is to identify assumptions:

  • We will work on the concept of a single page interface.
  • The page will have its own class/namespace.
  • The page will have a master HTML arrangement (header, body, footer).
  • The body will be a View container.
  • Each view will be based on an HTML template separate from the main html page. The HTML template will use normal HTML, CSS, and JavaScript.
  • Each View will have its own Controller or Presenter class.
  • All AJAX calls will be contained in a single Service class. (This is arguable, since a more complex web application could have highly distinct groups of service calls. More than one Service class could be adopted).

The result is a very simple and effective way to separate code in a single page framework jQuery driven website.

Create a web page called index.html similar to the one below:

<html>
<head>
    <title>Zifmia></title>
    ....
</head>
<body onload="javascript:$MyWeb.onLoad();">
    <div id="outerPanel">
        <div id="ajaxLoading"><img src="images/loading.gif" alt="Loading" /></div>
        <div id="headerPanel"><p>Textfyre Presents, A Zifmia+Web Portal (Beta)</p></div>
        <div id="viewContainer"></div>
        <div id="footerPanel">Copyright @ 2011 Textfyre, Inc. - All Rights Reserved</div>
    </div>
</body>
</html>

In the head section of the html page, create a class and create an instance of the class as MyWeb:

var $MyWeb = new mySite();

function mySite() {

    this.controller = null;

    this.username = getCookie("username");

    this.onLoad() = function() {
        // Initialize page here.

        // based on your page logic, cookies, etc, determine the initial state of the page
        // this is where you would determine which view to show, or to show the default
        // view. Based on whatever view is needed, we set that controller to the page
        // controller and call init(), which should be a standard function on all
        // controllers.

        if (username != "") {
            this.controller = new sessionController();
        } else {
            this.controller = new defaultController();
        }

        this.controller.init();
    };

}

Since I assume you have a design in mind, you should be able to separate the various views on your own into html templates. Each template might look something like this:

<div id="loginPanel">
    <div style="font-size: 14pt; font-weight: bold;">
        Zifmia Login Form<span id="loginMessage" style="font-size: 10pt; font-weight: normal;
            margin-left: 20px;"></span></div>
    <hr />
    <table>
        <tr>
            <td>
                <span style="white-space: nowrap;">
                    Username:
                    <input class="login" id="zLogUsername" type="text" onkeyup="javascript:validateRequiredField(this);" /><span
                    id="zLogUsernameError"></span></span>
                <span id="nickNameField" style="margin-right:10px;font-weight:bold;">
                </span>
            </td>
            <td style="white-space: nowrap;">
                Password:
                <input class="login" id="zLogPassword" type="password" onkeyup="javascript:validateRequiredField(this);" /><span
                    id="zLogPasswordError"></span>
            </td>
            <td style="white-space: nowrap;">
                <a id="zLogSubmit" href="#login" onclick="javascript:$MyWeb.controller.login();return false;">login</a>
            </td>
            <td style="text-align: right; padding-left: 20px;">
                <span id="registerNotice">If you don't have an account, please <a href="#showRegistration"
                    onclick="javascript:$MyWeb.controller.showRegistration();return false;">register</a>.</span>
            </td>
        </tr>
    </table>
</div>

This html should be stored in a subdirectory called templates with the name loginTemplate.html. We can use a simple AJAX call to retrieve it:

    var loginTemplate = getTemplate("templates/loginTemplate.html");

    function getTemplate(templateURI) {
        return $.ajax({
            url: templateURI,
            global: false,
            type: "GET",
            async: false
        }).responseText;
    }

The getTemplate function should be placed in a utility class or in the page controller for easy reuse. From here’s simple to create a controller class to display a view template in the correct place in our html page:

function introController() {

    var REG_USERNAME_FIELD = "zRegUsername";
    var REG_PASSWORD_FIELD = "zRegPassword";
    var REG_NICKNAME_FIELD = "zRegNickname";
    var REG_EMAIL_ADDRESS_FIELD = "zRegEmailAddress";

    var LOG_USERNAME_FIELD = "zLogUsername";
    var LOG_PASSWORD_FIELD = "zLogPassword";

    var viewContainer = "#viewContainer";
    var usernameField = "#zLogUsername";
    var nicknameField = "#nickNameField";
    var regErrorPanel = "#regErrorPanel";
    var loginMessage = "#loginMessage";

    this.introTemplate = $Z.getTemplate("templates/introTemplate.html");
    this.loginTemplate = $Z.getTemplate("templates/loginTemplate.html");
    this.registrationTemplate = $Z.getTemplate("templates/registrationTemplate.html");

    this.init = function (message) {

        $(viewContainer).hide();
        $(viewContainer).html($(this.loginTemplate).html());

        var zLogUsername = document.getElementById(LOG_USERNAME_FIELD);
        var zLogPassword = document.getElementById(LOG_PASSWORD_FIELD);

        setRequiredValidator(zLogPassword);

        if (message != null && message != "") {
            $(loginMessage).text("(" + message + ")");
        } else {
            $(loginMessage).text("");
        }

        if ($Z.username != "") {
            //
            // We know the username and nickname, but the user is logged out.
            //
            $(usernameField).hide();
            zLogUsername.isValid = true;
            $(nicknameField).show();
            if ($Z.nickname != "") {
                $(nickNameField).html('<a href="#changeUser" onclick="javascript:$MyWeb.controller.changeUser();">' + $Z.nickname + '</a>');
            } else {
                $(nickNameField).html('<a href="#changeUser" onclick="javascript:$MyWeb.controller.changeUser();">' + $Z.username + '</a>');
            }
        } else {
            //
            // We don't know anything about the user.
            //
            setRequiredValidator(zLogUsername);
        }

        $(viewContainer).append($(this.introTemplate).html());
        $(viewContainer).show();

    };

    this.changeUser = function () {
        $Z.username = "";
        $Z.saveSessionData();
        this.init();
    };

    this.login = function () {
        var zLogUsername = document.getElementById(LOG_USERNAME_FIELD);
        var zLogPassword = document.getElementById(LOG_PASSWORD_FIELD);

        $Z.login(zLogUsername.value, zLogPassword.value,
                function (zifmiaLoginViewModel) {
                    if (zifmiaLoginViewModel.Status == "0") {
                        $Z.username = zRegUsername.value;
                        $Z.authKey = zifmiaLoginViewModel.AuthKey;
                        $Z.nickname = zifmiaLoginViewModel.Nickname;
                        $Z.saveSessionData();
                        $ZWeb.onLoad();
                    } else {
                        $(regErrorPanel).text(zifmiaLoginViewModel.Message);
                        $(zLogUsername).focus();
                    }
                },
                function (xhr, textStatus, errorThrown) {
                    $(regErrorPanel).html(xhr.responseText);
                }
            );
    };

    this.showRegistration = function () {
        $(viewContainer).hide();
        $(viewContainer).html($(this.registrationTemplate).html());

        var zRegUsername = document.getElementById(REG_USERNAME_FIELD);
        var zRegPassword = document.getElementById(REG_PASSWORD_FIELD);
        var zRegNickname = document.getElementById(REG_NICKNAME_FIELD);
        var zRegEmailAddress = document.getElementById(REG_EMAIL_ADDRESS_FIELD);

        setRequiredValidator(zRegUsername);
        setRequiredValidator(zRegPassword);
        setRequiredValidator(zRegNickname);
        setRequiredValidator(zRegEmailAddress);

        $(viewContainer).show();
    };

    this.register = function () {
        $(regErrorPanel).text("");
        var zRegUsername = document.getElementById(REG_USERNAME_FIELD);
        var zRegPassword = document.getElementById(REG_PASSWORD_FIELD);
        var zRegNickname = document.getElementById(REG_NICKNAME_FIELD);
        var zRegEmailAddress = document.getElementById(REG_EMAIL_ADDRESS_FIELD);

        $Z.register(zRegUsername.value, zRegPassword.value, zRegNickname.value, zRegEmailAddress.value,
                function (zifmiaRegistrationViewModel) {
                    if (zifmiaRegistrationViewModel.Status == "0") {
                        $Z.username = zRegUsername.value;
                        $Z.nickname = zRegNickname.value;
                        $Z.saveSessionData();
                        $ZWeb.controller.init(zifmiaRegistrationViewModel.Message);
                    } else {
                        $(regErrorPanel).text(zifmiaRegistrationViewModel.Message);
                        $(zRegUsername).focus();
                    }
                },
                function (xhr, textStatus, errorThrown) {
                    $(regErrorPanel).html(xhr.responseText);
                }
            );
    };
}

Note there are many other things happening in this controller including ajax calls and handling user interactions. The view is shown to the user through a jQuery call (which can be done with simple DOM manipulation):

        $(viewContainer).hide();
        $(viewContainer).html($(this.loginTemplate).html());
        $(viewContainer).show();

So that’s it. You have a main controller in your index.html page that can be access by using $MyWeb at any time, you have varied controllers that are at $MyWeb.controller that have methods that can be called from your html. All of your HTML is in separate files for easy editing and reuse. This is a simple, yet effective way to separate and manage your AJAX/jQuery/JavaScript enabled website.

Architecting From the Bottom Up

I’m sure I’m going to steal someone’s cheese with this one, but I have very strong feelings about how systems are developed and who is involved in the process.

It’s been my experience that most companies employ someone in the Chief Architect role. This person interacts with the stakeholders to determine short and long-term technical needs, works with managers to integrate architectural change through internal product development, and above all else, let no man enter the Ivory Tower.

For whatever reason, many really smart (I mean really really smart) developers make their way into the role of Chief Architect without ever understanding who their audience is. They assume their audience is the IT Director, the Board, the principals, and all managers. It’s my contention that this is entirely wrong. The main audience for architecture is the developer. And not just any developer. I’m talking about Joe Average Developer. I’m not talking about the clock-watching consultant who tries to get his straight-eights in. I’m not talking about the workaholic senior developer who, if he (or her – no gender slights meant) doesn’t understand something, will draw his own blood in nightly rituals of self-abuse in order to gain an understanding. I’m talking about the developer that comes to work, gets handed an assignment, and wants to do a good job. They know they’re not likely to be a senior developer. They’re probably going to fork off into business analysis or project management at some point. But for now, they’re a developer. Heck, they may actually be an actor or singer who happens to know how to code. Coding pays the rent.

Back to our architect. The architect also assumes that they know what’s best for the company. They may claim they have no prejudice but believe me, they do. We all do. Out of the gate, all architects are suspect zero. We all have an agenda, we all like things a certain way. In most cases, the architect will arrange the pieces on the board that makes us feel the most comfortable. We will set out on a relentless quest to see a technical environment come to life that bears our heart and soul. We do this because we know that we can be successful in such a world. Well, actually success isn’t the motivator. That’s an illusion. We want to control our environment. That is our primary goal and in many cases, the architect doesn’t even understand their own primary goal.

However, there is another way. I see the lead architect role with four primary responsibilities.

First, there has to be strong communication with all levels. The architect should know the stakeholders, the analysts, the developers, the testers, the infrastructure staff, and the users. They should have strong communication networks with all of these people (and probably more). If you have an architect that likes to hide, boy do you have problems. I’m not talking about someone who’s digging in to get work done. I’m talking about someone that you’re never quite sure what they’re doing.

Second, there has to be a strong set of standards written down, introduced at all levels, discussed at all levels, and monitored at all levels. This may include code reviews, static code analysis, check-in policies. Developers like the freedom to write code, but they don’t like everyone doing it differently. In this respect, developers are a lot like soldiers. If you give them strict guidelines, they will find the art of their skill in being productive. They will be better for it and so will your company. If standards are given short-shrift or treated as an aside, your developers will be unhappy, less-productive, and very likely to switch jobs after the next disappointing pay-raise.

Third, all new technical requirements should be developed with all hands on deck. That means that developers should have a say in any newly developed framework. Everyone should be given the opportunity to provide technical ideas and in fact, the entire process should be presented in such a way that developers are encouraged and rewarded for their input. The less an architect listens to the developers, the more costly and time-consuming any and all new projects will become.

Fourth, and this is probably the most important. Keep it simple. I’ll say it again. Keep it simple. I don’t care if you have three PhD’s in math, engineering, or computer science. You are not going to be writing code. The developers, Joe Average Developer, are going to be writing code. So if your plan is to implement a complex set of requirements as a framework, you have failed before one line of code is written in your new framework. If you have an architect that constantly talks about object-relation mapping, object containers, dependency injection, separation of concerns, and abstraction layers, you have an architect that will create a set of middleware that no one, and I mean no one, will understand. If he gets hit by a bus, you’re screwed.

I have a rule. It’s a pretty simple rule. Take any framework or middleware or API. Grab any Joe Average Developer off the street and ask him or her to create a small data entry application with three or four related tables or a handful of related classes. It doesn’t matter if they start at the domain level or the database level. They get the same assistance that anyone else does on staff. If there’s training or pair programming in the regimen, that’s great. Here’s the rule. If Joe Average Developer can’t deliver a simple application in less than two weeks (and that’s a very forgiving schedule in my book), then you have completely failed at creating a productive and cost-effective framework. If you can’t get them to create a screen or report or web page in a few days, you’ve really messed up.

Some of the arguments I’ve heard over the years include:

“We know there are average developers, but we’re going to segregate them off into simpler jobs, like UI development.” – This is great for new development. What happens when someone has to maintain the code and all the smart people are missing?

“This isn’t that hard. I find it hard to believe that a good programmer won’t understand the framework.” – This is hubris. Don’t smart people know they’re smart? I don’t like to be an elitist but I’ve been around this business for a long time. There are many different kinds of developers, but I can assure you, only a handful will reach architect status and only a few those actually know design patterns. You can’t expect to hire all architects and senior developers. It’s just never going to work.

“We (meaning the smart people) have researched all of the requirements thoroughly. We understand all of our strengths and weaknesses. We know what’s best.” – By your divine right, you shall (cough) succeed. In the short-term maybe….let’s see your framework and code base in two years.

In summary, developers are the meat of any company that relies on computer systems for its products and services. Instead of putting one person in charge of the function of your business, doesn’t it make more sense to have everyone involved? Doesn’t it make more sense to rely on simplicity? Doesn’t it make more sense to create a technical environment that can be handed over to twenty Joe Average Developers and sustain productivity?

Or maybe you like your Ivory Tower.