Archive

Archive for the ‘web development’ Category

Getting ugly with BeginActionLink helper!

June 25th, 2010 ITmeze 1 comment

Have You ever had such a moment when the most stupid and trivial solution turns out to be the ONLY ONE that is logically suitable at the moment? When I had such a feeling today….
I am working on a module for one of huge web portals (not to mention which one). Part of that module is only accessible to users with administration permissions – as typical as it can be. The reason why I am mentioning that is to highlight the fact that at this specific part performance does not matter so much. Anyway, my talk to one of designers (Friday, half an hour before ‘the beginning of the weekend’):

Designer: I am going to spend whole weekend on those Views…

Me: Yeah… S*** happens….

Designer: Those ‘Html.ActionLink’ that You use everywhere, how do I put something inside, you know, images, spans, staff like that…

Me: Argh… Hm…..

I suddenly realize that before I leave the office this guy needs an extension method: BeginActionLink like right now!. The similar one that is used for Forms elements (BeginForm). Then I started to code… Have You ever realized that ActionLink has roughly 12 overloads!!!! That would take hours to prepare BeginActionLink for most of them.

idea bulb

When You are blocked, what You do? Me too, I started ‘googling’. Nothing simple and smart enough. Except 200 lines of code with tons of overloads… argh…

But then, completely unexpectedly ….

My moment of genius!

Don’t laugh! For people over … some age … that things do not happen offen! :)

There are solutions that developers are ashamed of, but they simply do their job:

public static string TrimEndTag(this MvcHtmlString htmlString, string tagName = "a")
        {
            var endTag = new TagBuilder(tagName).ToString(TagRenderMode.EndTag); 

            var tagString = htmlString.ToString();

            var endTagIndex = tagString.LastIndexOf(endTag);

            if(endTagIndex > 0)
                tagString = tagString.Remove(endTagIndex).TrimEnd();

            return tagString;
        }

        public static string ToEndTag(this HtmlHelper html, string tagName)
        {
            return new TagBuilder(tagName).ToString(TagRenderMode.EndTag);
        }

I am simply removing end tag from ActionLink returned string! As simple as that! So all that is left for my buddy to do is to use it like that:

<%= Html.ActionLink(" ", "testAction", "testController", new { id = 4 }, new {}).TrimEndTag() %>

        images, spans, text, whatever...

    <%= Html.ToEndTag("a") %>

Wuala! Ugly, So ugly, but at the same time I am preserving original methods for ActionLinks and I couldn’t figure out better solution….

A hint for Entity Framework multi-join performance problem

November 19th, 2009 ITmeze 3 comments

How I have started my adventure with Entity framework

Some of you may refer to one of my previous entries, when I was discussing tool I would use for my new web project. Look for (2. Database and ORM). I made a “brave” decision to choose Entity framework as my Object Relational Mapping tool. Well, I must say, i slightly regret this. To be honest, I would consider choosing other tools – or at least wait a little until more mature version of EF arrive (looking forward to play with it in .NET 4.0).

Why I don’t like it anymore

There are few things that annoys me with that. Tools that enable to quickly generate model objects from database schema (ADO.NET Entity Data Model Designer) is sort of an “error prone”. Each time i make modifications to db, and try to update model – it fails. And each time it is for a different reason. I completely stopped using it.

And how i almost ended up using it

But there are far serious problems. Or maybe ,better say, issues. One of them – one that really makes me feel scary was t-sql code generated by entity framework. In so many cases not really efficient one. But really strange when it comes to multiple joins. Have you ever looked at those gigantic “select” statement when you try to “Include” multiple entity collections to the result. I deliberately choose to name it “an issue”, cause i understand that is not an error. Moreover such queries cause some serious performance problems.

In my project, I ended up with following code:

var product = _productRepository.GetProductSet()
    .Include("Tags")
    .Include("Attachments")
    .Include("MarkAsDuplicatedBy")
    .Include("MarkAsDuplicatedBy.UserDetails")
    .Include(";FavouriteMarks")
    .Include("FavouriteMarks.User")
    .Include("FavoutiteMarks.User.UserDetails")
    .Include(";Orders")
    .Include("Orders.OrderDetails")
    .Include("Orders.User")
    .Include("Orders.Comments")
    .Include("Orders.Comments.User")
    .Include("Comments")
    .Include("Comments.User")
    .Include("Comments.User.UserDetails")
    .FirstOrDefault(p => p.ProductId == productId);

It is pretty straightforward. You have a product, products have a list of orders. Users can leave comments for each product, order or mark one as their favourite. Moreover, each product can be marked as a duplicate – notifying that there is another exactly the same product in in the store. Easy? Easy.
And Now it is lesson I recently learned. Such query is a KILLER! Believe me or not, it produces query of 3500 lines, where word “join” occurs 713 times. Unbelievable! It takes 4 seconds for this query to execute on my machine.
Now, playing with it a little I have managed to optimize it a lot. Don’t know if i am such a genius or my first approach was so bad… Rather second option, anyway…

First thing we may do is to reduce this code by separating “MarkAsDuplicate” property. That is something that will be used pretty rarely (le us hope so) so we can move it outside main query.

    if(product.MarkAsDuplicatedByReference.EntityKey != null){
        var user = product.MarkAsDuplicatedByReference
                                                .CreateSourceQuery()
                                                .Include("UserDetails").FirstOrDefault();
        product.MarkAsDuplicatedBy = user;
}

We first check if there is an assigned entity key for navigation property. Thanks to that we load more information only under condition there is a reason for that. Such a object is furhere assigned to

Secondly we may separate favourite marks, orders and comments.


var favs = product.FavouriteMarks.CreateSourceQuery()
                                      .Include("User")
                                      .Include("User.UserDetails")
                                      .ToList();

foreach (var fav in favs){
    product.FavouriteMarks.Attach(fav);
}

var orders = product.Orders.CreateSourceQuery()
                                      .Include("OrderDetails")
                                      .Include("User")
                                      .Include("Comments")
                                      .Include("Comments.User")

foreach (var order in orders){
    product.Orders.Attach(order);
}

And similarly with comments….

Although such an approach produces four db calls instead of one (like previously) achieved performance improvement is significant. In my case I have managed to drop it from 4 seconds to 1 second. Look at the table below to compare performance:

No of sql statements No of JOINs Time[sec]
Before splitting 1 713 4
After splitting 4 360 0.8

As you can see, number of joins was reduced twice and now our query is 5 times faster.

Another problem that arrives with such an approach is that it makes writing unit tests slightly harder. both Include and CreateSourceQuery methods are specific to Entity Framework. One way to overcome this is to prepare extension methods that would work differently depending on the context. Similar to example below:


public static class RepositoryExtensions {

        public static IQueryable<TEntity> LoadWith(this IQueryable<TEntity> obj, string path) {
             var query = obj as ObjectQuery<TEntity>;
             if (query != null)
                 return query.Include(path);
            return obj;
        }

        public static IQueryable<TEntity> CreateQuery(this EntityCollection<TEntity> entityCollection) where TEntity : EntityObject {
             var query = entityCollection.CreateSourceQuery();
             if (query == null)
                 return entityCollection.AsQueryable();
             return entityCollection.CreateSourceQuery();
        }
}

All that is left is to replace all calls to Include with LoadWith, and all calls to CreateSourceQuery with CreateQuery. Basic aim for those extension methods is to enable them to behave differently in case when we deal with ObjectQuery in entity framework environment, and differently when we have just a plain objects.

Summary

I hope some of You – especially those that are new to Entity Framework, like I am – will find this hint helpful. I have shown that sometimes, especially when we try to load entity with plenty of relations we made end up in a sql hell. In such a case it can be useful to split single query into few smaller. Despite the fact that we loose some performance due to those additional calls we end up with much higher gain. I have also demonstrated how further on such code may be improved for better unit testing. Thanks and happy coding

Categories: web development Tags:

Something is just wrong with this CAPTCHA!

October 19th, 2009 ITmeze 2 comments


Everyone knows what CAPTCHA is. This few weird letters/word that you write down to prove that you are a human. There are ton’s of them all around. Here and there. Often people (or developers) overuse them on web sites, which can be really annoying.
I was trying to register on one of the web sites today. After filling 16 (literally: sixteen) required fields on some really strange wizard I finally come up to form submission. This is what i saw:

weird catcha

Yeah, pretty straightforward. I thought. After filling input with PHN i saw JavaScript alert: ‘Invalid captcha!. Please try again’. I tried. And again the same. I was just about to abandon whole the process, but it all looked so strange i decided to  check what is going on in firebug. And then i figured out that actually valid input would be: ‘green’. WHAT?
Then I have read carefully what was written below the image: ‘If You are happy please type the color of the second character’. Argh! Wasn’t that obvious?

WEB DEVELOPERS! PLEASE, DON’T MAKE OUR LIFE DIFFICULT! DON’T LET US THINK!

What a stupid idea to make so common thing other way around! Or maybe it is okay, and this was my fault/foolishness not to read what was written? What You think? Do You know any other weird CAPTCHA?

Categories: web development Tags: ,

Short history of Facebook

October 19th, 2009 ITmeze No comments


If You haven’t seen or did not follow how world most popular social network changed over lat couple of years just take a break and spend next 4 minutes watching movie below.

And wow, just look at those numbers! RESPECT to Mark Zuckerberg!

After that I feel like an ant in today’s world.

I also recommend visiting web site: CheckFacebook. Where you can get some up to date stats about popularity and growth of Facebook user’s all over the world. Here is a simple screen shoot:

checkfacebook user's in cyprus

It looks like it is pretty popular in Cyprus as well  – third of population….

VS2010 Beta 2 is out! For MS employees :/

October 14th, 2009 ITmeze No comments


I have just read that It looks like Microsoft employees are already playing with beta 2 of Visual Studio 2010.

Nice, very nice. We want it too! Especially that it sucks to use beta 1 on old machine! And because You promised to fix some performance issues in next beta I desperately need that. Like now!

Read here blog entry from Misfit Geek.

Hope to download this version soon…

Categories: web development Tags: ,

Making internet start-up… Advices from Kevin Rose… and me

October 7th, 2009 ITmeze No comments


Have You ever heard about Kevin Rose?

No? He is known for his internet start-ups, like: Revision3 – internet television network, micro-blogging platform Pownce, and probably most known – social bookmarking Digg. Some of you might recognize wefollow.com project, especially If You are heavy twitter users.

I have just watched his excellent presentation at FOWA (The Future of Web Apps London) – found on the Carsonified’s Blog. He shares some ideas how to “take your site from one to one million users”.  Some of You will definitely find this useful.

Taking your Site from One to One Million Users by Kevin Rose from Carsonified on Vimeo.

What Do You think? To be honest – I really, really liked it. Maybe It wasn’t something fresh, something that we were not aware of, but something that allows web start-up creators to take another look at things they currently do or plan to do in the nearest future. And by the way, Kevin Rose is a good speaker and was able to present his ideas clearly, with some well chosen examples.

Let me comment on few of his thoughts.

1. Ego (Give a reward for user’s contributing to my system)

This is mainly concern for all of You thinking about web 2.0 start-up – web site that will gather community. Idea is pretty simple – give a reward for what people are doing, how they contribute to system.

Just look at the Facebook – how people are proud how many friends they have. Or Twitter – how users (or celebrities) compete to have more and more followers. To be honest – I am glad to have spam users following me - it doesn’t matter as long as my counter increases :) Or take a look at StackOverflow – programmers care so much about their reputations and badges in the system. One of Kevin’s new projects (wefollow.com) is just a twitter’s leader board, no more… Whole project just about that.

It was mentioned at the very end of the presentation (during “questions” time) that user’s should not be punished for their improper behavior. I couldn’t agree more. Before you punish someone (by banning user or deleting reputation) make sure that he/she fully understands how web site works… Probably punished user means lost user.

2. Simplicity and Analysis

Some of top community portals are simple and they focus on their certain functionality. Digg is about Digging links, Twitter about Twitting, Google about Googling :) Everyone knows that. So, stop building new Facebook, it will take ages. Focus on your core features. And remember – if you think building even simple features like twitter or digg have, does not take days or weeks if you really want user friendly experience.

Stop thinking you understand your users. Don’t assume that users do what you think they do.

Stop building new features that will take ages to finish, just because you think user’s may like it. Don’t spend time on features none cares about. Do investigation first. Allow user’s to provide feedback at your website, do it yourself or make use of existing projects for collecting user’s opinion, like: UserVoice or Get Satisfaction. Analyze your pages – use Google Analytics – it is for free and can bring a huge value to your knowledge about your customers, visitors. Analyze it – check how they show up on your website, what are they doing, when, from where they live (exit pages).

3. Marketing

Run your own blog, run your project’s blog. Talk to other bloggers about Your project – make them write about your project. Don’t use force!  :) Use Google Alerts – it will help you to respond to articles, entries where they mention your start-up.  Show Your project at conferences, make a demo to visualize your ideas.  Just think about the fact that Digg is where it is without a penny spend on keyword campaigns in internet.

Ugh… I am not really good at that. That makes me nervous every time i think about it. I like to think about myself as one to get job done. I am developer – marketing is fu!

4. Advisors

No matter what You think and how clever you are, there are people smarter than you, more experienced than you – especially if it concerns specialized areas (marketing, recruitment, business model, fund raising).

5. At the end

Most (90%) of web projects collapse. Extinct. It’s not the case with you. But one smart guy once said that:

The only truly failed project is the one where you didn’t learn anything along the way.

Uh… so true…