Monday, December 30, 2013

Sequence Based FlexUnit integration testing

Did you know that sequence based testing is built into FlexUnit? I was relieved to find this link in the documentation (http://tutorials.digitalprimates.net/flexunit/Unit-13.html). If you go to that page, please scroll to the bottom section about "Using Sequences".

One of Twin's clients needed a real time update for currency exchange. Basically in our system, instead of a continuous feed, the business requirement was that every week the admin would enter the new exchange rates (there were only 5 that were relevant). Once saved, there was supposed to be a real time push notification to all open clients so that they could update their forecast data. 

Here is what my integration test needed to prove: 
  • Get the current exchange rates from the service
  • Save a new exchange rate
  • Receive the push notification
  • Validate that the new rates has been recorded into model under the correct date.
var rtmpManager:ExchangeRateRTMPManager = new ExchangeRateRTMPManager();
var sequence:SequenceRunner = new SequenceRunner(this);
    sequence.addStep(new SequenceCaller(eventDispatcher, getInitialExchanges, [weeks] ))
    sequence.addStep(new SequenceWaiter(eventDispatcher, INITIAL_RATES_EVENT,TIMEOUT, handleTimeout));
         
    sequence.addStep(new SequenceCaller(eventDispatcher, saveCurrency ,[er]))
    sequence.addStep(new SequenceWaiter(eventDispatcher, SAVE_CURRENCY_EVENT,TIMEOUT, handleTimeout));
  
    sequence.addStep(new SequenceDelay(15*1000)) //Delay 15 s to see if we can get a notification in that time
    sequence.addAssertHandler( validateRTMPManagerReceivedPushNotifcation, null);

    sequence.run();

Tests passed, and it worked beautifully!

Permissions Modelling in Flex

Permissions is something that most of my projects have needed. I've been iterating on a design for many projects, and I've finally come up with something (leveraging some work that my Twin teammates have produced)  that is scalable, testable, and easy for my team to implement. I've written this up in the context of Flex / Actionscript, but there is no reason why it couldn't apply to other languages.

Just to clarify my requirements, here are the user stories that I'm working with. 
  • Should be testable.
    As the developer, I want to be able to declare which permissions are present during testing and development independent of my actual permissions on the system. (In other words - decoupled)  
  • Should be scalable
    As a client, I want to be able to add/remove permissions at any time without major work/rework in the application
  • Easy to understand
    As a new or jr. developer, I want to be able to understand and implement permissions in a best practices way

What I came up with, was a hierarchical string based system. It looks like the following:
public class PermissionTaskConstants
    {
        public static const DEVELOPER:String = "developer"
        public static const ADMIN:String = "admin";
        public static const ADMIN_USER:String = "admin.user";
 public static const ADMIN_CURRENCY:String = "admin.currency"
        public static const LOGIN:String = "login"
        public static const PROJECT:String = "project"
        public static const PROJECT_EDIT:String = "project.edit"
        public static const STAFFING:String = "staffing";
        public static const STAFFING_EDIT:String = "staffing.edit";
        public static const STAFFING_ALLOCATE:String = "staffing.edit.allocate"

    }

In this way, if you were assigned a permission of "staffing.edit.allocate", you would inherit all of the rights of "staffing" and "staffing.edit". This satisfy's the scalable requirement. It is trivial to add or remove permissions, as it would only mean adding / removing strings from the permission path.

These permissions would live in a "permission registry", which would contain an array of strings. This registry could be populated from a service call to a database, or it could be filled at run time. Filling it at run-time would satisfy the "should be testable" requirement. The code is availabe at the bottom, but I've set it up so that it dispatches events when permissions are changed.  A developer can listen for those events and update the UI. Although the typical workflow is that after login, we retrieve the permissions from the database, and the registry is populated before any of the UI is displayed.

IMPORTANT: Decouple the registry from the view!

So this is super important. In order to make this testable and decoupled, never, ever, ever reference the registry in the view. Said differently MXML files should have NO KNOWLEDGE of the PermissionsRegistry.

Here is the recommended workflow. You have a MXML file that represents the view. Just for clarification, this view is in charge of the layout and interactions with the user. There should be no business logic in the view.

Then you have an presentation model (PM) that is in charge of all business logic. This is likely a pure actionscript file. Business logic means conditionals, domain level events, and in this case permissions. The PM receives a copy of the permission registry through dependency injection. The PM then exposes the specific permissions that the view needs through methods.

The view creates its own Bindable public properties that represent the various permission states, and then reads them from the PM. (Please forgive the incorrect capitalization in the MXML objects, the css "brush" for this formatting strips that out)



    <![CDATA[
        import mx.controls.Alert;
        import mx.events.FlexEvent;

        public var pm:PermissionsPM;
        [Bindable] public var canReadProjects:Boolean;
        [Bindable] public var canEditProjects:Boolean;
        [Bindable] public var canReadStaffing:Boolean;
        [Bindable] public var canEditStaffing:Boolean;

        private function creationCompleteHandler(event:FlexEvent):void
        {
            pm = new PermissionsPM();
            canReadProjects = pm.canSeeProjects();
            canEditProjects = pm.canEditProjects();
            canReadStaffing = pm.canSeeStaffing();
            canEditStaffing = pm.canEditStaffing();

        }
        ]]>
    
    
    

package
{
 import com.squaredi.permissions.PermissionTaskConstants;
 import com.squaredi.permissions.PermissionsRegistry;

 import mx.collections.ArrayCollection;

 public class PermissionsPM
 {
  [Inject]  public var permissionsRegistry: PermissionsRegistry;

  public function PermissionsPM()
  {
   permissionsRegistry = new PermissionsRegistry();
   var permissions:Array = [PermissionTaskConstants.PROJECT_EDIT, PermissionTaskConstants.STAFFING]
   permissionsRegistry.permissionsList = new ArrayCollection(permissions);
  }

  public function canSeeProjects():Boolean
  {
   return permissionsRegistry.hasPermission(PermissionTaskConstants.PROJECT);
  }

  public function canEditProjects():Boolean
  {
   return permissionsRegistry.hasPermission(PermissionTaskConstants.PROJECT_EDIT);
  }

  public function canSeeStaffing():Boolean
  {
   return permissionsRegistry.hasPermission(PermissionTaskConstants.STAFFING);
  }

  public function canEditStaffing():Boolean
  {
   return permissionsRegistry.hasPermission(PermissionTaskConstants.STAFFING_EDIT);
  }
 }
}


A couple of other special features about the code. As a developer I can manually add and remove permissions from the list. When I do this, it sets a "developerUpdated" flag, which will ignore setting the whole array. Here is the use case for that. I login to the system but the service call to get permissions is delayed (for some reason). Then I want to verify how the system looks for other users, and add specific permissions, then the service call comes back and could potentially overwrite the values that I've modified. So there is code in place to prevent that.
public function set permissionSource(v:Array):void
        {
          if (developerUpdated) { return} //Don't allow it to be overwritten if the developer has already set individual permissions for testing
          permissionsList.source = v;
          permObj = createPermObj(_permissionsList)
          notifyUpdate();
        }

        public function addPermission(permission:String):void
        {
            var idx:int = permissionsList.getItemIndex(permission);
            if (idx <0)
            {
                permissionsList.addItem(permission);
                permObj = createPermObj(permissionsList)
                developerUpdated = true;
                notifyUpdate();
            }
        }

The other feature that is in the code, is an interface for extracting the data. This could be used in the case of a value object (VO) that returns from the database that has a list of permissions for a given user. This VO is an object, and doesn't have the necessary string representation for permissions. The permission registry accepts an PermissionExtractor helper, that can convert the VO into permissions strings.
package com.squaredi.permissions
{
    public interface IPermissionExtrator
    {
        function getPermissionString(perm:Object):String; // returns a.b.c
    }
}


All of the code and an example can be found at: https://github.com/dshefman/FlexPermissions

Quick and Free, Remote-Team Planning Poker

Recently I was on a hybrid team, made up of representatives from Twin Technologies and 2 other companies. We were all over the country, and we needed a way to play planning poker effectively. Given the other tools that we were using, adding an additional tool, credentials, IT clearance, etc. wasn't feasible.

So we found this great blog post from fourkitchens about using a Google Spreadsheet for planning poker.


To play planning poker, we all call into the phone / voip conference number and open the google doc. After we discuss each story, everyone enters their story point vote, but doesn't press Enter right away. The scrum master can see that everyone has entered a value when their respective box is highlighted grey. Once everyone has made a choice, the scrum master calls “3, 2, 1: Go” and everyone hits Enter. All values appear on everyone’s screen and the planning poker game continues as normal.

We color coded the cells based on conditional formatting (Format -> conditional formatting). Each Fibonacci number got its own color. Invalid numbers remained white. This gave an easy visual representation on the distribution of values.

Now you might have noticed the "Average" line in the photo. We were spending too much time discussing and coming to a unanimous agreement on these estimates.  Based on recent recommendations in the Agile world, everyone doesn't have to agree on a number. The numbers do have to be within a spread of 3 though. For example, 2,3,5 or 3,5,8 are valid spreads. The spread has to be there present though: 2,5,5 or 3,3,8 are not valid spreads and would need to be discussed. (The photo above would represent a invalid spread and we'd have to have more discussion until we could bring that in).

With the adopted averaging the numbers, we would round up to get our estimated point value. Usually what would happen, is that as the team size would unfortunately fluctuate and /or different people could or couldn't attend the planning, we would change what was being averaged. The picture above shows the average only from Rick, Drew, and Larry, and the resulting estimate would be 2 story points (rounding up, or Math.ceil(1.333) :) ) .

Given this system of averaging, it is likely and common to end up with non-Fibonacci totals for our estimates. That is okay. Since the estimates have no time based correlation, they are only used to determine our velocity and therefore our commitment, using Fibonacci only numbers as the inputs and the average as the output works out really well. Fours, sixes, and sevens in out estimate gave us good insight into velocity.

Now just to repeat how agile estimates are supposed to work. The estimate is RELATIVELY sized based on team decided criteria. These UNIT-LESS numbers are used solely to determine velocity. It will likely take 2-3 sprints to even figure out what the velocity is. The estimate HAS NO CORRELATION to time. Once the velocity has been determined, then it is used to make the COMMITMENT. The team says, that we can do (x) story points per sprint, so we will commit and GUARANTEE that (x) will be done by the end of the sprint. That is why averaging works in this case, because the numbers roll into the commitment, and not into any time units.

This system is fast and simple. Adding or removing team members is a no-brainer. Estimating was no longer a chore, nor took up very much time. We could get in and out very quickly and get back to work. I hope that it works as well for you.

Friday, December 6, 2013

Remoting Landmine without a stack trace or debug ability

Summary: 

While using AMF remoting, if you get the following error: 

TypeError: Error #1034: Type Coercion failed: cannot convert Object@1456c7b9 to mx.messaging.messages.IMessage

And you've overridden the  hashcode to your java VO objects, you will end up in an un-debuggable situation. 

Solution:  Remove the hashcode override. 

BackStory:

We are migrating database schemas, so I had set up unit tests to compare the results from one schema to the other. I am using JUnit and assertEquals. 
According to the documentation, I should override the equals() method on each object, as that is what the assertEquals uses for the comparison. This was tedious, but then I discovered that Eclipse had a generate equals() and hashcode() methods. Eclipse comments say to always include hashcode when overriding equals. Ok. I confirmed that on google, all things checked out. 

What happened though, is that serializing from Java to Flex went fine, but on the return trip --- BOOM. 
The error was an UncaughtErrorEvent.UNCAUGHT_ERROR. The request made it out, according to Charles webproxy, but never actually made it to the endpoint on the other side (Based on the debugging breakpoint). Since it never made it to the service, the normal fault responder didn't fire. Fortunately, I'm trapping all uncaught error messages in Flex. There was no stack trace in Flex or in Java. Just this error thrown from somewhere.

The only information I could gather from Charles was that it was a StackOverflowError. 

I only discovered this information by rolling back one commit at a time, then cherry-picking one file at a time, then one method at a time. Painful! 

If you run into this, I hope that I've included enough keywords that you find it quickly and don't waste a whole day like I did.