Agile Software Development, Estimation

We are agile, we use story points… why?

One of the most shocking and at the same time obvious aspects of Scrum is the usage of Story Points to measure the effort to be done. It’s shocking because the teams usually are more familiar with time measures but, once one understands its nature, it’s one of the most obvious aspects of the Scrum methodology.

Time/Effort vs Time/Distance

In a classical fashion based on concepts like the Project Management Quality Triangle, the quality of a project has to be evaluated from three constraints:

PM Quality triangle

So, if we want to deliver the best quality on a project because the quality is not negotiable, as one can infer from the agile manifesto, we must control those three constraints. Even though the scope and the cost are usually determined by the needs of whoever asked the project and his/hers budget, the time is usually something estimated by the somebody who will perform the effort. This will be a problem as the sooner the later somebody will ask for time estimations to the team in charge, and the development team is usually good making software but quite bad in futurology ;-). That’s one of the reasons why Scrum proposes to measure the effort, and calculate the time in basis of the team speed (aka. how much effort can be delivered in a chunk of time).

Even though we have units for the time (seconds, hours, weeks, etc) and for the costs (euros, dollars, bitcoins, etc), there is no clear unit for the effort. For some projects the effort could be “number-of-houses-to-build” but in the case of software development ones it is strongly hard to have a good unit. Luckily, Scrum proposes a really useful unit to measure the effort, the story points. This unit is quite tricky, as one needs to work a few before it is clear, but once it is correctly defined, it solves problems that can be considered superficial and some deep problems associated with the measure of effort.

At the end, and as stated by Mike Cohn in The main benefits of story points, the story points must be seen as the meters/yards of effort, once we understand them in this fashion, we’ll start to be deeply agile.

Main problems of estimating using effort instead of time

Obviously, estimating in basis of effort it’s not easy and from my point of view there is a couple of disadvantages about using story points:

  • We need some background to have a way to measure story points. As stated in some articles (e.g.- Agile Estimation in 8 steps) it is really useful to do some iterations before we can measure Story Points properly this can impact the Product Owner plans, as initially the unit won’t be totally reliable.
  • It’s difficult for the Product Owner  to understand them. Even more difficult if the Product Owner does not have technical background. They are a totally abstract unit and it’s not easy to understand what a Story Point means and how to manage it (and the expectations it generates).

Why we should embrace and love story points

On the other hand, there are several benefits which encourage us to totally adopt them, or at least give them a try. Furthermore I’ll add a couple of interesting (and non-obvious) facts about using Story Points:

  • They drive the team to a better work analysis, as everybody in the team has to compare something deeply in order to give a clear proportion comparing with another piece of software.
  • The conduct to proper roles assigned, the Product Owner can be responsible of timing and to better manage the stakeholders expectation. Meanwhile, the team can take control of effort, not time (as they do not manage resources). Finally, the Scrum Master can mix up everything using the speed, and agile can flow smoothly.

 

 

Advertisements
Standard
Agile Software Development

When does agile fail?

Failure vs Success

The background

I’ve been working under the agile principles during the last 4-5 years. I was used to work under the waterfall principles and methodologies, so I must admit that at the beginning it wasn’t easy. It was quite hard to forget about long-term plans, detailed designs and organizational hierarchies, however after a few time I discovered some enlightening facts that made me love the four agile principles from the Agile Manifesto:

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan

In fact, during this time I’ve been in several situations in which I’ve been able to apply both side of every principle and undoubtedly I’d rather the agile way. However, I only have a narrow view of the world’s overall software development state. So I’ve thought that maybe the agile way is not the panacea, that’s why I decided to do some research on the agile success ratio.

The reality

Once I convinced myself that perhaps agile was not so cool and good as it seemed to be I started digging into the Internet looking for some references. After a few searches I reached some interesting articles like the following:

In fact, it’s a list of 20+ reasons why agile fail, and many of them come from some of the software market renowned sources like Thoughtworks, so I thought that maybe agile was not so great as I experienced. Moreover, if one does a deeper analysis it is easy to detect some common patterns on agile failure:

  • Fail by people: In this pattern agile fails because of the people. Perhaps our people is not properly trained to embrace agile or maybe we have some reluctant members in our teams, whatever the case may we are not ready to embrace agile and this is difficult to solve meanwhile we have a project in hands.
  • Fail by organization: This is the next level of failure. In this case our people is somehow prepared but, the company environment is not. Maybe the top management does not promote agile (or at least tolerate its existence) or perhaps our organization structure is not agile friendly (physically dispersed team members, non-agile company values, etc), in any of these cases we shall remove these obstacles before starting a real project with agile, or the success of the project will be affected.
  • Fail by communication: This is the third level of failure. Once we have removed the people and organization obstacles we are able to start being agile but, what happens if we are not ready to communicate with our team members in an adequate manner? On the other hand, what will happen if we or our customer is not prepared to work in a continuous flow of feedback? Both situations will negatively impact the success of our agile transformation.

By the way, I think there are a couple of situations that must be considered when we talk about agile failure:

  • Fail by contract: The first extra bonus level of the failure (and the more obscure). From my point of view, this failure mainly applies when agile is used to deliver a service instead of a product so, what will happen if everybody is ready to embrace agile, our organization is also prepared and all the stakeholders are willing to be agile but we haven’t checked our contracts? Maybe everything ends fine but if something goes wrong everybody will be checking the agreed contracts in order to decide who pays the bills and, arrived to this situation, we’ll have inherently failed as no value has been delivered.
  • Fail by concept: Has it sense to deliver a software in an agile manner when the specifications are clearly defined from the beginning? For instance, has it sense to be agile while developing an airbag controlling software? or a plane autopilot software? Maybe it has sense, but from my point of view we can deliver the same value without agile, so it’s up to us to decide whether to change or not.

My own conclusion

From my point of view agile solves the most of the problems in software development and frankly it does software development more human. However, we must take into account that it is not smooth and easy to embrace than one can initially imagine, so we must do a good analysis of how we’ll embrace it in order to be agile doing agile 🙂

 

Standard
Android, Java

Failed to find target android-18… D’oh!

One of the first problems I’ve found on my Android adventure is to configure the environment. Although there are lots of tutorials and IDEs to do it for me, I’ve decided to start building my “toys” with the newest building tool, Gradle (http://www.gradle.org).

The first impressions with gradle were good, however once I started to configure the project as Android application, a strange issue started to appear in my console, an error telling me that the compiler failed to find the target android:

My Computer:project-dir user$ gradle assemble

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':mobile-app:packageDebug'.
> failed to find target android-18

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 6.56 secs

This started to happen once I introduced the android plugin in the gradle config file:

apply plugin: 'android'

android {
compileSdkVersion 18
buildToolsVersion "18.0.0"
}

dependencies {...}

So, after googling a bit, I discovered that the problem was that I wasn’t pointing to the sdk version I had installed, so I opened /adt/sdk/tools/android:

android_sdk_manager

And, change the buildToolsVersion with the installed version:

apply plugin: 'android'

android {
compileSdkVersion 19
buildToolsVersion "19.0.3”
}

dependencies {...}

Once I did this everything started to work fine. Easy, simple and… obvious, d’oh!

Standard
Uncategorized

Java concat files

Snippet to concat several files into a new one with Java:

import org.apache.commons.io.IOUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

...

OutputStream destinationStream = null;
InputStream is = null;

File fileDir = new File("path_to_directory");
File destination = new File("path_to_destination");

try {
   destinationStream = new BufferedOutputStream(new FileOutputStream(destination));
   for (File file: fileDir.listFiles()){
      try{
         is = new BufferedInputStream(new FileInputStream(file));
         IOUtils.copy(is, destinationStream);
         destinationStream.write("\n".getBytes()); //Separate files
      } finally {
         IOUtils.closeQuietly(is);
      }
   }
} finally {
   IOUtils.closeQuietly(destinationStream);
}

Enjoy it!

Standard
Java

JSF + Primefaces 4 + Spring 4 + Hibernate 4 + Maven Multi-module = JTemplate

Introduction

In the last days I’ve been working on a Java project template. After reading some inspiring articles, I’ve decided to mix up some of the concepts explained on them with other nice features which they don’t cover, and adding some improvements.

The basics

The idea is to present how to structure a Java multi-module project using maven. So, the project is divided into the following parts:

  • main: It contains the main files to build the application, the “Parent” pom
  • persistence: The module with the data access components
  • common: The inter-module common parts will go here. E.g.- Parsers, Utility classes, etc
  • business: Models the business logic of our application
  • web: Where the views and the webapp structure will be modeled

Moreover, the project code will be configured with as much annotations as possible, for two reasons, avoid to locate the configuration files in deeply hidden places, and to take advantage of the compliance of Spring and Hibernate with the JSR-330 and JSR-317, respectively.

Multi-module with Maven

The project uses the multi-module feature provided by Maven. It is defined in a “Parent” pom file which is located into the main project, and as we’ll see later it has to be located into the root directory (where all the projects are located). The parent looks like:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<groupId>com.mm.jtemplate</groupId>
<artifactId>jtemplate</artifactId>
<version>0.1-SNAPSHOT</version>

<modules>
<module>jtemplate-main</module>
<module>jtemplate-common</module>
<module>jtemplate-persist</module>
<module>jtemplate-module</module>
<module>jtemplate-web</module>
</modules>

<properties>
<spring.version>4.0.0.RELEASE</spring.version>
</properties>

<dependencies>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>

<!-- Spring 3 dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- Log4j library -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.7</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<server>tomcat</server>
<path>/jtemplate</path>
</configuration>
</plugin>
</plugins>
<finalName>jtemplate</finalName>
</build>
</project>

The file is structured in two blocks, the first one is used to identify the modules. The second block refers to the dependencies and the needed configuration stuff to construct the project.

How-to build

There is only one required step to be done before building the project with maven normally, copy the “Parent” pom from the main project to the root directory:


cp ./main-module/parentPom.xml ./pom.xml

After this step is done, the project can be build normally with the common maven command:


mvn clean install

And, after a few seconds everything has to be build and on fire!

The components

Entity


package com.mm.model.domain;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@javax.persistence.Entity(name="Entity")
public class Entity {

 @Id
 @GeneratedValue
 @Column(name="id")
 private int id;
 @Column(name="attribute")
 private String attribute;

 public Entity(){}

 public Entity(int id, String attribute) {
 super();
 this.id = id;
 this.attribute = attribute;
 }

 public int getId() {
 return id;
 }
 public void setId(int id) {
 this.id = id;
 }
 public String getAttribute() {
 return attribute;
 }
 public void setAttribute(String attribute) {
 this.attribute = attribute;
 }
}

EntityDAO


package com.mm.model.dao.impl;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.mm.model.dao.IEntityDAO;
import com.mm.model.domain.Entity;

@Named
public class EntityDAO implements IEntityDAO {
 @Inject
 private SessionFactory sessionFactory;

public SessionFactory getSessionFactory() {
 return sessionFactory;
 }

public void setSessionFactory(SessionFactory sessionFactory) {
 this.sessionFactory = sessionFactory;
 }

public void addEntity(Entity entity) {
 Session session = getSessionFactory().getCurrentSession();
 Transaction trans = session.beginTransaction();
 session.save(entity);
 trans.commit();
 }

public void deleteEntity(Entity entity) {
 Session session = getSessionFactory().getCurrentSession();
 Transaction trans = session.beginTransaction();
 session.delete(entity);
 trans.commit();
 }

public void updateEntity(Entity entity) {
 Session session = getSessionFactory().getCurrentSession();
 Transaction trans = session.beginTransaction();
 session.update(entity);
 trans.commit();
 }

public Entity getEntity(int id) {
 Session session = getSessionFactory().getCurrentSession();
 Transaction trans = session.beginTransaction();

 List<?> list = session
 .createQuery("from Entity where id=?").setParameter(0, id)
 .list();

 trans.commit();
 return (Entity) list.get(0);
 }

public List<Entity> getEntities() {
 Session session = getSessionFactory().getCurrentSession();
 Transaction trans = session.beginTransaction();

 @SuppressWarnings("unchecked")
 List<Entity> list = (List<Entity>) session.createQuery("from Entity").list();

 trans.commit();
 return list;
 }

}

EntityService


package com.mm.module.one.impl;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.springframework.transaction.annotation.Transactional;

import com.mm.model.dao.IEntityDAO;
import com.mm.model.domain.Entity;
import com.mm.module.one.IEntityService;

@Named
@Transactional(readOnly = true)
public class EntityService implements IEntityService {

@Inject
 IEntityDAO entityDAO;

@Transactional(readOnly = false)
 public void addEntity(Entity entity) {
 getEntityDAO().addEntity(entity);
 }

@Transactional(readOnly = false)
 public void deleteEntity(Entity entity) {
 getEntityDAO().deleteEntity(entity);
 }

@Transactional(readOnly = false)
 public void updateEntity(Entity entity) {
 getEntityDAO().updateEntity(entity);
 }

public Entity getEntityById(int id) {
 return getEntityDAO().getEntity(id);
 }

public List<Entity> getEntitys() {
 return getEntityDAO().getEntities();
 }

public IEntityDAO getEntityDAO() {
 return entityDAO;
 }

public void setEntityDAO(IEntityDAO entityDAO) {
 this.entityDAO = entityDAO;
 }
}

EntityBBean


package com.mm.web.bbean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import org.springframework.context.annotation.Scope;
import org.springframework.dao.DataAccessException;

import com.mm.model.domain.Entity;
import com.mm.module.one.IEntityService;

@Named("entityBBean")
@Scope("session")
public class EntityBBean implements Serializable {

 private static final long serialVersionUID = 1L;

@Inject
 private IEntityService entityService;

 private int id;
 private String attribute;
 private List<Entity> entityList;

public void addEntity() {
 try {
 Entity entity = new Entity();
 entity.setId(getId());
 entity.setAttribute(getAttribute());
 getEntityService().addEntity(entity);
 FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Added!", "Message: "));

 } catch (DataAccessException e) {
 e.printStackTrace();
 FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "D'oh!", "Message: "));
 }

 }

public void reset() {
 this.setId(0);
 this.setAttribute("");
 }

public List<Entity> getEntityList() {
 entityList = new ArrayList<Entity>();
 entityList.addAll(getEntityService().getEntitys());
 return entityList;
 }

public IEntityService getEntityService() {
 return entityService;
 }

public void setEntityService(IEntityService entityService) {
 this.entityService = entityService;
 }

public void setEntityList(List<Entity> entityList) {
 this.entityList = entityList;
 }

public int getId() {
 return id;
 }

public void setId(int id) {
 this.id = id;
 }

public String getAttribute() {
 return attribute;
 }

 public void setAttribute(String attribute) {
 this.attribute = attribute;
 }
 }

index.xhtml


<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">

<h:head>

<title>Welcome to JTemplate</title>

</h:head>

<h:body>

<p:messages></p:messages>

<h:form>

<table>

<tr>

<td><h:outputLabel for="id" value="Id : " /></td>

<td><p:inputText id="id" value="#{entityBBean.id}"

disabled="true">

<f:converter converterId="javax.faces.Integer" />

<p:ajax event="blur" update="idMsg" />

</p:inputText> <p:message id="idMsg" for="id" display="icon" /></td>

</tr>

<tr>

<td><h:outputLabel for="attribute" value="Attribute : " /></td>

<td><p:inputText id="attribute"

value="#{entityBBean.attribute}">

<f:validateLength minimum="5" />

<p:ajax event="blur" update="attributeMsg" />

</p:inputText> <p:message id="attributeMsg" for="attribute" display="icon" /></td>

</tr>

<tr>

<td><p:commandButton id="addUser" value="Add"

actionListener="#{entityBBean.addEntity}" ajax="false" /></td>

<td><p:commandButton id="reset" value="Reset"

actionListener="#{entityBBean.reset}" ajax="false" /></td>

</tr>

</table>

&nbsp;

Elements:

&nbsp;

<p:dataTable id="entities" var="entity" value="#{entityBBean.entityList}"

style="width: 10%">

<p:column>

<f:facet name="header">

<h:outputText value="ID" />

</f:facet>

<h:outputText value="#{entity.id}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="Name" />

</f:facet>

<h:outputText value="#{entity.attribute}" />

</p:column>

</p:dataTable>

</h:form>

&nbsp;

</h:body>

</html>

Where is the code?

Feel free to fork the code from https://github.com/miquelmillan/jtemplate

References

http://www.javacodegeeks.com/2012/04/jsf-2-primefaces-3-spring-3-hibernate-4.html

http://www.mkyong.com/maven/how-to-create-a-web-application-project-with-maven/

http://www.mkyong.com/maven/how-to-deploy-maven-based-war-file-to-tomcat/

http://books.sonatype.com/mvnex-book/reference/multimodule.html

– https://jcp.org/en/jsr/detail?id=330

https://jcp.org/en/jsr/detail?id=317

Standard
Personal branding

Personal brand + domain name = ?

The first steps of my blog-resurrection plan is to give it a  nice User eXperience (UX). That’s the first because of some reasons:

– Give the blog a better readability to ease my eventual readers the hard task of reading my tedious posts

– Make it nicer will give me more energy to keep focused on writing nice posts

– I’ll learn new concepts like SEO, SEM, etc. Yes, it seems crazy for a software engineer, but in my day-to-day work I don’t have to fight with such techniques but, as I want to improve the blog  UX it’s good to make it easy to be found on web search engines.

Once defined the reach of the UX improvement I wanted to perform, I’ve started doing something involved on the 1st and the 3rd point, defining what’s known as my personal brand and giving it a good domain name. So, I googled searching for information regarding which are the best techniques, and I found lots of good articles, from which I’d like to highlight the next ones:

– Understanding domain names

– The dot com is taken for my name

– Dot com are domain names even relevant now

– Learn seo domain

The most relevant points I’ve learned from these articles are:

– It’s better to use your personal name than a short description about what you’re interested now, because interests change in an easier manner than your name

– If your name is taken it will be harder to have a good domain but with a little of imagination you’ll find a good domain

– Use a short domain name

– Even though .name seems the best TLD  for personal branding, the reality says that it’s usually interpreted as spam, so it’s better to use the .com as main TLD. As an IT professional this is the most surprising point to me, as I’ve always thought that .name was better than .com for personal brand, but I suppose that the street people do not understand the .name TLD.

So in basis to all this stuff, I’ve decided to use miquelmillan.com as it fits with mainly all the recommendations of the SEO experts. I hope it will be easy to remember 😉

Standard
Uncategorized

New Year, New Challenges :-)

Perhaps it’s a human tradition, but once started the new Year people has a lot of good propositions to do during the year. In this regard, I (a common software engineer, but a person too 😉 ) have my own propositions, as the rest of the world. And one of them is to resurrect this blog, an exciting but hard task.

In my opinion it will be it will be hard, too hard, as not everybody will accept my opinions, thoughts, acts and experiences as good. Furthermore,  sometimes the energy to keep working hard will not be there.

On the other side, it will be very exciting, and challenging too!! I believe that as one arrives to his thirties, he has accumulated the enough knowledge and experiences to write them somewhere whether to share them to the rest of the world or simply to have somewhere where he can search them when his memory fails :-P.

By now, That’s all, hope to meet you again soon!

Standard