Long Hours Culture – Agile Anti Patterns

Long Hours Culture – Agile Anti Patterns

If you have worked in IT for a while you see the same things happen over and over again. When you have worked in IT for a few more years you start questioning the things you see and wondering if there is another way. Given a few more years you’ll be the one shaking things up so the old norms are consigned to the dustbin of history.

The topic I’m touching on today is working practices for software developers or more precisely it is a challenge to the long hour’s culture often seen in software development.

There was a time (and it probably still happens today) where you simply didn’t leave work until after the boss did. They leave at 8pm so you’ll be leaving at 10 past. People would work 10, 12, 14 hour days so they looked like the important one, the busy one, the one that could be depended on. How many times have you heard people recount the 50 or 60 hour weeks they have worked and hold it aloft as a badge of honour.

Using these old terms, I might be considered a boss. Well I’m usually the oldest on a team but I certainly don’t consider myself a boss. Do I expect people to leave after I do? – no I don’t! Instead I judge people on results and how they interact with their team mates. Not on how much stamina they have.

I have likened the mental effort of software development to doing an exam. You’re doing complex mental puzzles for many hours each day. Having done this myself, I know that if I work flat out for 6 – 7 hours I’m mentally spent. After that I’m in neutral. I might be trying but nothing much is happening. Many studies have demonstrated that most people’s mental capacities are similar. If you tell me that you have been doing 12 or more hours a day I question what you actually have been doing in that time or whether that time would have been better spent recharging for the next day.

Lean and Agile tell us to use prioritisation and work in progress limits to set a predictable and sustainable pace. This means that the 6 – 7 hours mental capacity each developer spends each day is always on the most important thing. There is no stress and no pressure. You are always working on the most important thing. I’m not saying you only work 6 – 7 hours. Instead you are free to use the time outside of that for what you want, whether that is a side project, training or otherwise keeping yourself sharp.

Unfortunately, development teams don’t work in a bubble. There are often arbitrary deadlines which need to be dealt with. Before I move on to that, it is worth digressing for paragraph to consider why Agile teams find themselves with deadlines.

pizzas
Too familiar?

When these deadlines come up it is important to recognise where they are coming from. In my experience, it is always someone outside the team, not working in your sustainable pace each day. It might be a sales person who has committed to a customer that feature X will be ready by Y. It might be an external supplier who is expected to integrate with your software by a given date. The commonality is that they don’t know what the pace of the team is and they have plucked a date from thin air without any further context or understanding. They have made a commitment on your team’s behalf.

So, the team has to knuckle down and get on with it. The first thing to do is reprioritise. Focusing on the new commitment might still be achievable if all other things in the backlog are delayed. If not than the team should agree between themselves what the new working arrangement should be. It is a team decision and they should resist the urge to be dictated to from outside. This can be very emotionally charged as the external stakeholder may see the team not caring. What is really happening is the stakeholder has put their neck on the line and now they what everyone else to pull out all the stops to save them.

Everyone should recognise that as hours increase quality suffers. Notice I didn’t say “may suffer”. Quality will go down. Mistakes will be made. One strategy to minimise this is to ensure each team member has some opportunity to rest and recover. Not only is it important for their own mental state, a fresh pair of eyes are more likely to identify mistakes early.

Doing this however it a symptom of a wider problem. Ideally resolving it might be in your control but more often than not, it is cultural and is much harder to change.

Regardless, my mind is set. You can keep your evenings fuelled by pizzas and your days off in lieu for weekend work. All I want is a sustainable pace.

 

 

 

Advertisements

AngularJS, Protractor and TeamCity – Part2

AngularJS, Protractor and TeamCity – Part2

In my last post, I covered the basics for creating a protractor test suite to test an AngularJS application. The next step for all self-respecting developers is having the suite running as part of a CI/CD pipeline. I promised to outline how you might do this with TeamCity. Before I do that, I want to cover some of the stages that you might miss.

Writing a protractor test suite boils down to writing JavaScript. As with any development effort this might result in good code or it might result in a ball of mud. Whilst the success of the test suite is dependent on the quality of the tests, good automated suites are also dependent on the quality of the code that makes them up. The automated test suite will run regularly, so it needs to be reliable and efficient. The software will evolve, it will change, so the tests will need to change too. Your test code needs to be simple and easy to maintain. The software principles that apply to production code such as SOLID, should also apply to your test code.

Testing Patterns

A typical pattern used when writing automated end 2 end tests is Page Objects. The idea is that the complexity of driving a particular page is removed from the test itself and encapsulated in a page object. The page object has intimate knowledge of a page in the application and exposes common features that the tests will need. The pattern reduces the amount of repeated code and provides an obvious point of reuse. The page object evolves at the same rate as the underlying application functionality. Done correctly the tests themselves become decoupled from changes in the application.

As the page object and the underlying page end up in step it becomes natural for the developer and the tester to work closely. The developer helps the tester understand the capability of the page. The tester then builds a page object to expose this functionality to tests. Done correctly this collaboration drives out an application that is easy to test. As new functionality is created the tester can influence the developer to write the page in a way that is easy for them. One common area is the use of selectors to find elements within the page’s DOM.

Tests written after a page is finished often result in complex and/or unreliable selectors. Complex XPath expressions or custom logic to search the DOM tree for the correct element is common. Tests written like that become hard to maintain. On the other hand, if the tester and developer work together and importantly, the developer understands how their work will be tested, then pages that are easy to test are the result.

Testing the Tests

Writing test code starts to look and feel like writing production code. Similar tooling should be in place. Don’t let your testers struggle with basic editors when your developers are using fully featured IDEs with syntax highlight and intelli-sense. Testers working with protractor should use a decent editor such as VSCode, Sublime or ATOM with a compliment of JavaScript plugins. In-particular use linting tools to ensure that the JavaScript written for tests matches similar style guidelines as the main application AngularJS code.

You should also ensure that it is easy to test your test. This link demonstrates how to set up VSCode to run a test specification by hitting F5. This article itself advertises that you are able to debug protractor tests. Whilst I have managed to hit breakpoints in my tests the debugging experience has fallen well short of my expectation. I have not had the time to investigate further.

Team City Integration

The final step of this is to have your test suite running as part of your CI/CD pipeline. Protractor is a e2e testing framework. End 2 end tests may take some time to execute. Large test suites may take several hours. CI builds should take minutes not hours so it is advisable to run these types of test suite overnight. Daily feedback is better than no feedback at all. If you have a deployment build that deploys to a specific environment each night you could tag execution of the test suite to the end of that. If you deploy to an environment less regularly you can still run the suite each night.

TeamCity happens to offer comprehensive statistical analysis of repeat test runs. It provides trends that show if particular tests are getting slower and it will also highlight tests that are flaky – i.e. ones that sometimes work and sometimes fail even if nothing has changed.

The simplest way to integrate your suite into TeamCity is to use the TeamCity Jasmine reporter. You can add the reporter to your conf.js like this. Don’t forget to add it your package.json file.

exports.config = {
    framework: "jasmine2",
    capabilities: {
        browserName: "chrome"
    },
    onPrepare() {
        let jasmineReporters = require("jasmine-reporters");
        jasmine.getEnv().addReporter(new jasmineReporters.TeamCityReporter());
    },
};

In the last post, I created a gulp task to execute the suite. The final step is to add a build step to execute it.

protractor1

I have a npm install step that ensure all the dependencies required by the tests are downloaded. I’m then executing gulp e2e to run the test.

You can see this is working on the build summary. You can see a count of passing and failing tests.protractor2

As your test suite is outputting results just the way TeamCity likes them you can drill into your tests and get all sort of useful stats, like this.

protractor3

AngularJS, Protractor and TeamCity

AngularJS, Protractor and TeamCity

The go to solution for creating automated end to end tests when building AngularJS applications is Protractor. In this post, I am not going to explain how to write tests using Protractor. Instead I’m going to cover some of the things I discovered when trying to integrate a suite of Protractor tests into a TeamCity based CI/CD pipeline.

Protractor Basics

The following article cover the basics of Protractor. This formed the basic understanding that I needed to work out where all the moving parts were and therefore work out how best to integrate into a CI/CD pipeline.

http://www.protractortest.org/#/

Protractor is a node module so I’ll assume that you have nodejs installed on your development machine. Once you have that you need to get protractor using

npm install protractor -g

Protractor relies on drivers for the various web browsers. It will execute your E2E test scenarios directly in the browser so this bit is important. The drivers in turn use Selenium, a common testing framework.

That is a lot of moving parts I hear you say. Luckily it is relatively simple to get this up and running. Once you have Protractor ensure you have all the latest webdriver bits

webdriver-manager update

This ensures that all the latest webdriver and selenium versions are downloaded and configured correctly. The final step is to start everything up. You can do that with

webdriver-manager start

You may hit your first hurdle at this point. Selenium is a Java based solution and as such requires Java to be installed on your development machine. So if you have a problem at this stage go off to Oracle’s site, download Java and install it. You’ll need the latest JDK.

In order to continue you’ll need an example test spec, spec.js. I used this one which is part of the Protractor tutorial.

describe('Protractor Demo App', function() {
    var firstNumber = element(by.model('first'));
    var secondNumber = element(by.model('second'));
    var goButton = element(by.id('gobutton'));
    var latestResult = element(by.binding('latest'));
    var history = element.all(by.repeater('result in memory'));

    function add(a, b) {
         firstNumber.sendKeys(a);
         secondNumber.sendKeys(b);
         goButton.click();
     }

     beforeEach(function() {
         browser.get('http://juliemr.github.io/protractor-demo/');
     });

     it('should have a history', function() {
         add(1, 2);
         add(3, 4);

         expect(history.count()).toEqual(2);

         add(5, 6);

         expect(history.count()).toEqual(3); // This is wrong!
     });
});

You also need a configuration file, conf.js. This is the one used in the tutorial.

exports.config = {
    framework: 'jasmine',
    seleniumAddress: 'http://localhost:4444/wd/hub',
    specs: ['spec.js']
}

To run this selenium must be running locally exposing an endpoint on port 4444. But if you remove the line starting seleniumAddress… guess what… an instance is started for you automatically. With the modified conf.js file you should be able to run your test with the following command.

protractor conf.js

This should work if

  1. You have installed protractor globally
  2. You have ensured that the web drivers and selenium are updated.
  3. And all the versions of protractor, your browser and its particular web driver are all aligned

When I was trying to make an old implementation of a Protractor test suite CI/CD ready. It turned out that it was using an old version of protractor so updating the web drivers downloaded old versions. The machine I was testing this on happened to have an old version of chrome so all seemed to work. This subsequently failed when other people tried because they were using the latest versions of chrome. An upgrade to protractor fixed that but then caused problems for people stuck on older versions.

You might think why are people on old versions of chrome? Blame centralised management of software in big organisations”

So the lesson I learned here was to always start with the latest versions, even when picking up older implementations. The version of the framework and the browser matter.

Making this CI/CD Friendlier

With the CI/CD pipeline I was working with I didn’t want to have an instance of the webdrivers and Selenium running constantly. Neither did I want to have to manually start up the web driver on each build. As Gulp was being used for other purposes I happened on gulp-angular-protractor which provides a wrapper for all of these things. Effectively it updates the webdrivers and starts them for you and then clears them down when you have finished. This meant that I could have a single gulp task that executed my test suite.

A good build is self-contained and minimises dependencies on what is installed on the build server. The packages I need are installed locally. In order to create a package.json file install the required packaged like this

npm install protractor -save-dev
npm install gulp-angular-protractor -save-dev
npm install gulp -save-dev

Although the final step installs gulp locally it also needs to be installed globally too. I have no idea why but it does. You can then create a Gulp file like this one

let gulp = require("gulp");
let gulpProtractorAngular = require("gulp-angular-protractor");

gulp.task("runtests", callback => {
    gulp
        .src(["myspec.js"])
        .pipe(gulpProtractorAngular({
            configFile: "protractor.conf.js",
            debug: false,
            autoStartStopServer: true
        }))
        .on("error", e => {
            console.log(e);
        })
        .on("end", callback);
});

Lets break this down.

First, I’m bringing in gulp and gulp-angular-protractor so I can use them later. Next, I’m creating a gulp task called “runtest”. The rest basically says execute conf.js with spec.js as the test spec file.

As this point you have a basic spec and conf file that can be executed from a Gulp task. This is enough to start building some real test specs and checking them out. Come back next time to see what you need to do to integrate this properly with TeamCity.