Friday, September 30, 2011

Developer + QA + Req. Engineer, A Triangular love story

Yesterday I happened to have a discussion with our QA Engineers within our company. I was away from the local projects for some time. So I had few questions to ask from them regarding the current QA practices and they also had questions to ask from me, regarding the QA practices I have experienced in the few of the companies I have worked with. I have summarised few suggestions that I have shared with them.

I started off by explaining how we, developers used to see these QA people. QA people are the first level customers, who try out the product and tell the possible improvements before we ship the product to the end customers. Moreover they are the people, who thinks from the end user's perspective and drive the product development in a such a way to deliver a usable & less buggy product to the end customers. To be precise, they are the worst enemies for the developers, who are lives in the near qubicles. Anyway these harder part of the relationship between the developer and QA need to be handled through one the Bug reporting tool (eg: Bugzilla). But verbal communication should be so friendly, so that bug could be explained in a friendly manner to come to a common agreement to fix the bug. I believe QA is more professional when they act as a mixture of worst enemy & a good friend with the developers. They need to believe themselves as a customers to get the thinking right.

Even each of the QA guy should seriously think about their career and need to find the ways to improve their ways of testing. They are in a situation to prove themselves to the developers. Then only, your justifications for your reported bugs will be given respect from the developer's side. As a Developer I know how I rate a bug based on that person's abilities. Some guys can be good with the scripting so they can choose one of the scripting language to write some of the scary performance testcases to find some of the performance bottlenecks. Some people are good at lateral thinking ability, they are the kind of guys, who prepares the testcase scenario document to come with the testcases for the both the Success/Failure scenarios in few hours. These sort of special abilities will simply helps you to build a self confidence among yourself as a QA person and the developers will show a lot of respect, based on your way of testing. Each QA Engineer should find their strength and improve on it to create a respect for yourselves among the team. This will make the developers to believe that, these QA guys know something special.

Requirements are the base for the QA Engineers to refer and test. So they need to make sure these requirements/changes are captured properly. When you follow a agile process these requirements will have a change every other day. These changes are going to be badly affecting the development + QA testing process. These change of requirements will be communicated with ease depending on the relationship, you have with your Requirements engineer. There are instances these requirement communications will happen without the knowledge of the QA engineers. So they will be surprised to see the note within the release email and enough preparation will not be there to tackle those new requirements. So QA Engineer need to have a proper communication with the Requirement engineers to get the proper update. I strongly feel they need to be much closer with Requirement engineers than developers to get the advantage of knowing the what is happening around in the requirements side. They can use the following tactics to move closer to the Requirement engineers

  1. Help the Requirement engineers by reviewing the SRS and give your feedback which considers the corner cases, which were not addressed
  2. Actively participate in the Internal requirement knowledge sharing sessions. Show your presence by asking the sensible questions
  3. Try to share a spreadsheet kind of document to raise your side of concerns regarding the requirements. Try to come up with something important to make a point.
  4. Always give pressure to the Requirements Engineer on the parts, those are not addressed clearly. Ask more questions and give more suggestions to have a good SRS. At the end of the day, QA Engineers can contribute to the quality of the SRS as well.

When Requirement engineers are benefited by your efforts, they will try to consult you next time before going for a possible change in the requirement. So rarely these new requirements can sneak in without your knowledge.

Anyway this is from my point of view. I feel one person can be a good QA Engineer when he/she enters in to the Developers' dream to threaten them with a tough bug :). The more you scare the developer the more you contribute to the project.

Wednesday, July 6, 2011

Java EST to DayLight Saving conversion

We are gifted. We live in the part of the world, where Sun rises on almost the same time on the each day of the year. So we don't need to worry about the "Day Light saving time" conversions during any Software development. But this cannot be prevented, when you have to develop a system for clients, who are in such regions.

Yesterday I had to work on bug, which is giving some confusing results during the DayLightTime saving peirod (march - november). I had different web users located in different part of the world. Their respective TimeZone was attached to their UserProfile. This UserProfile TimeZone will be used to convert the Date/Time value, shown within the Web UI system. It converted the Time properly when a "PST" timezone user logged in. But when "EST" timezone user logged in, system showed the time without the DayLightTime saving conversion. So I wrote a small test method to verify it. Here I have assumed that my source Date/Time is stored in the Asia/Colombo timezone.



private static void testDayLightSupport(String tz, int month) {

DateFormat dateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss z");
dateFormat.setTimeZone(TimeZone.getTimeZone(tz));
System.out.println("==========Month =" + (month + 1) + "==========================");

Calendar cale = Calendar.getInstance();
cale.set(2011, month, 12, 14, 34);
cale.setTimeZone(TimeZone.getTimeZone("Asia/Colombo"));
System.out.println(dateFormat.format(cale.getTime()));
}



I passed the "PST" as the TZ string and tried it.


testDayLightSupport("PST", 1); // February
testDayLightSupport("PST", 3); // April
testDayLightSupport("PST", 6); // July
testDayLightSupport("PST", 12); // December


Results were :

==========Month =2==========================
2011:02:12 01:04:33 PST
==========Month =4==========================
2011:04:12 02:04:33 PDT
==========Month =7==========================
2011:07:12 02:04:33 PDT
==========Month =13==========================
2012:01:12 01:04:33 PST


Results were quite satifying as there is a one hour difference in the conversion and timezone was specified as PDT. But I passed the "EST".


testDayLightSupport("EST", 1); // February
testDayLightSupport("EST", 3); // April
testDayLightSupport("EST", 6); // July
testDayLightSupport("EST", 12); // December


Results were :

==========Month =2==========================
2011:02:12 04:04:58 EST
==========Month =4==========================
2011:04:12 04:04:58 EST
==========Month =7==========================
2011:07:12 04:04:58 EST
==========Month =13==========================
2012:01:12 04:04:58 EST



It is terrible. There is no DayLightSaving conversion. I was googling for any similar bug reports, but I found a Java alert on the TimeZone.

Java TimeZone alert

In that alert, they requested to use the long values as timezones, such as "US/Eastern". These 3 letter TimeZone values were declared to be deprecated as they were ambiguous. After the introduction of the Olson's (Java's TZ data provider) new standard, some of the 3 letter timezone values were not continued with the support. When I tried the long values time conversions happened as expected :).


testDayLightSupport("US/Eastern", 1); // February
testDayLightSupport("US/Eastern", 3); // April
testDayLightSupport("US/Eastern", 6); // July
testDayLightSupport("US/Eastern", 12); // December

Results were :

==========Month =2==========================
2011:02:12 04:04:43 EST
==========Month =4==========================
2011:04:12 05:04:43 EDT
==========Month =7==========================
2011:07:12 05:04:43 EDT
==========Month =13==========================
2012:01:12 04:04:43 EST

Monday, June 27, 2011

Morphia for MongoDB ORM

We have seen enough of "Object/Relational mapping with the JPA" is used with the SQL based databases. It is more popular, as it gives a simple layer of access to the database without depending on underlying database management system. This helps to hide a database, which might be hard to understand.

NoSQL based databases increase in popularity due to various requirements. So there should be a way to provide a additional Object/Relational mapping. This extra feature is provided by the Google code project called Morphia. This library helps to get a simple view of the database rather than seeing the complex JSON view. I simply tried the following steps to setup my sample project.

1) Downloaded the Mongo java connector
2) Downloaded the Morphia library
3) Created sample model classes based on Pizza (I tried just before the lunch time :))
4) Tried Simple, OneToMany, Embedded, Query examples

I will explain simple save & query example based on Morphia.

Step1 : Annotations

1) Entity Annotation - need to specified for the model classes. If you want a different name to be specified for the datacollection, you can specify the custom name within the brackets. Here I have used "pizza_tb" as the specific name for the data collection.

Eg:

@Entity("pizza_tb")

public class Pizza {

...

...

}


2) Id annotation - will be used to specify the id field. It is mandatory for a entity class to have ObjectId type field.

Eg:

@Id
private ObjectId id;


3) Embedded Annotation - when you want to embed a class within a entity class, then you can declare it as "Embedded". You still get a chance to specify the custom name for that field.

Eg:

@Embedded("pizza_type")
private PizzaType pizzaType;

4) Reference Annotation - another entity can be referred within the current entity.

Eg:

@Reference
private List<pizzacontent> pizzaContents;


5) Transient Annotation - to avoid a field to be mapped as a database field.

Eg:

@Transient
private String comment;


6) Indexed Annotation - to index a field

Eg:

@Indexed(value = IndexDirection.ASC, name = "IDX_NAME", unique = true)
String name;


Step2 : Define Entity classes

1) Pizza class - here it is necessary to have the ObjectId type Id field.

@Entity("pizza")
public class Pizza {

@Id
private ObjectId id;
private String name;
private String description;

// pizzaType is to be embedded with the Pizza class
@Embedded("pizza_type")
private PizzaType pizzaType;

// Collection of pizzaContents to be referred
@Reference
private List<pizzacontent> pizzaContents;

public Pizza() {
// default contructor for Morphia
}

public ObjectId getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}


public PizzaType getPizzaType() {
return pizzaType;
}


public void setPizzaType(PizzaType pizzaType) {
this.pizzaType = pizzaType;
}


public List<pizzacontent> getPizzaContents() {
return pizzaContents;
}


public void setPizzaContents(List<pizzacontent> pizzaContents) {
this.pizzaContents = pizzaContents;
}
}


2) PizzaType class - this has the Embedded annotation to tell the system, that it is just going to be embedded into a another main class. But this is not mandatory.

@Embedded
public class PizzaType {
private String typeName;
private String comments;

public PizzaType() {
// default constructor for morphia
}

public String getTypeName() {
return typeName;
}

public void setTypeName(String typeName) {
this.typeName = typeName;
}

public String getComments() {
return comments;
}

public void setComments(String comments) {
this.comments = comments;
}
}


3) PizzaContent Class - another entity class

@Entity("pizza_content")
public class PizzaContent {

@Id
private ObjectId id;
private String contentName;
private String contentDesc;

public ObjectId getId() {
return id;
}

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

public String getContentName() {
return contentName;
}

public void setContentName(String contentName) {
this.contentName = contentName;
}

public String getContentDesc() {
return contentDesc;
}

public void setContentDesc(String contentDesc) {
this.contentDesc = contentDesc;
}

}



Step3 : To save

i) Create a datastore

Morphia morphia = new Morphia();
Mongo mongo = new Mongo("localhost");
Datastore datastore = morphia.createDatastore(mongo, "dominos_hut");

ii) Save the instances
Here PizzaContent need to saved before Pizza

PizzaContent pizzaContent = new PizzaContent();
pizzaContent.setContentName("Wheat");
pizzaContent.setContentDesc("Flour");
dtStore.save(pizzaContent);

List<pizzacontent> pizzaContents = new ArrayList<pizzacontent>();
pizzaContents.add(pizzaContent);
pizza.setPizzaContents(pizzaContents);

PizzaType pizzaType = new PizzaType();
pizzaType.setComments("comments");
pizzaType.setTypeName("Italian");

pizza.setPizzaType(pizzaType);

dtStore.save(pizza);


Step4 : Querying interface

Morphia provides a good amount of functions to query the MongoDB.


1) To select all the records in the Pizza data collection

Query<pizza> qryPizza = (Query<pizza>)dtStore.find(Pizza.class);
for (Pizza retPizza : qryPizza.fetch()){
System.out.println("Pizza Description: " + retPizza.getDescription());
}


2) To add a custom where" condition filter

Pizza retPizza1 = dtStore.createQuery(Pizza.class).filter("pizzaType.typeName = ", "Italian").get();
System.out.println("Pizza Description: " + retPizza1.getDescription());

3) It provides specific off the shelf functionalities as well

Typical equals condition

List<pizza> retPizzas2 = dtStore.createQuery(Pizza.class).field("name").containsIgnoreCase("Tomato Pizza").asList();
System.out.println("No. of Tomato Pizzas - " + retPizzas2.size());

Helps to order the results

List<pizza> retPizzas3 = dtStore.createQuery(Pizza.class).order("name").asList();
System.out.println("pizza.getId() - " + retPizzas3.size());

Endswith String matching

List<pizza> retPizzas2 = dtStore.createQuery(Pizza.class).field("name").endsWith("1").asList();

Startswith String matching

List<pizza> retPizzas3 = dtStore.createQuery(Pizza.class).field("name").startsWith("Tom").asList();