Google Analytics

Search

To search for specific articles you can use advanced Google features. Go to www.google.com and enter "site:darrellgrainger.blogspot.com" before your search terms, e.g.

site:darrellgrainger.blogspot.com CSS selectors

will search for "CSS selectors" but only on my site.


Wednesday, February 22, 2012

Technical Debt

What is technical debt? 

For the past ten years I have been hearing the expression "Technical Debt" in reference to programming. But what is technical debt?

At the same time I noticed the best project managers would have a summary chart for upper management. It broke things down into red light, yellow light or green light. The idea was that upper management have a lot of information to sift through so we needed to keep it simple.

I think the same idea applies to technical debt. You don't need a precise measurement of technical debt but you need to know if it is growing (red light), stable but still there (yellow light) or reducing (green light).

This still leaves the question, what is technical debt? If I'm running a business and my business needs a piece of machinery to finish a project. I cannot get money from the customer until I deliver the product but I need money to buy the machine to finish the project. So I get a small business loan, buy the machine, finish the project and sell it to the customer. At this point I have debt. Is the interest on the debt acceptable? If the interest is equal to the profit I made on the sale then I'll never get ahead (yellow light). If the interest is greater than the profit I made then I'll slowly go deeper and deeper into debt (red light). But if the interest is less than the profit I made, I can pay down or pay off my debt. BEFORE I get the loan, I need to know the profit will be greater than the interest on the loan. I need to know I will still turn a profit and can get out of debt.

Technical debt is similar. It MUST be a conscience decision to do something which is not good from a development point of view but which I'll be able to correct after the product is out the door. For example, I'm going to pick an inexpensive or easy to implement technology which I know will not scale. I know it will exceed the current load. I can predict, if successful, this choice will be a bottleneck in 18 months. In other words, the 'interest' on this 'loan' will eat away all my profit in 18 months. The long I wait to change to a more scalable technology the less profitable my project will be.

Worse would be to not only fail to pay off or at least pay down this technical debt but to incur more technical debt. Most people would like to have a nice home, a good car, annual trips to Europe or the Caribbean, send their kids to the best schools, etc. but would you use a credit card to pay for it all? When the bill collector comes knocking would you apply for another credit card to pay off the first credit card? Hopefully, you answered no. Even if you didn't, credit bureaus like Equifax or TransUnion would quickly make it impossible for you to get more credit.

Unfortunately, in software development there is no Equifax or TransUnion. Creating technical debt is a LOT easier than creating financial debt. This means you need to monitor your technical debt and make sure you are paying it down.

For short periods of time your technical debt might rise but the over all trend should be a reduction.

What is NOT technical debt? 

It is MORE important to understand what is not technical debt. A lot of people will chalk things up to technical debt when it is really lack of planning.

It isn't even poor planning but more a total lack of planning. Many times I have worked on projects where the project manager (or above) have made it very clear that the project must ship by a specific date. No excuses. What are you telling the programmers? You are telling them you don't care what the cost it, it has to ship by a specific date. The truth is that no one REALLY means 'money is no object'.

If you don't look at the cost of a technical compromise and just implement it, it is the equivalent of going to the local loan shark and signing a piece of paper without reading it. No successful business person would do this but I have seen Fortune 500 companies do the technical equivalent.

As a programmer, if my management tells me something has to be completed by a specific date, no matter what then they are telling me technical debt is no object. Take on whatever technical debt is necessary to get the project done on time. As a senior programmer I know they don't REALLY mean this. However, I have worked in companies where I tried to point out the technical debt is too high only to be told they don't want to hear excuses. Another programmer will swoop in and tell them he can get it done. I get demoted, the other programmer gets promoted.

Inevitably, the project ships on time and under budget. The programmer who swooped in and saved the day might even get a bonus. He might even do this again on the next release of the product. But then I noticed a pattern. Sooner or later, the programmer does a lateral shift to another department or worse, leaves the company to go work for the competition. Shortly after his departure from the project, the new developer starts trying to point out how much technical debt the previous programmer created. For example, a 50,000+ line function which uses lots of GOTOs and stack manipulation to make things work. Adding a new feature which should take 2 days to implement takes months and introduces dozens of new bugs in other features.

Reducing technical debt.

So what if you already have technical debt, planned or otherwise? You need to pay it down. I worked at one company where they went to their customers and let them know they had incurred a lot of unplanned technical   debt. They needed to pay it down. This meant the product would not be growing new features but it would be more stable and scalable. Most the customers looked at the market and believed we could still stay ahead of the competition plus the cost of re-training staff on a new product, creating a business relationship with a new company, etc. would be more costly than giving us a chance. Some major clients walked away and we took a big hit. The clients who did give us a second chance wanted to see that we had a plan. They wanted to see how we would make sure it didn't happen again. They wanted to see a road map of how we'd get back to adding new features. We had to regain their trust.

Hopefully you never get to this point. You want to start addressing unplanned technical debt before it gets this bad. But how do you do it?

Try and leave this world a little better than you found it. Robert Baden-Powell.
This is a quote from the father of scouting. The idea was, when you went camping to leave the camp site in better condition than you found it. If you show up at a camp site and someone has left some garbage, pick up their garbage as well as any garbage you create. If they trampled some saplings, plant new saplings.

I used to be a tradesman. Many homes in North America have aluminium wiring. Aluminium wiring was used because copper was in high demand and electricians could save money using aluminium wiring. However, the aluminium cannot handle as high a load. Homes were 40 to 60 Amp service. Today we are finding homes with 100 to 200 Amp service. The aluminium wiring cannot handle the higher amperage and fires occur.

New home owners buy a used home only to find out that it has aluminium wiring. At first, insurance companies were telling home owners you had to replace all the wiring or no insurance. Mortgage companies would then say, no insurance == no mortgage. So the home owner needed to come up with $50,000 to $70,000 to re-wire their new home.

This would be the equivalent of saving, I have too much technical debt so for the next year I'm going to add no new features and just refactor the code to remove technical debt. After a year the product will look the same from a customer's point of view but you will have spent hundreds of thousands of dollars. No customer is going to pay extra for a product that looks the same from their perspective. So you are out the money. Just like a new home owner saddled with $50,000 of extra debt on day 1 of their new home, this sort of debt can ruin a company. There is no way most companies can afford to take a year to remove technical debt.

The insurance companies soon realized they were asking the impossible and losing a LOT of potential customers. So they told the new home owners that whenever they renovated a room they needed to make removing the aluminium wiring part of the project.

Software companies need to do the same thing. Rather than give the customer nothing and spend 100% of your time reducing technical debt, whenever you adding a feature you should remove the technical debt as part of adding the feature. In other words, try and leave the software a little better than you found it.

Rather than removing all technical debt in a year it might take you 3 to 5 years but you are still adding new features and therefore getting revenue from customers.

How much time do you spend removing technical debt and how much time adding new features? This is a judgement call. You have to add enough new feature to make the customer feel they are getting their money's worth but leave enough time to reduce the technical debt.

Remember, it might have taken you 5 to 10 years to create the technical debt. It is not unreasonable to take a few years to remove it.

Tuesday, February 14, 2012

My environment for Selenium 2.0 (WebDriver)

One thing I believe to be very important for any sort of software development (and test automation with Selenium is software development) is having a good environment. So here is how I set up my environment to start with Selenium 2.0 and Java.

What you need:

  1. Java (go to  http://www.oracle.com/technetwork/java/index.html)
    1. I typically go with Java SE 1.6.0. If you don't need the latest, go with something more mature.
    2. Download the full SDK and docs.
    3. Install them in C:\jdk1.6.0_30 (assuming you downloaded build 30)
    4. I like to put it in the root of the C drive with no spaces in case other things don't like spaces.
    5. Unpack the docs into the same directory so they are easy to find. 
  2. Eclipse (go to  http://www.eclipse.org/downloads/)
    1. I typically go with Eclipse IDE for Java Developers because it has everything for Selenium and it is small.
  3. SVN (go to  http://subversion.apache.org/)
    1. You need some sort of source control.
    2. I usually go with Git but more people are still using Subversion.
    3. There are more tutorials on SVN and better support.
  4. Selenium (go to  http://code.google.com/p/selenium/downloads/list)
    1. You'll need to download:
      1. selenium-java-2.19.0.zip (or whatever the latest version is)
      2. selenium-server-standalone-2.19.0.jar (or whatever the latest version is)
    2. Unpack the zip file to some location
      1. I'll typically unzip them into the workspace for the project
      2. I'll also put the jar file in the same location
      3. This way I can add the jar files to subversion
  5. Eclipse support for SVN (go to  http://subclipse.tigris.org/ )
    1. Normally I would suggest using Marketplace from the Help menu but not for the latest SVN client.
    2. I like subclipse for an SVN client.
    3. Once on the subclipse site go to download and install.
    4. Copy the link for Eclipse Update Site URL for 1.8.x
    5. Go to Eclipse Help->Install New Software...
    6. Click Add...
      1. Name: subclipse 1.8.x
      2. Location: the update site URL you copied above.
    7. Select all
    8. Unselect Mylyn 3.x if you don't want it.
    9. Follow the install wizard
  6. Adding the JDK to Eclipse
    1. Go to Window->Preferences in Eclipse
    2. Expand Java
    3. Select Installed JREs
    4. Click Add...
    5. Select Standard VM
    6. Set JRE home to C:\jdk1.6.0_30\jre
    7. Set JRE name to JDK 1.6.0
    8. Everything else can be left as default.
  7. Creating a project
    1. Select File->New->Java Project
      1. Project name: something relating to the application you are testing
      2. I usually go with the defaults.
      3. Maybe change the JRE.
      4. Click Next >
      5. On the Libraries tab
      6. Add JARs... (add External JARs... if you didn't put them in the project workspace)
      7. Go to the location you unzip the Selenium files.
      8. Select the selenium-java-2.19.0.jar and selenium-java-2.19.0-src.jar files and add them.
      9. Add JARs... (add External JARs... if you didn't put them in the project workspace)
      10. Go to the location you unzip the Selenium files.
      11. Go to the libs folder and add all the jar files in there.
      12. Add JARs... (add External JARs... if you didn't put them in the project workspace)
      13. Go to the location you downloaded the selenium-server-standalone-2.19.0.jar file
      14. Add this file to the libraries.
    2. Finish the rest of the project creation using defaults.
    3. You can now start adding JUnit Test Cases to the project
      1. I select JUnit 4
      2. I select a package which follows Java conventions
      3. For example, com.mycompany.selenium.application where application is the application we are testing.
      4. Add a setUp() and tearDown()
      5. Finish
    4. Have a look at  http://seleniumhq.org/docs/03_webdriver.html for what to put in the setUp(), tearDown() and test cases.

The most important thing about using Selenium with Java is that you really need to know Java, Source Control (Subversion), an IDE (Eclipse) and a test framework (JUnit) before you even start using Selenium. So search the web for basic Java tutorials, play with Eclipse, check out http://www.junit.org/ and search for tutorials on JUnit 4 then look at the docs on Selenium HQ.

If you need help with Selenium and WebDriver, post a message to http://groups.google.com/group/webdriver. I usually respond to people there on a regular basis.

Update to using WebDriver / Selenum 2.0 with Safari

Around this time last year I wrote an article about using Safari with WebDriver. You can find this article at http://darrellgrainger.blogspot.com/2011/02/using-selenium-20-with-webdriver-and.html.

It has been a year and there is still no SafariDriver which extends WebDriver. Unfortunately, Safari 5.0 and 5.1 have hit the market and the Selenium 1.0 "*safari" driver is no longer working. As the Selenium look at dropping support for older web browsers they are also looking into supporting things like Safari 5.x.

Ideally, I would like to see:

    WebDriver driver = new SafariDriver();


or

    URL hub = new URL("http://localhost:4444/wd/hub");
    DesiredCapabilities dc = DesiredCapabilities.safari();
    WebDriver driver = new RemoteWebDriver(hub, dc);


Until this happens, we'll have to rely on using Selenium 1.0 to create an instance of Safari. But if "*safari" is no longer working and there are no plans to update it, what do we do? The solution appears to be use "*safariproxy" instead.

Looking at the code for SeleneseCommandExecutor() there are two constructors. The first takes as input a Selenium instance. The second takes as input a CommandProcessor. The second constructor actually calls the first constructor. So either method will work. So here it is:

    String baseURL = "http://www.google.com";
    Selenium sel = new DefaultSelenium("localhost", 4444, "*safariproxy", baseURL);
    CommandExecutor executor = new SeleneseCommandExecutor(sel);
    DesiredCapabilities dc = new DesiredCapabilities();
    WebDriver browser = new RemoteWebDriver(executor, dc);


or

    String baseURL = "http://www.google.com";
    CommandProcessor cp = new HttpCommandProcessor("localhost", 4444, "*safariproxy", baseURL);
    CommandExecutor executor = new SeleneseCommandExecutor(sel);
    DesiredCapabilities dc = new DesiredCapabilities();
    WebDriver browser = new RemoteWebDriver(executor, dc);


Additionally, if the browser cannot be found, i.e. it is not in the default locations, then you can specific the path to the Safari executable using:


    "*safariproxy /Application/Safari.app/Contents/MacOS/Safari"


This code is untested but hopefully better then the previous example.

Happy automating.

.

Thursday, February 9, 2012

Automated GUI Testing

From time to time I will see an automation tool with image compare. The idea is to get a screen capture, save it as a baseline then when the automation runs it gets a screen capture and compares it to the baseline.

Originally this always failed because there would be small differences. For example, the screen displayed the time and date, this would always be different and the compare would always fail.

The solution was to mask out parts of the screen capture we know will not be the same or to capture a portion of the screen and see if any part of the baseline matches the portion of screen capture.

This was a better solution but the video drivers from one machine to the next would create slightly different screen captures. So if you developed the baseline on one computer and ran it on another there was a high probability the compare would fail. Even comparing the screen capture to a baseline created on the same machine has a high probability of failing.

So what is the alternative?

We could go back to manual testing but that would be a step in the wrong direction.

We could automate the tests but hire someone to sit and watch them. If they see something wrong, do a screen capture and file a bug. Problems with this are, you still have one person tied up for the day watching the automation. Additionally, getting a screen shot and filing a bug while the automation is running could be a problem. Ideally, you'd want to be able to pause the automation, get the screen capture, file the bug and resume the automation.

However, there is a third alternative. When I create the test cases they will usually have points in the testing when you want to confirm the display looks okay. In some cases we just assume the user will be constantly looking. With automation, you want to explicitly decide when we need to confirm the display is okay. At those points in the automation, do a screen capture. The name of the file and the directory you store it in will have enough information for you to know which test case created the screen capture.

Once you have a directory of screen captures, you can quickly scan them and see that everything looks okay.

How does this save time? Most the time, GUI Testing is 80% getting the to place you want to confirm good display and 20% actually confirming the display. So if you are just reviewing the screen captures the time to get to the point to create the screen capture does not involve a tester and you save, on average, 80% of the time.

Classic examples of this being even better are confirming different configurations on the same test cases. For example, I tested a Java library for creating graphics. I would run the tests on 5 different operating systems with 3 different versions of Java.. So the test runner would essentially run:

for os in (5 different operating systems):
    for jvm in (3 different versions of Java):
        run all tests

This would result in 15 different test runs. I would then display all 15 screen captures for test case #1. If they all looked the same it would be a pass. If any one of the screen captures looked wrong I'd know which operating system, which JVM and which test case. So I could file a bug against that configuration.

You could do a similar thing for web testing. Run the same tests against the different operating systems and different web browsers. Then compare the screen captures to ensure all the configurations displayed correctly.

If you wanted to you could video capture the display as the tests ran. With a good video play back you could fast forward through the parts you know won't change.