Defect Priority

I recently had the chance to overhear two groups arguing about the priority of a defect that had gotten out into the wild and caused some trouble. “It was a Priority 3 defect”…”It was still a Priority defect…” went the debate. In other words, this group had 3 levels of defect labeled Priority, with subtypes 1 through (at least) 3. What does Priority 3 mean, or Priority 1, for that matter? Evidently, it wasn’t clear enough.

A quick look on the internet turns up this page on priority. It goes into detail about the difference between priority and severity, but frankly, I don’t think it’s all that helpful of an explanation. Unfortunately, it also defines priority as ranging from P1 to P4. It then goes on to give explanations for what they mean. So why use the label if it’s meaning isn’t obvious? There is no justification and you should stop using it. Pick obviously meaningful names for your priority levels!

As the article states, the priority is usually a judgement call, and it was a wrong call that led to the discussion I overheard.

So what about severity. Surely, its meaning and derivation should be obvious. The article goes on to explain 4 levels of severity. Coupled with priority, that’s 16 different combinations. This is too much. You want to use as few severity levels as you can–start with 2; a primary use case is impacted, or a secondary use case is impacted. A primary use case is one of the 20% that generate 80% of the value. Everything else is a secondary use case. I know what you’re thinking: “But what about defects that cause crashes versus defects that…blah blah blah”. If a primary use case is impacted, what difference does it make? Creating too many buckets just masks the fact that you have a quality problem, and causes confusion for no real gain.

Next, look at isolation: Is this defect in production code? The answer to this question, coupled with the severity, should be enough to tell you what to work on next. The farther out a defect has escaped, the faster it should be fixed. By farther out, I mean that it is impacting other teams, with the customer being the “farthest out” a defect can escape.

Think hard before adding additional categories or making your prioritization more complicated, because confusion can be costly.

Advertisements
Posted in Software | Leave a comment

Safari Books as the next Google?

In previous posts I discussed using Safari books and the iPad and Android Text-to-speech (TTS) capabilities. Assuming Safari uses EPUB 3 format, it is possible to annotate the text with correct pronunciation, add and the contents are navigable. If Safari were to provide voice navigation and TTS, then you could interact a little with the book, skipping sections or paragraphs, etc. If you can add notes and highlights with your voice, then you can build up a collection of useful stuff from all the books you’ve read on Safari.

If you can search your notes, then even with minimal annotation capabilities in its reader, Safari Books could answer questions directly. “Safari. What are the phases of the Rational Unified Process.” could take you to a book you read last year. If you combined all of the public annotations from all Safari readers, you’d be able to directly answer questions using the content of Safari books. There is no reason this couldn’t be extended to their audio and video offerings as well.

Authors could annotate their books to facilitate question answering. Who knows? It might usher in a new book paradigm.

Posted in Software | Leave a comment

Safari part 2

Unfortunately, trying to use Text to Speech (TTS) on the Safari app doesn’t *quite* work on my Pixel, although it works fairly well on my latest gen iPad (fortuitously, yours truly cracked the screen of his old one and then destroyed the LCD trying to replace the screen…what was I thinking).

The TTS worked pretty well in my truck, although the iPad’s volume is a little low–easily fixed by plugging it into a car radio or, since my PoS old GMC pickup doesn’t have that, a beats pill speaker borrowed from my eldest!

Previously, I posted that I was setting aside more time for reading, and was trying to find a way to incorporate TTS for situations where reading wasn’t practical. Also, since a lot of the books I read contain technical jargon, I’d like a way to tell TTS how to pronounce certain words. There are also things it should skip–phrases like: references to other parts of the book, picture accessibility text, and visual navigation.

TTS would be greatly improved if I could control the TTS feature by voice. It’s easy to skip things when reading, and a similar feature is essential if O’Reilly really wants TTS to succeed. In fact, I think the navigation should be much more sophisticated than VCR controls.

Posted in Software | Leave a comment

Safari Part 1

Following up on my previous blog post, I’ve set aside more time for reading. I’m using the OReilly app on my iPad, and laptop-I have the app on my phone but I haven’t used it.

Watching the football playoffs this weekend, I turned the sound down and used the iPad’s text-to-speech (TTS) feature to read out a book. I set my iPad on the Ottoman, and I could read and listen along between plays, and look up to watch the actual game. I sped up the reader to something I could comfortably understand–still slower than just reading, and I wasn’t as focused on the material as I would be if I we just reading, but it worked. When I got to a point in the book that I wanted to bear down on, I paused until the next commercial. The reader is a little kludgy in terms of skipping uninteresting bits, but it does a nice job of actually reading. Next I’m going to try it in my car.

I had less luck using the text-to-speech functionality of my Google Pixel phone. From the little sample I had, the sound quality is great–better than the iPad, but I couldn’t figure out how to get it to work in any App. This is disappointing, because I carry my phone around all the time, so it would be really convenient. I’ll keep digging around.

Update: I managed to get Google TTS to work on my phone. Sort of. The OReilly app will not auto scroll while TTS is in operation, and stops after a page. I’ve set the font size as small as possible to compensate, but it’s a hack, not a solution.

Update: O’Reilly responding to my inquiry about TTS support and said no date but something they want to do. I’ll create a new post with my wish list.

Posted in Software | Leave a comment

Soul searching as citizenship

Patrick Chovanec argued on twitter that folks who hate President Trump need to do some soul-searching as to why the country was willing to elect him after 8 years of President Obama.

1. Liberals exclusively blame GOP cynicism for Trump. But what of the abject failure of public education to cultivate critical thinking, the erosion of family and community, the promotion of relativism and identity-based ideology?

Soul-searching is an admission that I might be wrong, which is difficult to do in realtime and/or in public. Social and political media are both realtime AND public, and then there’s Twitter, which add it’s own twist to the genre. If I want to soul search, I have to get out of real time, and that means a step away from social media. So, designated media-free days or hours seems like a start for me. Thinking about this further, if I am truly soul-searching, then I need to focus on my own ignorance and education, instead of blaming someone else, and that requires *some* media. So I need to find stuff that is worthwhile, and eliminate junk. That requires disciplined effort. If I want to do my part for the other items-family, community, identity (tribalism), etc., they each require similar diligence. Maybe I’ve just become too lazy?

I have a Safari account–I purchased one for everyone on my team–and I just downloaded the app to my phone and iPad. I also put the Safari app in my iPad home bar, so it’s easier to get to as the twitter app.

Posted in Software | Leave a comment

Testing Mean.js Controllers – Part 2

You need to test that only authorized users can perform certain functions, to help prevent AshleyMadison-like embarrassments. Plus, doing so will boost your code coverage metrics by hitting all of those auth failure branches.

For mean.js with passport, you normally have something like this in each controller:

var users =  require(app/controllers/users/authorization.server.controller);

You need to mock this controller, using the method I described in another post on mocking. Yes, there are lots of mocking libraries available, but I’m too lazy to learn them, and so far, my cheap method seems to work really well for me.

var users =  require(config.requireModules.authorization.version);

In your normal config file, such as production.js, you would have:

requireModules: {
   authorization: {
      version: 'app/controllers/users/users.authorization.server.controller'
   }
 }

Note how the authorization.version field points to the normal auth controller.
In test.js, your config file for testing, you would include the following:

requireModules: {
   authorization: {
      version: 'app/tests/mock_modules/mock-users.authorization.server.controller'
   }
}

Now, you’ve successfully mocked your auth module. That module looks like this:

'use strict';

/**
 * Module dependencies.
 */
var passFailFlag = true;

//For test setup
exports.passFail = function(pr) {
passFailFlag);
	passFailFlag = pr;
};
/**
 * User middleware
 */

exports.userByID = function (req, res, next, id) {
	if (passFailFlag) {
		req.profile = config.anonymousUser;
		next();
	} else {
		return next(new Error('Failed to load User ' + id));
	}
};

/**
 * Require login routing middleware
 */
exports.requiresLogin = function (req, res, next) {
	if (passFailFlag) {
		next();
	} else {
		return res.status(401).send({
			message: 'User is not logged in'
		});
	}
};

exports.validLogin = function (req) {
	//console.log('***validLogin*** passFailFlag= ' + passFailFlag);
	return passFailFlag;
};

exports.isAuthorized = function (req, roles) {
	return passFailFlag;
};

/**
 * User authorizations routing middleware
 */
exports.hasAuthorization = function (roles) {
	return passFailFlag;
};

This auth mock will let you dynamically set whether an auth test should pass or fail within an individual test!
Note that it exports a function that lets you set the value of a pass/fail flag that it uses to determine whether it passes or fails authorization.

Now, to test an authorization failure:

describe('taskJobs.Server.Controller.Test - Auth Fail Show Task Jobs', function() {
   it('should fail to return a list of jobs', function(done) {
      var response = buildResponse();
      var request  = http_mocks.createRequest({
         method: 'GET',
         url: '/taskJobs'
      });
      response.on('end', function() {
         if (response.statusCode !== 302) {
            done(new Error('Incorrect Status Code: ' + response.statusCode));
         } else if (response._getRedirectUrl() !== '/') {
            done(new Error('Incorrect Redirect: ' + response._getRedirectUrl()));
         } else {
            done();
         }
      });
      users.passFail(false);
      controller.list(request, response);
      users.passFail(true);
   });
})

Note how we set the passFail flag
An auth failure results in a 302 (redirect) statusCode, AND the redirect url will be (in this case, anyway), = ‘/’. You can look in your controller and see what you do for each method when an authorization failure occurs. See my previous post on controller testing to see the controller that fits this example.

Without the auth mock, you can use the bulk of this code to test any redirect, just set the expected redirect url value, and the url in the request, and this code should just work.

Posted in Software | Tagged , | Leave a comment

Testing Mean.js Controllers – Part 1

It’s time to test controllers. In this post, I’ll test a controller that returns a json response.

Step 1 is to install node-mocks-http.

Step 2 is to download jsdValidator.

In our sample controller test file, include jsdValidator and create a schema. The schema will match what should get returned by the real controller.

The relevant portion of our route looks like this:

var taskJobs = require('app/controllers/taskJobs.server.controller');
app.route('/taskJobs')
   .get(taskJobs.list);

In our taskJobs.server.controller, we have:

exports.list = function (req, res) {
 if (!users.isAuthorized(req, ['user'])) {
 res.redirect('/');
 return;
 }
 var restJobs = restValidatorService.restJobs;
 var scre = /^(\S+)\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s(\S+)/;
 var cronX;
 var output = [];
 _.forEach(taskJobs, function (job) {
 output.push({
 task: job.task.service,
 enabled: job.enabled,
 persist: job.persist,
 status: job.running ? 'running' : 'waiting',
 lastRun: job.startTimeStamp,
 processedMessages: job.processedMessages,
 errorMessages: job.errorMessages,
 commError: job.commError
 });
 });
 res.jsonp(output);
};

The controller is working if it responds with json output in a particular format. So, include jsdValidator in the controller test file, and create a schema that matches what the controller is supposed to produce. See jsdValidator for more info on how it works and how to build schemas.

The relevant portion of taskJobs.server.controller.test.js looks like this:

var jsd = require('app/services/jsdValidator/jsdValidator');
var streamSchema = {
	'Type': 'Array',
	'Optional': false,
	'Values': [
    {
      'Type': 'Object',
      'Optional': false,
      'Attributes': [
        {
          'Name': 'task',
          'Description': '',
          'Type': 'String',
          'Optional': false
        },{
          'Name': 'enabled',
          'Description': '',
          'Type': 'Boolean',
          'Optional': false
        },{
          'Name': 'persist',
          'Description': '',
          'Type': 'Boolean',
          'Optional': false
        },{
          'Name': 'status',
          'Description': '',
          'Type': 'String',
          'Values': ['running','waiting'],
          'Optional': false,
        },{
          'Name': 'lastRun',
          'Description': '',
          'Type': 'String',
          'Optional': false,
          'CanBeNull': true
        },{
          'Name': 'processedMessages',
          'Description': '',
          'Type': 'Number',
          'Optional': false
        },{
          'Name': 'errorMessages',
          'Description': '',
          'Type': 'Number',
          'Optional': false
        },{
          'Name': 'commError',
          'Description': '',
          'Type': 'Number',
          'Optional': false,
          'CanBeNull': true
        }
      ]
    }
  ]
};
describe('myTasks.Server.Controller.Test - Show Tasks', function() {
 it('should return a list of tasks', function(done) {
    var response = buildResponse();
    var request = http_mocks.createRequest({
       method: 'GET',
       url: '/myTasks'
    });
    response.on('end', function() {
       if (response.statusCode !== 200) {
          done(new Error('Incorrect Status Code: ' + response.statusCode));
       } else {
          jsdv = new JSDValidator({Schema: myTaskSchema});
          var isValidated = jsdv.Validate(JSON.parse(response._getData()));
          if (!isValidated) {
             done(new Error('Invalid Response: ' + jsdv.Error));
          } else {
             done();
          }
      }
    });
    controller.list(request, response);
 });
})

In the test controller, set up a few parameters:
First, the url needs to match the url in the route file for the action in the controller that you want to test.
Second, at the bottom, where it says: controller.list(request, response), .list is the actual method that you want to test in the controller. It has to match the method that is in the route file.
Third, modify the ‘describe’ and ‘it’ descriptions, and you’re done. It’s pretty easy to clone this code to test all of your controllers.

Posted in Software | Tagged , | Leave a comment