Archive for October, 2008

Has Google lost their point of difference?

Google used to be the one place I went to search for everything. It used to be that Google was the non-commercial company that had a search engine that wasn’t tuned to shopping, seems it is not so these days: I searched for details on a laptop I was considering buying… I know where I buy my laptops, what I wanted was spec’s

Google

http://www.google.com.au/search?hl=en&q=Lenovo+8932A45&btnG=Google+Search&meta=

Gives me a list of every site on the internet I can buy the Lenovo. Do you think perhaps the manufacturers web site is on the first page? Nope (And no I don’t even consider the sponsored link to the manufacturer as a part of my search results).

Live Search

http://search.live.com/results.aspx?q=Lenovo+8932A45&go=&form=QBLH

Yes more shopping for laptops… but at least they had the manufacturers web site as the first link on the list as well as the forum for that laptop model, admittedly at the bottom, but at least it’s not on Page 7 like Google, after 70 links of shopping websites.

Yahoo Search

http://au.search.yahoo.com/search?p=Lenovo+8932A45&fr=yfp-t-501&ei=UTF-8

Yep Yahoo also get’s the point and lists the manufacturers web site on the first page (not the first link but still better than Google).

Yes, I know this is only one example and I am not saying Live Search is any less commercially focused (possibly even more so than Google). But I think it shows that Google doesn’t necessarily deserve to be the centre of the internet universe that everyone perceives it to be. I would suggest that all search engines drop the advertisement links down the chain unless I search for “Shop for a Lenovo 8932A45” or at least give that as a separate option (one link to shopping for a Lenovo, not 70).

Leave a comment

Why Internet Explorer 8 Beta 2 scares me!

People who know me, know how much I hate HTML and how it was a horrible document standard (if you can even call it that) from the very beginning. Today web “applications” are built on top of this document standard to such a massive degree that everyone has lost the plot and decided that the future of the web is HTML + JavaScript. Google makes investments in a JavaScript virtual machine, which to their credit is incredible (for what it has to work with).

Today I installed a virtual machine of Internet Explorer 8 on XP SP3. Oh my god, I was terrified. Now I know that IE8 is still in Beta, but what scared me is our old IE6 Quirks mode site was pixel perfect, and our supposedly web-standards based UI was flaky with buttons disappearing on page refreshes, lines of text disappearing on the bottom of elements etc. So much for the future of the web.

Ignoring this I get the feeling MS has taken the approach that the browser is “the OS of the internet”. The reason the browser cannot be this is because everyone, (people who use the web, as well as those who produce content for it), wants the browsing experience to be the same for everyone on the planet. This is important, but unfortunately it means that Browsers really shouldn’t be innovating by adding features, but more removing and streamlining (making them faster) the one thing they were originally designed to do… Display documents!

Internet Explorer 8 is suffering from bloat… BIGTIME! Every release of Internet Explorer I feel like they’ve added something, I get this innate feeling that Internet Explorer 6 was more lightweight, more nimble. Then IE7 came along and added tabs, which take for-ever to add… then IE8 came along and added web slices… OMFG… just give up guys. Web Slices are going to go the way of active desktop, not because they aren’t a useful feature, but because there’ll always be the one stubborn browser out there that doesn’t want to implement them.

Looking at IE8’s out of the box UI in XP makes Google’s Chrome look like the best browser on the internet not for it’s features, but it’s lack thereof. There’s no crap (yet) it just does what it does extremely cleanly and simply, and I love it and would only use it if it was just a little more mature.

image

Internet Explorer’s Great Wall of Chrome

image

Browser Chrome done right (Google’s Chrome)

I think Microsoft’s best move has been making Silverlight a cross browser application platform to write proper applications with proper threading, memory management and network communication protocols. This is excellent news to me, as it gives the internet a REAL operating system. But what worries me is there is a large anti-MS movement out there touting Flash or Flex (or JavaScript *shudder*) as the future of web application development, not because it is necessarily better, but because it isn’t a Microsoft technology. Moonlight is probably the most important mitigation to this, but I get the impression people don’t see it as a real alternative because it will always be lagging years behind Silverlight (just like Mono is lagging behind .NET). MS would do well to give a very big hand to the Moonlight guys and make sure they never release Silverlight without a Moonlight release close behind. They have to realise this is the only way that Silverlight will get permanent adoption to the point where all browser’s come bundled with support for running Silverlight apps.

Leave a comment

Come get the world’s best LINQ Extensions

Ok, so maybe I’m exaggerating a little bit, but really this list of extensions for all things IEnumerable<T> is quite useful.

Feel free to chop and change and use whatever you like. A little credit to me in your code wouldn’t go astray though. smile_wink

The Code

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace FlatlinerDOA
{
    /// <summary>
    /// World's best LINQ extensions by Flatliner DOA
    /// </summary>
    public static class LinqExtensions
    {
        public const int DefaultMaxRetries = 1;
        public const int DefaultRetryDelayMilliseconds = 500;

        public static void AddOrReplace<T>(this IList<T> target, IEnumerable<T> source, IEqualityComparer<T> comparer)
        {
            target.AddOrReplaceWhere(source, (eachTarget, eachSource) => comparer.Equals(eachTarget, eachSource));
        }

        public static void AddOrReplaceWhere<TTarget, TSource>(this IList<TTarget> target, IEnumerable<TSource> source, Func<TSource, TTarget, bool> compareClause) where TSource : TTarget
        {
            if (source == null)
                return;
            var replacedIndexes = (from eachTarget in target
                                   from eachSource in source
                                   where compareClause(eachSource, eachTarget)
                                   select new 
                                   { 
                                       Index = target.IndexOf(eachTarget), 
                                       NewItem = eachSource 
                                   });

            foreach (var item in replacedIndexes)
            {
                target[item.Index] = item.NewItem;
            }

            foreach (var newItem in source.Except(replacedIndexes.Select(p => p.NewItem)))
            {
                target.Add(newItem);
            }
        }

        public static void RemoveAll<T>(this ICollection<T> target, IEnumerable<T> source)
        {
            if (source == null)
                return;

            var list = source.ToArray();
            foreach (T item in list)
            {
                target.Remove(item);
            }
        }

        public static void AddRange<T>(this ICollection<T> target, IEnumerable<T> source)
        {
            if (source == null)
                return;

            foreach (T item in source)
            {
                target.Add(item);
            }
        }

        public static int ElementIndex<T>(this IEnumerable<T> source, T element) where T : class
        {
            if (source == null)
                return -1;
            if (element == null)
                return -1;
            int i = 0;
            foreach (T item in source)
            {
                if (item.Equals(element))
                    return i;
                i++;
            }
            return -1;
        }

        public static IEnumerable<int> ElementIndexes<T>(this IList<T> source, IEnumerable<T> elements) where T : class
        {
            if (source == null)
                yield break;
            if (elements == null)
                yield break;
            // TODO: Use a sorted list to improve indexing performance
            foreach (T element in elements)
            {
                yield return source.IndexOf(element);
            }
        }

        public static IEnumerable<int> ElementIndexes<T>(this IEnumerable<T> source, IEnumerable<T> elements) where T : class
        {
            int i = 0;
            // TODO: Use a sorted list to improve indexing performance
            foreach (T element in elements)
            {
                foreach (T item in source)
                {
                    if (item.Equals(element))
                        yield return i;
                    i++;
                }
            }
        }

        public static bool IsNullOrEmpty<T>(this IEnumerable<T> source) where T : class
        {
            if (source == null)
                return true;
            return !source.Any();
        }

        public static IEnumerable<TSource> Update<TSource>(this IEnumerable<TSource> source, Action<TSource> update) where TSource : class
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (update == null)
                throw new ArgumentNullException("update");

            foreach (TSource element in source)
            {
                update(element);
                yield return element;
            }
        }

        public static IEnumerable<TTarget> UpdateWith<TTarget, TUpdateWith>(this IEnumerable<TTarget> target, IEnumerable<TUpdateWith> updateWith, Action<TTarget, TUpdateWith> update) where TTarget : class
        {
            if (target == null)
                throw new ArgumentNullException("target");
            if (update == null)
                throw new ArgumentNullException("update");

            int counter = 0;
            IEnumerator<TUpdateWith> updates = updateWith.GetEnumerator();
            foreach (TTarget element in target)
            {
                if (!updates.MoveNext())
                    yield break;
                //TUpdateWith updateValue = updateWith.Skip(counter).FirstOrDefault();
                update(element, updates.Current);
                yield return element;
                counter++;
            }
        }

        public static IEnumerable<TSource> DescendantsAndSelf<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childSelector, int maxDepth) where TSource : class
        {
            if (maxDepth > 0)
            {
                foreach (TSource child in source)
                {
                    foreach (TSource subChild in child.DescendantsAndSelf(childSelector, maxDepth))
                    {
                        yield return subChild;
                    }
                }
            }
        }

        public static IEnumerable<TSource> DescendantsAndSelf<TSource>(this TSource source, Func<TSource, IEnumerable<TSource>> childSelector, int maxDepth) where TSource : class
        {
            if (maxDepth > 0)
            {
                yield return source;
                foreach (TSource child in childSelector(source))
                {
                    foreach (TSource subChild in child.DescendantsAndSelf(childSelector, maxDepth - 1))
                    {
                        yield return subChild;
                    }
                }
            }
        }


        public static IEnumerable<TSource> Descendants<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childSelector, int maxDepth) where TSource : class
        {
            if (maxDepth > 0)
            {
                foreach (TSource child in source)
                {
                    foreach (TSource subChild in child.Descendants(childSelector, maxDepth))
                    {
                        yield return subChild;
                    }
                }
            }
        }

        public static IEnumerable<TSource> Descendants<TSource>(this TSource source, Func<TSource, IEnumerable<TSource>> childSelector, int maxDepth) where TSource : class
        {
            if (maxDepth > 0)
            {
                foreach (TSource child in childSelector(source))
                {
                    foreach (TSource subChild in child.DescendantsAndSelf(childSelector, maxDepth - 1))
                    {
                        yield return subChild;
                    }
                }
            }
        }

        public static bool OnlyContains<T>(this IEnumerable<T> items, IEnumerable<T> containsItems)
        {
            return !items.Except(containsItems).Any();
        }

        public static bool OnlyContains<T>(this IEnumerable<T> items, T containsItem)
        {
            return !items.Except(containsItem).Any();
        }

        public static IEnumerable<T> Union<T>(this IEnumerable<T> items, T item)
        {
            return items.Union(new T[] { item });
        }

        public static IEnumerable<T> Concat<T>(this IEnumerable<T> items, T item) 
        {
            return items.Concat(new T[] { item });
        }

        public static IEnumerable<T> Except<T>(this IEnumerable<T> items, T item)
        {
            return items.Where(p => !item.Equals(p));
        }

        /// <summary>
        /// Attempts to submit the changes and will retry once if there is a Deadlock (with a delay of 500ms)
        /// </summary>
        /// <param name="context"></param>
        public static void SubmitWithRetry(this DataContext context)
        {
            context.SubmitWithRetry(DefaultMaxRetries, DefaultRetryDelayMilliseconds);
        }

        /// <summary>
        /// Attempts to submit the changes one or more times, will also retry
        /// </summary>
        /// <param name="context"></param>
        /// <param name="maxRetries"></param>
        /// <param name="retryDelayMilliseconds"></param>
        public static void SubmitWithRetry(this DataContext context, int maxRetries, int retryDelayMilliseconds)
        {
            for (int attempt = 1; attempt <= maxRetries; attempt++)
            {
                try
                {
                    context.SubmitChanges();
                    return;
                }
                catch (SqlException sqlEx)
                {
                    sqlEx.TraceException();
                    if (sqlEx.Class != 13)
                    {
                        // Not a SQL Deadlock
                        throw; // No hope, the connection's gone
                    }
                }
                if (retryDelayMilliseconds > 0)
                    Thread.Sleep(retryDelayMilliseconds);
            }
            throw new ApplicationException("Maximum retries exceeded");
        }

        public static void TraceException(this SqlException exception)
        {
            string message = @"A SQL Exception occurred on server {0}.
Severity: {1}
Error: {2}
Procedure: {3}
Line No: {4}

Message:
----------
{5}

Stack Trace:
-------------
{6}";
            object[] parameters = new object[] 
            { 
                exception.Server,
                exception.Class,
                exception.Number,
                exception.Procedure,
                exception.LineNumber,
                exception.Message,
                exception.StackTrace 
            };

            if (exception.Class >= 20)
            {
                Trace.TraceError(message, parameters);
            }
            else if (exception.Class == 13)
            {
                // SQL Deadlock
                Trace.TraceWarning(message, parameters);
            }
            else
            {
                // Stuff like Foreign Key Contraint failures etc.
                Trace.TraceWarning(message, parameters);
            }
        }
    }
}

2 Comments

WPF Developer Guidelines

It’s always good to have a central reference for all things regarding a single technology. So with that in mind, I recommend if you are a WPF developer, that you check out Microsoft’s Whitepaper on building Quality WPF apps:

http://windowsclient.net/wpf/white-papers/wpf-app-quality-guide.aspx

Particularly useful is the WPF Tools listed at the bottom, most of them I use, but whenever I’m on a new development machine I always forget what they’re called.

Leave a comment