Digiguru.co.uk

Random musings

    Managing multiple CSS and javascript files, and reduce your http requests

    05 Aug 2010

    We are always looking at optimizing performance in our website.

    we have loads of features through the site, but we like to program the work modularly. As a result a single page can have up to 50 different CSS and javascript files. Each of them are very small, but serve a specific function.

    An example might be as follows...




    <link href="/Css/reset.css" rel="stylesheet" type="text/css" /> <!-- We want to style nicely -->
    <link href="/Css/default.css" rel="stylesheet" type="text/css" /> <!-- Our sitewide font sizes and colours -->
    <link href="/Css/DropdownLists.css" rel="stylesheet" type="text/css" /> <!-- We have dropdown list navigation done in CSS -->
    <link href="/Css/footer.css" rel="stylesheet" type="text/css" /> <!-- The footer is quite a large chunk that we style nicely -->
    <link href="/Css/signinRibbon.css" rel="stylesheet" type="text/css" /> <!-- This is above the header -->
    <link href="/Css/newswide.css" rel="stylesheet" type="text/css" /> <!-- This is a page that uses our News panel -->
    <link href="/Css/buttons.css" rel="stylesheet" type="text/css" /> <!-- We have buttons on the page, so include our nice button styles -->


    This is 7 stylesheet requests before we even get started on the actual content in the page!

    Rule number one of ySlow! suggests you minimize the number of HTTP requests. They show that most users visits to your site are from users with an empty cache.

    We decided we needed a way to minimize the number of requests per page.

    I don't have time to waste on creating a massive solution and a quick browse on the internet yeilded nothing exicting that my Boss wanted to pay for, so I quickly wrote this:

    /CSS/MasterHomepage.aspx


    <%@ Page language="VB" ContentType="text/css" %>
    <!-- #Include virtual="~/Css/reset.css" -->
    <!-- #Include virtual="~/css/default.css" -->
    <!-- #Include virtual="~/Css/buttons.css" -->
    <!-- #Include virtual="~/Css/DropdownLists.css" -->
    <!-- #Include virtual="~/css/footer.css" -->
    <!-- #Include virtual="~/css/signinRibbon.css" -->
    <!-- #Include virtual="~/Css/newswide.css" -->


    All I have to do is include a single file in the page, and I get all the stylesheets.

    <link href="/Css/MasterHomepage.aspx" rel="stylesheet" type="text/css" />

    Suddenly i've reduced the 5 files to 1.

    I can use the same technique for javascript



    <script type="text/javascript" src="/js/googlecse.js"></script>
    <script type="text/javascript" src="/js/pngfix.js"></script>
    <script type="text/javascript" src="/js/jquery.js"></script>
    <script type="text/javascript" src="/js/DropdownList.js"></script>
    <script type="text/javascript" src="/js/daterangepicker.js"></script>


    becomes



    <%@ Page language="VB" ContentType="text/javascript" %>
    <!-- #Include virtual="~/js/googlecse.js" -->
    <!-- #Include virtual="~/js/pngfix.js" -->
    <!-- #Include virtual="~/js/jquery.js" -->
    <!-- #Include virtual="~/js/DropdownList.js" -->
    <!-- #Include virtual="~/js/daterangepicker.js" -->


    That's it for now, but check back later to see how we sped up these pages further.
    (1 minute)

    Why you shouldn't mix your View logic with your Controller logic.

    28 Jul 2010

    I was called up to say the admin pages for the supplier gallery had stopped working, all new images wouldn't upload. After searching through the javascript (which usually causes issues here) I discovered this juicy morsel in the code behind....


    If PostID = 0 And btnUpload.Text.Trim.Equals("Upload Photo") Then
    AddPostToMediaGallery()
    Response.Redirect("MediaGallery.aspx?msg=add")
    Else
    UpdateMediaGalleryPost()
    Response.Redirect("MediaGallery.aspx?msg=update")
    End If

    That reads "If the post has no ID, and the button to upload the photo was named 'Upload Photo' then Add the photo to the media gallery, otherwise update the existing media gallery photo."

    Firstly, that's too much information to read in a few lines of code, so let's refactor it a little...



    Public Enum ImageActionType
    AddImage
    UpdateImage
    End Enum

    Public Readonly Property ActionType As ImageActionType
    Get
    If PostID = 0 And btnUpload.Text.Trim.Equals("Upload Photo") Then
    Return AddImage
    Else
    Return UpdateImage
    End If
    End Get
    End Property

    ...


    If ActionType = ImageActionType.AddImage Then
    AddPostToMediaGallery()
    Response.Redirect("MediaGallery.aspx?msg=add")
    Else
    UpdateMediaGalleryPost()
    Response.Redirect("MediaGallery.aspx?msg=update")
    End If

    There, we've moved the nasty bit of code into a much easier to read property, but the problem remains. So next I check both the properties that are in the page. PostID is 0, that's as expected... this is a new Post, so we don't have an ID. I'm confused why "0" is representing the absence of an integer. What if there was a valid post with the ID of 0? We should make PostID nullable.


    Private _postID As Nullable(Of Integer)
    Public Property PostID() As Nullable(Of Integer)
    Get
    Return _postID
    End Get
    Set(ByVal value As Nullable(Of Integer))
    _postID = value
    End Set
    End Property

    Great, things are looking better already, but we haven't fixed the cause of the issue. Let me check the value of the buttons' text....

    Upload your Photo

    Here it is! Some designer has come in and changed the text of the button to "Upload your photo". That should be allowed. Why would anyone expect that changing the text of a button changes the behaviour too? I can see in the code that if the user is performing an update, it changes the label to another wording. This is the view, but the controller relies on the contents of the view to function. This is really bad. I checked all the code stubs and this is simply over-zealous programming. On no account is PostID ever set to anything but 0 for a new photo. Even if we did rely on a parameter in the page, we definitely shouldn't be storing it on the view.

    So i've gone into the code and removed that condition, now it looks much nicer.


    Public ReadOnly Property ActionType() As ImageActionType
    Get
    If Not PostID.HasValue Then
    Return ImageActionType.AddImage
    Else
    Return ImageActionType.UpdateImage
    End If
    End Get
    End Property
    (2 minutes)

    Chrome rendering bug? Check the spec!

    08 Mar 2010

    I've been experiencing a weird rendering issue in my site. After messing around with the HTML and using Safari's Web Inspector, I found the issue was recreate-able...


    read more (1 minute)

    Show me your ID

    22 Aug 2008

    One of the joys of working on software that has been outsourced to third parties, is fixing all the third party issues that only get discover after the support contract has expired.

    Apart from having massive portions of duplicated code all over a payment system, I had to discover why some payments were going missing, and some were being assigned to the wrong businesses.
    read more (2 minutes)

    Optimizing SQL Queries

    14 Aug 2008

    I was working on some code when I came across a behemoth of an inline SQL query nestled in the code behind of a page.

    Select 
        a.list_id, 
        a.company_name, 
        a.company_description, 
        a.url,
        (  case when (
            Select upper(County_Name) 
            from tbl_County 
            where County_id=a.County_id
        ) is null then (
            Select upper(Country_Name) 
            from tbl_description_Country 
            where Country_id= a.Country_id
        ) else (
            Select upper(County_Name) from tbl_County where County_id= a.County_id) 
        end     ) as County_name,
        b.review_approval,
        ( case when (
            Select county_id 
            from tbl_County 
            where County_id = a.County_id
        ) = 0 then (
            Select Country_id 
            from tbl_description_Country 
            where Country_id = a.Country_id
        ) else (
            Select county_id 
            from tbl_County 
            where County_id= a.County_id
        ) end ) as CountryID,
        dbo.funcGetRatingSum (a.list_id) as ratingSum,
        dbo.funcGetRatingCount (a.list_id) as totalCount,
        ( Select case when ( 
            select top 1 banner_path 
            from tbl_banners 
            where list_id = a.list_id 
            and a.subscription_id = 2
        ) is null then ''
        else ( 
            select top 1 banner_path 
            from tbl_banners 
            where list_id = a.list_id 
            and a.subscription_id = 2
        ) end ) as bannerpath
    from 
        tbl_directorylisting a, 
        tbl_preferences as b ,
        tbl_companymaster c 
    where a. status = 1 
    and ( a.company_id = b.company_id And a.status = 1) 
    and c.category_id= @CategoryID
    and a.company_id= c.company_id and a.subscription_id in (2,3) 
    and subscription_date >= (dateadd(year,-1,getdate()))
    Order by county_name, a.subscription_id asc, a.date_fee_paid

    read more (1 minute)