Saturday, January 14, 2012

How to get intellisense for JQuery in Visual Studio

Visual Studio comes with JQuery out of the box, but it's always a good idea to go to JQuery.com to get the latest version. Currently we're at v1.7.1. There are the two versions there, one large and one small. The small (Production version) is around 31k and the large (developer version) is around 229k.

In addition to this, if we visit http://appendto.com/community/jquery-vsdoc we can download a version that provides the ///- type comments and intellisense for Visual studio.

  1. You download the file. 
  2. You save it to the folder that contains the JQuery file. 
  3. Save it with a JS extension. 
And away you go.


The header comments from the file:


/*
* This file has been generated to support Visual Studio IntelliSense.
* You should not use this file at runtime inside the browser--it is only
* intended to be used only for design-time IntelliSense.  Please use the
* standard jQuery library for all production use.
*
* Comment version: 1.7
*/

/*!
* jQuery JavaScript Library v1.7
* http://jquery.com/
*
* Distributed in whole under the terms of the MIT
*
* Copyright 2010, John Resig

What is the Open Closed Principle in OO

What does this mean, well the title refers to classes and means:
Open to Extension yet Closed for modification.

So we should be able to extend it if we need to add behaviour, but we should not need to rip the code apart.

To do this we need to use abstractions. These are Interfaces and Abstract classes, or in procedural languages we can use parameters.


The problem

A common problem in coding is when an object has some kind of rule inside it. Perhaps there's an If else -if  - else if ... inside. And each If statement is really a rule.

A typical example is the pricing cart and product pricing problem.
If we sell products but they have different pricing rules, then we may need to add a new rule after a while.

As an example, say we have a class that sums the price of products in a shopping cart but each product is priced in a different currency. (This example is a good example of a problem, but the solution given here would probably be very different, so don't take it too seriously or literally. It's the principle that we're after.)


namespace OpenClosedPrinciple.FirstAttempt
{

    public class OrderItem
    {
        public string Currency { get; set; }
        public decimal Price { get; set; }
    }

    public class OpenClosedPrincipleDemo1
    {
        private List<OrderItem> _items;

        public OpenClosedPrincipleDemo1()
        { 
            _items = new List<OrderItem>();
        }

        public void AddItem(OrderItem item){
            _items.Add(item);
        }

        public decimal CalculateTotalAmountInEuros()
        {
            decimal total = 0m;

            foreach (OrderItem item in _items)
            {
                if (item.Currency == "Euro")
                {
                    total += item.Price;
                }
                else if (item.Currency == "US dollar")
                {
                    total += item.Price * (decimal)1.26;
                }
                else if (item.Currency == "Brazil Real")
                {
                    total += item.Price * (decimal)2.8;
                }
                // We'll probably end up having a lot more of these...
            }
            return total;
        }
    }
}


We can see that the if-else if - else if could become quite long if we wanted to add new currencies and any change would require a code change.
We can come up with another version by using the Strategy pattern. I have a post on the Strategy pattern.

namespace OpenClosedPrinciple.SecondAttempt
{
    public class OrderItem
    {
        public string Currency { get; set; }
        public decimal Price { get; set; }
    }

    public interface IPriceCalculator
    {
        decimal Calculate(OrderItem item);
    }

    public interface IPriceConversionRule
    {
        bool IsMatch(OrderItem item);
        decimal CalculatePrice(OrderItem item);
    }

    public class BrazilConversionRule : IPriceConversionRule
    {
        public bool IsMatch(OrderItem item)
        {
            return (item.Currency == "Brazil Real") ? true : false;
        }
        public decimal CalculatePrice(OrderItem item)
        {
            return item.Price * (decimal)2.8;
        }
    }

    public class EuroConversionRule : IPriceConversionRule
    {
        public bool IsMatch(OrderItem item)
        {
            return (item.Currency == "Euro") ? true : false;
        }
        public decimal CalculatePrice(OrderItem item)
        {
            return item.Price;
        }
    }

    public class USDollarConversionRule : IPriceConversionRule
    {
        public bool IsMatch(OrderItem item)
        {
            return (item.Currency == "US dollar") ? true : false;
        }
        public decimal CalculatePrice(OrderItem item)
        {
            return item.Price * (decimal)1.26;
        }
    }

    public class PriceCalculator : IPriceCalculator
    {
        private readonly List<IPriceConversionRule> _priceRules;

        public PriceCalculator()
        {
            _priceRules = new List<IPriceConversionRule>();
            _priceRules.Add(new BrazilConversionRule());
            _priceRules.Add(new USDollarConversionRule());
            _priceRules.Add(new EuroConversionRule());
        }

        public decimal Calculate(OrderItem item)
        {
            return _priceRules.First(rule => rule.IsMatch(item)).CalculatePrice(item);
        }
    }

    public class OpenClosedPrincipleDemo2
    {
        private readonly List<OrderItem> _items;
        private readonly IPriceCalculator _calculator;

        public OpenClosedPrincipleDemo2()
            : this(new PriceCalculator())
        { }

        public OpenClosedPrincipleDemo2(IPriceCalculator calculator)
        {
            _calculator = calculator;
            _items = new List<OrderItem>();
        }

        public void AddItem(OrderItem item)
        {
            _items.Add(item);
        }

        public decimal CalculateTotalAmountInEuros()
        {
            decimal total = 0;
            foreach (var item in _items)
            {
                total += _calculator.Calculate(item);
            }
            return total;
        }
    }
}


Complexity

107 lines versus 48 lines. From that view the fancy strategy pattern is longer and if we were after a quick piece of code then I would imagine most people would prefer the shorter version.

Complexity of the main class is less in the longer version. It is clear to see what it is doing and it is doing it well. It is doing one thing and has delegated the task of applying rules to someone else. The longer version is better form that perspective.

Understanding the rules. Well that is more difficult to understand on the longer version. But, if the rules were complex and if they differed greatly from one to another, then the longer code version would separate these really well and would aid in maintenance.


Thursday, January 5, 2012

Some justice at last for the Stephen Lawrence family

It has been so long in coming and but for the tireless pushing by his family these convictions probably wouldn't have happened. This case has changed British policing and it seems that it needed improving.


Wednesday, January 4, 2012

Model View Presenter for ASPX


Now that we have the excellent ASP.NET MVC we might not be visiting the aspx much anymore. One huge benefit of the ASP.NET MVC is the testability. The HTTPContext caused a real problem with its singleton behaviour in ASP.NET. To make TDD much more useful in the aspx world we can use the Model View Presenter technique. There are a couple of dialects to this depending on how strictly you adhere to the separation of the objects, but in general their purpose is described in the diagram below. The yellow blocks are the main players of MVP. For more info about the dialects we can see Martin Fowler's thoughts

Looking from the bottom-up:
1. I use the Entity Framework to create the OO abstraction of the underlying database. 
2. As great as these classes are, they are not always representative of the Domain objects - the Business language and concepts used in the Business - so we need to convert/translate (map) them to Domain Entities.
3. From the Domain Entities we often need simplified entities for the aspx pages. So, I think of the Domain Entities as a Domain Model, which is full and complex and complete. I create simplified Models for the Views and call them the View Model. We are now in the MVP part of the action.


I'm not talking much about MVP at the moment, but I'll get there. Anyway, a quick summary of the evolving Entity from database to screen.

  1. At the bottom of the system is the Table in database, e.g. Car.
  2. Entity Framework creates a Car class at design time. This class is hidden from the user of the system in the Repository object. 
  3. The Business Domain entity, Car, this is retrieved from the Repository. A mapper class exists inside the  workings of the Repository that takes the Entity Framework's Car and converts it to the Business Domain's Car.
  4. The car class in the View Model. This is the object to be displayed on the web page. Again a Mapper will convert/map/translate from the Domain's Car object to one suitable for the View (web page).

The aspx code behind class implements the ASPX View. That is, it is a concrete View. The view of the MVP pattern is actually an Interface defining the behaviour of the concrete view. This separation is excellent for testing. We can create a test object that implements the interface that will not be dependent on the HttpContext. A devoted View Model for that page provides data to one View.

There are two practical and high level questions that need to be asked and answered:
1. How do I divide this up into separate Projects in the Solution, and
2. Is this all necessary.

Is this all necessary
Well, for the small project the answer is definitely no. I would probably keep the MVP and Entity Framework, but I would ditch the Domain Entity objects unless the database tables and the subsequent EF classes do not represent the Business well enough.


How do I divide this up into separate Projects

Project for the web-site.
Namespaces:
  • Project


Project for the MVP. 
These are all related to the views, the  web pages
Namespaces:
  • Project.MVP.Models, 
  • Project.MVP.Views, 
  • Project.MVP.ViewModels
  • Project.MVP.ViewModels.Builders
  • Project.MVP.ViewModels.Mappers


Project for the Domain
These are all related to the Domain objects, the domain layer. Conceptually they are between the Web page stuff and the Repository stuff. They hold the Business meaning, the model of the Business.
Namespaces:
  • Project.Domain.Commands
  • Project.Domain.Entities
  • Project.Domain.Repositories
  • Project.Domain.Repositories.Mapping


Project for the Data
Namespaces:
  • Project.Data

This can of course be simplified by using fewer actual projects, and using folders and namespaces to separate the files. It can all change during development. My advice would be to think what you want, do it, change it when you evolve the development and discover possible improvements. Using the refactor feature in Visual Studio to rename classes, and using the context menu's rename option in the Solution explorer to rename files and their constituent classes (right-click on the filename), will make doing big structural changes easier. Building the Solution will find the breaks from any re-engineering.

Practical point to note. If, in a given example, the database table entity is named Cars then Entity Framework will produce a class named Car and the collection will be Cars. If you then translate this using a mapper class to a Domain Entity object, and thence onto an object in the ViewModel for the aspx page, will there be any confusion if give the name Car to the objects in those layers?
How do you want to handle that?

Package diagram indicating how most of the classes are separated.



Key to becoming familiar with the architecture
People who are new to this stuff can, with difficulty, pick this stuff apart and try to copy it parrot-fashion. But what is key to understanding this and making up your own improvements, is to know why each design block in the diagram exists. If you are writing your unit tests and there is some bug or block to your development, it is crucial to be able to vocalise to yourself what this object is supposed to be doing, what is it responsible for.
There are two levels to understanding the architecture. 1, is understanding the objects, and 2, is understanding why we are using interfaces. The interfaces are probably secondary to the understanding and are pretty much there for testing purposes. To aid in the unit testing.
As an example, lets say there is a Default.aspx page. (This is really a class named _Default.)
_Default - this is the View. The concrete class that is responsible for displaying things to the user and handling the user's button presses etc. No hard-lifting should go on in this object.
This class inherits from two classes. An interface class, IView and an abstract class, Viewbase.
IView, this is very useful for unit testing.
Viewbase, the use of this is debatable and usually doesn't do a lot. It is a good candidate to leave out.

DefaultPresenter - this is the "controller". The View (web page code file) creates the Presenter and the Presenter is aware of who his creator was (the View). The Presenter will create a ViewModelBuilder and tell it to create the ViewModel. The ViewModel is then given over to the View.
The Builder uses the Mapper to translate the fields from the Repository's Entity (e.g. Car) to the Entity use in the ViewModel. Remember that the View Model may well have fewer data fields than the Domain Entity, or perhaps concatenated data. The View Model is designed specifically for this particular View's needs.

Class structure for MVP. (Including Repository class from the Domain project).




Saving BBC iPlayer content on a Mac using (Get iPlayer Automator)

Get iPlayer Automator - I can't get past thinking that it's a strange name for an application.

Thing is, for Mac users who want to record and save audio and video from the BBC iPlayer this does the job. Probably not legal actually, so best you don't do it.
But if you do, then I hear it has a few simple issues to negotiate. Also, it is one of the least Mac-like applications you'll get - not very slick or polished but it can be made to work.

Download from:
http://tom-tech.com/iplayer_automator/iPlayer_Automator/Get_iPlayer_Automator.html

update May 2015 - you may like to try this link,
https://github.com/GetiPlayerAutomator/get-iplayer-automator/releases/tag/1.8.5 
The first link will work but I found it difficult at first to find the download link on the page.




The idea is to tell the application what url(s) you want to download and then tell it to go and download.

Sometimes it crashes. Normally that is enough to put people off using it. But it has only crashed on my 'friend' when he was adding the target url. (the programme url in the BBC iPlayer). It has not crashed on the download.

The best way to download a BBC programme is to:
1. Open iPlayer and navigate to the programme you want. Do not start or play the programme.
2. Open the "Get iPlayer Automator" application.
3. Click on the Use Current Webpage button. This is halfway down the application on the left.
4. Press the Start button in the toolbar.

The programme will download.

The next conundrum is the file's location.


Use Spotlight on the Mac, Cmd-Space and enter the name and there you are.


This method may not work outside of the UK as the BBC probably block the iPlayer to those DNS addresses outside of the UK. In which case you will need to configure the Proxy and add the urls another way via the Add to Queue button.


Update May 2015 - Still looking good

I looked again at this and downloaded the latest version 1.8.5 onto a newer laptop. It kept failing. I noticed by looking in Preferences on the General tab, that it was trying to save to a folder that wasn't present. I clicked on the Choose... button, created a new folder, and it worked nicely.






By the way, I was a bit critical of the look of the application before. It's much improved.