Month: March 2017

Scrum: Survival guide for devs

Scrum: Survival guide for devs

Working as a dev in Scrum can be really hard, let’s face it. With constant deliveries and no time for tech improvements, it is easy to feel like in crazy race to nowhere. These are the facts that I found myself most annoying, and how I try to deal with them.

#1 Management not involved

Very hard one. If management is not involved, you will not be doing really Scrum. And sell Scrum to management is impossible it you do not support it with metrics or very un-questionable success stories. I have read stories about changing processes without stating that you are going on an Agile direction, and when the changes are made, reveal the intention behind. I think is not the normal thing: if mangament does not want to hear about Agile, probably is beacuse it is the type of management that does not allow teams to change their processes easily. But if you feel you can makes changes, but your company is just against Scrum/agile thingie, maybe it makes sense to try this approach.

 #2 Pressure -all the time

Delivering tested features in 15-days cycles is exhausting, and if there are hard deadlines, dealing with management while delivering can put devs under a lot of pressure. You have to estimate carefully to avoid throwing yourself to the lions, and to get used to renegotiate the scope of the stories with the PO. If you came across some undefined behavior, do your best to create a follow-up story for that use case and concentrate on the originally defined scope. If you end with some extra hours at the end of the sprint, you can pick another story (or read a blog post, maybe ^^). QAs are your friends. Involve them in the discussions with the PO, to keep them aware of all the story details and avoid any misunderstandings that can delay the acceptance phase.

#3 Micrometrics & violent transparency

You will be analyzed at the end of each sprint (or even more often) and compared to your teammates and to the rest of Scrum teams. It is ok. Burndowns are more visual than the percentages we gave in the old times, but it is the same. Just try to raise your problems/blockers early (in the daily or even before if it is critical). If you think that you are regularly performing poorly, talk with the Scrum Master. He or she probably has clearer view of the big picture and can give you some useful insights.

#4 The long-term goal is missing

With the backlog changing all the time and the pressure to always keep your eyes on the next tiny story to deliver, it can be hard to see the big picture or the long term goals of the project. Get involved in the plannings and retrospectives and ask the PO to provide and update a roadmap. When possible, do attend the demos that include stakeholders or final users, or at least try to get feedback from the assistants.

#5 No career plan / no expertise recognition

Scrum does not have roles. Everyone in a Scrum Team is just that: a Scrum Team member. In addition to this, you have to give reports each day, which, apart from killing creativity, feels a little bit like being constantly observed. And this usually happens only in the early stages of a developer career, although usually you never put a team of juniors to work in Scrum. This “junior feeling” usually depends on how the Scrum Master filters the pressure and how much ownership of the increment implementation he gives to the team. Try to win the leadership of the areas that you master: take the opportunities of giving guidance to the rest of the team in those areas to become a reference.

#6 – Technical debt

It is really frustrating to see technical debt grow as the sprints pass, and this can be a hard one to fight for if management or PO really do not understand/care about the impact of poor code quality. If the team and the PO can reach an agreement of a discrete amount of story points that are destined each sprint to code improvements, that would be great. These story points can be assigned to each developer, leaving into his hands the refactoring of the code that he is delivering, or you can assign the whole amount to an experience dev and let him refactor and re-test complex component or implement some transversal improvements. Also, it is very important to maintain a good level of Unit testing coverage and to add a static code analysis as part of the integration build.

 

***

Waterfall is broken. I really like Scrum and I think some of the ideas of the Scrum Guide are very useful, but I think we can do better and with less hypocrisy.

 

Backbone + React

Backbone + React

Some time ago a teammate and I implemented some POC with Backbone and React and from the beginning I thought it would be interesting to combine these two frameworks, as Backbone only provides a lightweight base for scaffolding the app and React seems a very powerful library to build the UI. But the first implementation I tried made use of JSX, from React Tools, which has been deprecated in favor of Babel (Facebook’s React Blog).

This post documents my second attempt of integrating Backbone with React in a web application that uses RequireJS to define modules and Grunt to preprocess the JSX files and wrap everything up.

Backbone + React example I

You can download the full source code of this example at Github.

Backbone + React example I

 

This is the folder structure. The “src” folder contains all the source files, that will be proccessed by a Grunt build script, putting the resulting file structure inside “dist” folder.

 

 

 

 

 

Ok, let’s see the code…

  <body>
        <script data-main="js/main" src="../node_modules/requirejs/require.js"></script>
  </body>    
  • index.html: Will only load require.js and refers to main.js as our application’s entry point. All the HTML content of the different views of the app will be located in React components. We will compose these views with Backbone.
'use strict';
require.config({
    // shim: scripts that do not call define() to register a module
    shim: {
        underscore: {
            exports: '_'
        },
        backbone: {
            deps: [
                'underscore',
                'jquery'
            ],
            exports: 'Backbone'
        },
        backboneLocalstorage: {
            deps: ['backbone'],
            exports: 'Store'
        }
    },
    paths: {
        'jquery': '../../node_modules/jquery/dist/jquery',
        'underscore': '../../node_modules/underscore/underscore',
        'backbone': '../../node_modules/backbone/backbone',
        'text': '../../node_modules/requirejs-text/text',
        'react': '../../libs/react',
        'ReactDOM': '../../libs/react-dom'
    }
});

define([
    'backbone',
    'views/MainView'
], function(Backbone, MainView) {
    'use strict';
    return Backbone.Router.extend({
        init: function() {
            window.app = {};
            window.app.vent = _.extend(Backbone.Events);    
            new MainView();
        }            
    });
});
  • main.js: This file contains the RequireJS configuration. The shim field is used to configure dependencies for scripts that do not call define() to register a module. The paths field contains shortcuts to the different libraries that we will use. Backbone has underscore and jQuery as dependencies, so we are loading all of them, and React on its side is split into React and ReactDom.
define([
    'underscore',
    'backbone',
    'views/HeadView',
    'text!templates/main.html'
], function(_, Backbone, HeadView, mainTemplate) {
    'use strict';

    return Backbone.View.extend({
        el: 'body',
        template: _.template(mainTemplate),
        events: {},
        initialize: function() {
            this.render();
        },
        render: function() {
            this.$el.html(this.template({}));
            this.postRender();
        },
        postRender: function(){
            this.headRegion = this.$('#head-region');
            if (!this.headView) {
                this.headView = new HeadView();
            }
            var props  = {title: 'Header Title'};
            this.headView.render(this.headRegion, props);    
        }
    });
});
  • MainView.js: Is a Backbone View that will use a standard way of rendering HTML templates with underscore & text. With this configuration, we can use either React or underscore to render the HTML corresponding to a Backbone View. After MainView renders its contents, it will render the React component inside the header DOM element (#head-region), passing the title property to the component.

 

define([
    'backbone',
    'ReactDOM',
    'react',
    'components/HeadComponent'
], function(Backbone, ReactDOM, React, HeadComponent) {
    'use strict';

    return Backbone.View.extend({
        events: {},
        initialize: function() {},
        render: function(el, props) {
            //Create React Element based on HeadComponent.jsx
            this.reactElement = React.createElement(HeadComponent, {
                view: this,
                title: props.title
            });
            //Render element into DOM element passed from parent view
            ReactDOM.render(this.reactElement, el[0]);
        }

    });
});
  • HeadView.js: Here is when we start using React. The HeadView is a Backbone View that receives a DOM element as parameter in its render method. We will call React.createElement() passing to the call the JSX component and the title we received from MainView. Once the element has been created, we call ReactDOM.render() to actually insert the rendered contents into the DOM.

 

define([
    'react',
], function(React) {
    'use strict';
    return React.createClass({
    render : function() {
        return (
            <div>
            <span id="header-title">{this.props.title}</span>
            </div>
        );
    }
  });
});
  • HeaderComponent.jsx: It is a simple header that will take a string named “title” as parameter and render a span with the received string. The props field of a React element is populated with the properties passed to the React.createElement() call that is made to create that element.
module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);
  grunt.loadNpmTasks('grunt-execute');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-express');  

  grunt.initConfig({

    clean: ["dist"],

    babel: {
      options: {
        sourceMap: false,
        modules: "common"
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'src',
          src: ['js/components/*.jsx'],
          dest: 'dist',
          ext: '.js'
        }]
      }
    },

    copy: {
      main: {
        files: [{
          expand: true,
          src: ['**/**', '!**/components/**'],
          dest: 'dist/',
          cwd: 'src',
          filter: 'isFile'
        }],
      },
      libs: {
        files: [{
          expand: true,
          src: ['libs/**'],
          dest: 'dist/'
        }],
      },
      node_modules: {
        files: [{
          expand: true,
          src: [
            'node_modules/requirejs/require.js',
            'node_modules/jquery/dist/jquery.js',
            'node_modules/underscore/underscore.js',
            'node_modules/requirejs-text/text.js',
            'node_modules/react/**',
            'node_modules/react-dom/dist/react-dom.js',
            'node_modules/backbone/backbone.js'
          ],
          dest: 'dist/'
        }],
      }
    },
    express: {
      all: {
        options: {
          port: 3000,
          hostname: 'localhost',
          bases: ['./dist'],
          livereload: true
        }
      }
    },
    watch: {
      scripts: {
        files: ['src/**/*.js', '!src/js/components/**'],
        tasks: ['copy'],
        options: {
          spawn: false,
          livereload: true
        },
      },
    }

  });
  grunt.registerTask('server',['express','watch']);
  grunt.registerTask('default', ['clean', 'copy', 'babel', 'server']);

};
  • gruntfile.js: A simple Grunt script to copy all the source files to “dist” folder, process the JSX files with Babel and open a light node server.

 

Next steps I plan to take are to add some user interaction, handling the events with React and implement the Backend calls with Backbone Models. And Webpack maybe.

Still there? You are awesome <3