Welcome to Blogs From The Geeks, Intermittent insightful nuggets.


Uncategorized

Detecting when a page is loaded from the browser cache

Posted in Uncategorized on February 12th, 2010 by Karl O'Keeffe – Be the first to comment

When a user presses the back button in their browser to return to a previous page, that page is usually loaded straight from the browser’s cache, without any requests being made to the server. When that page shows information that could be out of date (such a an old list of products in your basket) this can cause problems.

So how about we knock up a little code that allows us to determine whether the page has been loaded from the server or the browsers cache. Then we can reload those parts of the page that may need updating (such as the basket).

We can do this by setting a cookie on every response from the server, and modifying that cookie using javascript. We can then use this cookie to know whether the page has been loaded from the server or the browser cache.

Setting the cookie on every response from the server

We will use a loadedFromBrowserCache cookie to facilitate the cache detection. We will set it to false every time a page is loaded from the server.

You can use the BrowserCacheIndicator class below to manage the cookie.

BrowserCacheIndicator.cs

using System.Web;
 
namespace SevenDigital.Web.Com.Code {
	public class BrowserCacheIndicator {
		private const string CACHE_COOKIE = "loadedFromBrowserCache";
 
		// This works with the javascript on the site to determine whether
		// a page has been loaded from the browser cache
 
		// *Every time* a page is loaded from the server we need to set
		// the loadedFromBrowserCache cookie to false
 
		// This method should be called in all Master Pages
		public void ClearCacheCookie(HttpResponse response) {
			response.SetCookie(new HttpCookie(CACHE_COOKIE, "false"));
		}
	}
}

And then set the cookie in every Master page:

namespace SevenDigital.Web.Com {
	public partial class ExampleMasterPage: BaseMasterPage {
		protected readonly BrowserCacheIndicator BrowserCacheIndicator = new BrowserCacheIndicator();
 
		protected void Page_Load(object sender, EventArgs e) {
			BrowserCacheIndicator.ClearCacheCookie(Response);
		}
	}
}

Using the cookie to know whether the page was loaded from the browser cache

The loadedFromBrowserCache cookie will be reset set to false by the HTTP Response header every time the page is loaded from the server. But it will not be reset when the page is loaded from the cache. We can use this to our advantage by setting the loadedFromBrowserCache cookie to true in javascript.

Then we know that the browser was loaded from the cache if the cookie is true on page load (because it was not reset by the server).

We just need to make sure we check the cookie before we set it to true!

browser-cache.js

// Detect whether or not we are loading this page from the browser cache
// Set the value $.loadedFromBrowserCache, which other scripts can use
(function() {
	var CACHE_COOKIE = 'loadedFromBrowserCache';
	jQuery.loadedFromBrowserCache = getCookie(CACHE_COOKIE) == 'true';
	setCookie(CACHE_COOKIE, 'true');
})();

Now we have a $.loadedFromBrowserCache variable that let’s us know whether the page was loaded from the browser cache.

Note, the above function can run immediately, it does not need to wait for the jQuery ready event, or the window.onload event as it does not modify the DOM.

Using $.loadedFromBrowserCache to do something useful

Now we can do something useful with the knowledge a page was reloaded from the cache. How about reloading the users basket to ensure it is always up to date:

// Reload the basket using ajax
// This is so that users still see the latest basket when using the back
// button in their browsers
$(function() {
	if ($.loadedFromBrowserCache) {
		refreshBasket();
	}
});

Enjoy!

Test Smells and Test Code Quality Metrics

Posted in Uncategorized on December 15th, 2009 by Hibri Marzook – Be the first to comment

Note: Cross posted from .Hibri.
Permalink

The major highlight at XP Day 2009, was Mark Striebeck’s talk on unit testing practices at Google.  What makes a good test depends on experience , skill and school of thought. I had to agree when he said that developers can be almost religious when it comes to the topic of what makes a good test. This made them solve this problem the Google way, by gathering data. Let the data speak.

He went on to describe metrics that they were collecting on tests and test code.  A test that has never failed is likely to be a bad test. If the test was fixed to make the test pass, then this is also an attribute of a bad test. A test can be a good test if the code was fixed to make the test pass.

This got me thinking. Generally I haven’t gathered metrics on test code. We have a pretty good metrics dashboard for production code. What metrics can I gather on test code ?

Metrics on test code should also focus on the readability of the code. Having large test methods is ok, but not too big. My opinion is that a test method with more than 20 lines is too big.

Tests should be concise, the assert should be obvious. Some code duplication is fine to make the test readable. This is all fine, but how can I get these as metrics  ? Only way to judge this is to eyeball the tests, and there are differences of opinion.

However, there are ways to measure what a test should not be. These are test smells. Test smells are described in xUnit Test Patterns

I’ve listed a few test smells and NDepend CQL queries find these smells. These can be automated in the build process and flagged up.

Large Test Methods

These can be a chore to read. Tests should be written as simply as possible. These also  point to too many responsibilities and dependencies in the code being tested, as most of the test code is used to do setup for the test.

SELECT METHODS WHERE HasAttribute "NUnit.Framework.TestAttribute" AND  NbLinesOfCode > 20

Large setup methods

Usually when unit testing the same code, we tend to have a common setup method, in order to make the test more readable. What happens is, more and more code is moved into the common setup method. We get blind to this after a while, and all the dependencies for the test are hidden away. If you do have [Setup] methods, keep them small.

SELECT METHODS WHERE HasAttribute "NUnit.Framework.SetUpAttribute" AND NbLinesOfCode  > 10

Deep inheritance trees in test fixtures

Again, common test code moved up to a base class and the base class is used in many tests. Then more base classes are created. This creates more tight coupling between test classes. Which makes tests harder to change. Low coupling and high cohesion applies to test code as well. Make each unit test class as independent as possible.

SELECT TYPES WHERE HasAttribute "NUnit.Framework.TestFixtureAttribute"  AND DepthOfInheritance >2

Test fixture setup

TestFixtureSetup is bad. The TestFixtureSetup is run once before all tests. This leads to fragile tests and inadvertently leads to using some shared state. Use Setup instead

SELECT METHODS WHERE HasAttribute "NUnit.Framework.TestFixtureSetUpAttribute"

Tests that fail when they are run in a different order

The xUnit test runner helps with this, by randomizing the order tests are run.

Ignored tests

Ignored tests are like comments. Dead code that doesn’t do anything. Either fix them or delete them.

I have yet to find some way of detecting duplicated tests, shared state in tests and multiple asserts in tests.

Why Microsoft Enterprise Library 4.1?

Posted in Uncategorized on August 20th, 2009 by noelhoo – Be the first to comment

This is just a quick post on why we should upgrade from EntLib 2.0 to 4.1

A lot has changed since the January 2006 release of EntLib 2.0. The current 4.1 version (released in October 2008) has a few new features that I have used and found particularly useful: Policy Injection.

Policy Injection Application Block

What is PIAB? Hopefully a small blurb and picture will help explain. According to the P&P team

The Enterprise Library Policy Injection Application Block provides a mechanism for automatically applying policies to object instances; this helps developers to better manage crosscutting concerns, maximize separation of concerns, encapsulate behavior, and manage code evolution and maintenance. Developers define the set of policies for the target classes and their members through configuration of the Policy Injection Application Block or by applying attributes to individual members of the target class. [source]
Policy Injection Application Blocks

Policy Injection: Handlers Pipelin

So what does that mean for us as 7Digital developers?

We can start applying crosscutting concerns (such as logging, caching, exception handling, validation) uniformly across our codebase either

  1. declaratively (ie. via use of attributes)
  2. OR by configuration (ie via use of App.config/Web.config).

For example, the code below shows the declarative option of caching.

[CachingCallHandler(0, 0, 30)]
public decimal GetSavingsBalance(int accountNumber)
{
  // Code here to extract balance from database.
  return balance;
}
 
[CachingCallHandler]
public decimal GetMortgageBalance(int accountNumber)
{
  // Code here to extract balance from database.
  return balance;
}

Simple isn’t it? So what happens in the background?

The Caching Handler does the following: (source)

  • It reads the cache expiration time span from the Policy Injection Application Block configuration.
  • It creates a cache key based on the method signature and input parameter values when the handler is invoked.
  • It checks whether the cache contains a value for this cache key.
  • If a value does exist, the Caching Handler extracts this from the cache, prevents subsequent handlers and the target method from executing, and returns the cached value to the caller instead.
  • If a value does not exist, the Caching Handler allows the next handler in the pipeline to execute. Then, after the method executes, the Caching Handler stores the returned value in the cache using the cache key and the configured expiration policy.

(The thing to note, the actual cache provider is independent to to this… so potentially you could use memCached, NCache, MS Velocity, etc…)

There are various other things in there with PIAB. Authorisation comes into mind. Check the following :

[AuthorizationCallHandler("make-deposit)]
 public void Deposit(decimal depositAmount){
   balance += depositAmount;
}

There’s more goodies in PIAB there, so check it out.