Monday, March 26, 2012

Quick update

Hey everyone,

Been super busy, sorry for the lack of updates. Finishing up my senior design project, continuing another project, and starting a new job soon. Expect some updates at some point though! Looks like I'll be leaving Microsoft land, as I installed Ubuntu over my Windows installation so no more .Net stuff for awhile.

See you next time.

Friday, February 17, 2012

Simple example of a Sencha ExtJS 4 login form using MVC

Hey guys.

For my senior design project I've been working with Sencha's ExtJS 4 to develop a web application. Now, I wouldn't normally try and write a beginner tutorial for something like this because I believe there are plenty of badly written beginner's tutorials all over the place that you could find much easier. But I'm going to post what I've been doing with this framework for two reasons:
  • Most tutorials I see seem contrived and don't employ any kind of separation. I'm using an MVC architecture and had trouble finding examples. 
  • Some references in Sencha's documentation seem to be wrong. Apparently their API has gone through several major revisions. 
And I'd like to go ahead and state that this is how I got it working, it might not be the best way to do so. In fact, if you know a better way to do something, feel free to let me know.

The goal here is simple: A user should be able to log in, see some indication that they've been logged in, and log out. Here's what that looks like:
Not the most amazing login system...
Pretty crude, but the important part is getting it functional. Here you see that the user can log in our out. There's also an entry below the form that displays the currently logged in user. Normally if they're logged in the "login" button doesn't show, but this is from an earlier version.

So, to the right I've given you the directory structure so you can see what it looks like -- as you can see it's a pretty straight forward MVC layout.

A short disclaimer: I've put together this example by ripping off various examples in Sencha's documentation, so if you see some dangling reference to them that's why.

Alright, let's start with the store and model. First, here's the model:

Ext.define('AM.model.User', {
    extend: 'Ext.data.Model',
    fields: ['username', 'isAdmin', 'authenticated', 'loggedOut']
});


Nothing too exciting, this represents the current user. Here's the corresponding store:

Ext.define('AM.store.Users', {
    extend: 'Ext.data.Store',
    model: 'AM.model.User',

autoLoad: true,

proxy: {
    type: 'ajax',
    url: 'login?view=sencha&json=true',
    method: 'GET',
    reader: {
        type: 'json',
        root: 'model',
        successProperty: 'model.success'
    }
}

});



As you can see, the store is configured to ask the server for the user data.

Ok, now the views. The first view is the actual form:

Ext.define('AM.view.login.Form' ,{
    extend: 'Ext.form.FormPanel',
    alias : 'widget.loginform',

    name: 'loginform',
    frame: true,
    title: 'Password Verification',
    bodyPadding: '5px 5px 0',
    width: 350,
    height: 150,
    fieldDefaults: {
        labelWidth: 125,
        msgTarget: 'side',
        autoFitErrors: false
    },
    defaults: {
        width: 300,
        inputType: 'password'
    },
    defaultType: 'textfield',
   
    initComponent: function() {
        this.buttons = [
        {
        name: 'loginButton',
            text: 'Login',
            action: 'login'
        },
        {
        name: 'logoutButton',
        text: 'Logout',
        action: 'logout',
        visible: false
        }
        ];
       
        this.items = [
        {
            fieldLabel: 'Username',
            name: 'username',
            id: 'username',
            inputType: 'text'
        },
        {
            fieldLabel: 'Password',
            name: 'password'
        }
        ];
       
        this.callParent(arguments);
    }
});



By the way, I ran across a tutorial in the documentation referencing Ext.FormPanel, but Ext.form.FormPanel seems to be correct.

Here's the other view that just lists the currently logged in user:

Ext.define('AM.view.login.Display' ,{
    extend: 'Ext.grid.Panel',
    alias : 'widget.logindisplay',

    title : 'Users',
   
    initComponent: function() {
        this.store = 'Users',

        this.columns = [
            {header: 'username',  dataIndex: 'username',  flex: 1},
            {header: 'authenticated',  dataIndex: 'authenticated',  flex: 1}
        ];
  
        this.callParent(arguments);
    }
});



Alright, now the fun part: the controller. First, here it is:


Ext.define('AM.controller.Login', {
    extend: 'Ext.app.Controller',

    models: ['User'],
    stores: ['Users'],
    views: [ 'login.Form', 'login.Display'],
   
    refs: [
           {
               ref: 'loginForm',
               selector: 'form'
           },
           {
           ref: 'loginButton',
           selector: 'loginform button[action=login]'
           },
           {
           ref: 'logoutButton',
           selector: 'loginform button[action=logout]'
           }
       ],
   
    init: function() {
        this.control({
        'loginform button[action=logout]': {
        click: function(button)
        {
           var store = this.getUsersStore();
           var logoutButton = button;
           var loginButton = this.getLoginButton();
        
           this.getLoginForm().form.submit({
                        waitMsg:'Loading...',
                        url: 'login',
                        method: 'POST',
                        success: function(form,action) {                        
                           Ext.MessageBox.alert('Logged out', 'You have been logged out');
                           logoutButton.setVisible(false);
                           store.load();
                           store.sync();
                           loginButton.setVisible(true);
                        },
                        params:
                        {
                           view: 'sencha',
                           json: true,
                           logout: true
                        }
              });
            }
        },
        
        'loginform button[action=login]': {
            click: function(button)
            {
            var store = this.getUsersStore();             
            var loginButton = button;
            var logoutButton = this.getLogoutButton();
            
            this.getLoginForm().form.submit({
                        waitMsg:'Loading...',
                        url: 'login',
                        method: 'POST',
                        success: function(form,action) {                        
                            store.load();
                            store.sync();
                            loginButton.setVisible(false);
                            logoutButton.setVisible(true);
                        },
                        failure: function(form,action){
                            Ext.MessageBox.alert('Error', "Invalid username/password");
                        },
                        params:
                        {
                           view: 'sencha',
                           json: true
                        }
               });
            }
            }
        });
    }
});


I didn't have much success on finding information about referencing views from the controller. Most examples mix the logic with the view so it's not an issue. In the end I ended up using refs to obtain the form and its buttons.

There's not much going on here actually. When the user clicks 'Login,' we pass the information to the server and then synchronize the store. If the user is logged in, the server will pass back the user's information. To log out, the parameter is passed to log out and the server clears the user. When the store is synchronized, the user will no longer be in it.

Oh, and here's app.js: 



Ext.Loader.setConfig({enabled:true});

Ext.application
({
    name: 'AM',

    appFolder: 'js/sencha/app',  /* this appears to NOT be a relative path */    

    controllers: ['Login'],   
   
    launch: function() {    
    console.log("init");
    
        Ext.create('Ext.Panel', {
            layout: 'fit',
            renderTo: 'login',
            items: [
                {
                    xtype:'loginform'                 
                },
                {
                    xtype:'logindisplay'
                }
            ]
        });
    }
});

So that's pretty much it. Again, I'm sticking this up here because I had problems finding examples that suited my needs. Most of them mixed the view/controller logic which made referencing components a lot easier. For this project however, we're using an MVC architecture so that didn't help.

See you next time. 

Sunday, February 12, 2012

Running Emma with jdk7 produces "expecting a stackmap frame at branch ..."

Hey everyone.

Today while integrating adding a code coverage build step to integrate into Jenkins (using Emma), a test failed with this error:

Expecting a stackmap frame at branch target 11 in method model.bean.Car.setId(Ljava/lang/Long;)V at offset 4

... Right. And it only failed on the build server (not my machine) What on earth does that mean? Honestly, I have no idea. This post on stackoverflow suggested it was something to do with our build server running jdk7 that the binary distribution of emma did not like (2.0.5312). So, we reverted back to 1.6. That fixed the problem.

I'll probably explore that more in detail sometime, but in the meantime that's the solution.

Saturday, February 11, 2012

jqPlot: crash/hang/infinite loop in the DateAxisRenderer

Hi everyone,

This seems oddly specific. If you've tried using the DateAxisRenderer in jqPlot with a single data point, or multiple data points with the same y value, you might have found yourself stuck with a browser crash.

For example, see this question on stackoverflow or the issue tracker.

Well, the problem has a partial fix which is now in the codebase. I believe there are still some cases where there might be a problem so it's being worked on.

Until its released, you can incorporate the changes into dateAxisRenderer.js by copying them from here. 

Wednesday, February 8, 2012

Local Mercurial repositories on top of other SCM systems

Hi everyone,

Big fan of Mercurial here. Enough that going to other SCM systems is seen as an unfortunate experience. For example, where I worked as an intern we use TFS. Now TFS is much more than source control but I personally don't like its approach to the source control aspect (also: I'm starting to dislike source control plugins to the IDE, but that's another day).

One of the policies is that every commit must have a separate code reviewer. That's fine, but for me made commits a hassle, especially since I started working outside normal hours (and was given limited commit access in the beginning as an intern).

Anyway, the solution is simple: I create a local Hg repository in the directory the project's checked out in and commit to that instead. Also be sure to clone it to a not-your-desktop-which-could-randomly-explode location.

The good news is that this is a very simple process. The bad news is that you of course don't gain the advantage of keeping the Hg commit history like you would with a more complex tool for this like hg-svn or something. Of course in my situation that would get the same problem of requiring reviewers.

The main use for this was to be able to commit frequently and have snapshots of the progress instead of having to, for example, shelve it in TFS. As long as you make sure to clone it somewhere that's not your local machine as well, you should be good to go.

Another time this makes sense is where the rest of your team is used to SVN and the learning curve of another source control system is too much of a pain right now.

Friday, February 3, 2012

Don't forget your server side validation

Hey everyone,

So: the project we're maintaining is filled with JavaScript on the client. One of the things I make sure happens is that everything gets validated server-side even with those fancy shiny JavaScript validators, and we incorporate that requirement into our automated tests. This was missing from some parts when we first took over the project.

Anyway, some projects don't keep that in mind. Today a friend of mine tried to submit something past the specified date, which is enforced by the web application. Said web application enforces this client-side with a crusty snippet of JavaScript code and a hidden form element. Well, surely they would do a check on the server as well, instead of rely on this fairly crude method? No, and with tools like FireBug and friends it's trivial to work around.

You just can't trust the client. I love JavaScript as well, but you still better be validating it from a trusted spot.


See you next time!

Monday, January 23, 2012

Finally getting around to more JavaScript

Hello everyone,

Well, as part of my senior design class for computer science, we are assigned teams of four and each team gets a different project. Our project looks like it will involve a lot of JavaScript. This is good, because I am a fan of JavaScript and don't know it nearly as much as I would like. Also, I'm sick of every class project being in Java (not because I hate Java, just because I'd like to see some variety). Anyway, we're going to be doing a few small web applications that will be using a Java backend (!). Luckily, most of the interesting stuff will be client side.

I took it upon myself to set up everyone's favorite tools like Jenkins. I also had to search out a bug tracker to install. I haven't installed a bug tracker before and I have to say, some of them are a real pain to install and have a lot of dependencies. So after trying out some popular ones and disliking the setup process, I went with one called YouTrack.

I like YouTrack because installing it consists of me deploying it on Tomcat (after the install program), and I'm a big fan of doing as little as possible. I haven't worked with it that much yet but so far it seems simple enough. So if you're looking for a bug tracker with a simple setup and running a windows server, go ahead and give it a try.

(disclaimer: I don't work for them!)

See you next time.

Thursday, January 19, 2012

Rely on your (well written) tests when adding new features

Hi everyone!

Well, I found some time to make a post here. On the ASP .Net project we're working on, things are going pretty well (although they have slowed a bit -- working on getting back into it). Still don't have my dev machine though.

Anyway, our previous work over the past two months has been mostly bug fixing, but we've recently implemented an actual new feature. The feature in question required some pretty substantial modification of various parts of the site and so the potential for breaking things was there.

Luckily, both our unit test suite and functional tests have grown pretty substantially and so there is a lot of coverage to ensure things don't break. In fact, the feature in question affects areas that happen to be heavily tested, so we can prevent regressions that way.

But it's not just about having test coverage of the code you're modifying -- you have to treat your test code right. That is to say, the test code is not "just test code" and it should be held to certain quality standards like your production code. We've spent a good chunk of our time establishing a test architecture when we could spend that time cranking out more badly written, fragile, hard to maintain tests.

Instead, we've taken the time to isolate potential changing parts of the code (such as element locaters) and build an abstraction layer on top of the Selenium API specific to our project. This makes the tests easier to maintain and less susceptible to UI changes. Another nice benefit is that it's reduced the time it takes to write functional tests like this substantially. Most of the actual Selenium code has already been written, and writing a test means creating different page objects and calling their methods.

When we do add to the page objects, it's usually a small amount of code and just means we'll be reusing it later.

So, the moral of this story: treat your tests right and you will benefit from it (we certainly have).


See you next time!

Monday, January 9, 2012

Back in school again...

Hi everyone.

Well, I'm back in school again about to start my last semester of university (hopefully). This is my 5th year and I'm trying to wrap up everything for computer science and chemistry. Chemistry is proving to be the more annoying one to account for.
Anyway, there won't be too many updates in these first couple weeks until I get into the usual routine, and I also don't have my dev machine at the moment. Instead I'm using my old crusty laptop. Ah well.

And finally for reference, here's some of what I'm hoping to get into more this year:
  • More JavaScript, both client and server side.
  • Clojure, haven't devoted as much time as I wanted.
  • Continue ASP .Net development
  • Use some formal MVC frameworks for Java development
  • Finish reading SICP (!)
See you next time.