iThink

eye on the next fun project

iPhone 4.0 SDK Change is Really about Pushing Mac Sales

update: Here is a list of iPhone apps that will run foul against the new licensing terms.

Since the section 3.3.1 licensing change of the SDK, every developer who has a blog or twitter account has pretty much written about their disdain/understanding/appreciation.

3.3.1 — Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs. Applications must be originally written in Objective-C, C, C++, or JavaScript as executed by the iPhone OS WebKit engine, and only code written in C, C++, and Objective-C may compile and directly link against the Documented APIs (e.g., Applications that link to Documented APIs through an intermediary translation or compatibility layer or tool are prohibited).

Among the responses, some are completely against the idea that Apple should control how applications are written. iPhone is not free software and it’s hard to imagine that developers can demand such freedom. In this view, the fact that Apple requires you to write in Objective-C with Xcode is unacceptable. At the technical level, I can’t understand how Apple will be able to detect (and therefore enforce) whether apps are originally written in Objective-C. Some proposed that static analysis will indicate the presence of these unofficial libraries within the symbol tables. This immediately puts Apple and developers in a cat-and-mouse game. A determined code generator merely has to hide signatures that Apple uses for in detection mechanisms. Also, an interesting point arises: can libraries code be written in different languages with only the core of the app complies with the standard? Another option would possibly be to put as much as logic on the server-side and write a simple shell in Xcode.

Immediately, mass speculation started. Some Apple enthusiasts claim that Apple changed the agreement to acquire even more control as they can’t let any other toolkits be the de facto standard for the platform. However, I don’t think that’s the case. Usually in the developer world, it’s usually the implementation that gets the official blessing is the one that developers flock to. Given Apple’s morbid attention to details and continuous investment in improving its developer tools, no other business will reap the same benefits in making any alternative development platforms on iPhone, not even Adobe. Therefore, losing control in the preferred tool set for iPhone just isn’t a scenario that will happen.

Straight from the horse’s mouth, Steve Jobs responded to the uproar. He believes that applications that are written exclusively for a single platform generally have a higher quality than those aren’t. Sure, this may be the case for small shops where resource is a big constraint. But I can’t imagine when EA games adapted its Need for Speed franchise from PC and console to the iPhone, none of the code base is reused. Would this run foul with the new terms? On the flip side, if Apple removes section 3.3.1, high quality frameworks may appear and the said small shops can simply write on top of that.

Here is my speculation. As it happens, to write native iPhone/iPad apps, you have to own a Mac computer (or go hackintosh). Here are some numbers. In the latest quarter, Apple sold 3.36 million computers. Given that there are 185,000 apps currently in the app store, the number of computers used to make them are a tiny drop in the ocean. However, a crucial point here is momentum. As more developers flock to the iPhone platform to strike gold, they have to buy Macs. This will suddenly create a new niche for Apple. As more developers move from Windows to Mac, they may in turn influence more friends to switch.

Lastly, I must say that internet always exaggerate issues. Frankly, I think the percentage of developers who have used or will use unofficial frameworks is incredibly small. Most successful applications require a fine understanding of the Mac concept. I don’t think just because you’ve written Windows Forms application for the past 5 years and you can suddenly become a iPhone super star with MonoTouch. Developers have to have used Mac for a long while to appreciate all the small things that make it tick. And frankly, if iPhone/iPad is where you want to make money, buy a Mac and learn Objective-C. The market now is too crowded for accidental millionaires.

Concurrent Programming in .NET (Part 3)

In part 2, we looked at explicit threading support in great details and different ways that it can help create concurrency. In typical demo-ware fashion, the cost associated with thread creation is usually not mentioned. There is an explicit cost to create and destroy managed and native threads. Such cost will be amortized if the work these threads do far outweigh their creation cost. In simple terms, the longer that the threads spend on CPU calculating (not waiting for I/O), the smaller is the concern. If a large number of threads are created for small chunks of work, then the aggregate overhead will not be negligible.

There is a recourse in the .NET framework since the beginning, ThreadPool. Essentially, a pool of threads are created for reuse. Cost saving is achieved from reduced number of thread creation/destruction activities. When the work is done, threads in the pool do not die. They are released back to the pool for re-use. There is even a design pattern for this.

Something strange about the .NET 1.1 version of the documentation is that it says

The thread pool is created the first time you create an instance of the ThreadPool class.

However, despite that ThreadPool class is not declared as static, all its methods are static. Therefore, instantiating an object of ThreadPool is completely useless. Curiously, that sentence is purged in documentation for newer versions of .NET. Also, the ThreadPool class is now static. Some interesting characteristics

  • There is no way to cancel a work item after it has been queued.
  • There is one thread pool per process. The thread pool has a default size of 250 worker threads per available processor, and 1000 I/O completion threads.
  • The number of threads in the thread pool can be changed by using the SetMaxThreads method.
  • When all thread pool threads have been assigned to tasks, it creates new idle threads at 0.5 second intervals.
  • The threads in the managed thread pool are background threads. That is, their IsBackground properties are true. This means that a ThreadPool thread will not keep an application running after all foreground threads have exited.
  • When the thread pool reuses a thread, it does not clear the data in thread local storage or in fields that are marked with the ThreadStaticAttribute attribute.

I think the first point about no built-in support for cancellation is one reason for BackgroundWorker and TaskFactory but we’ll leave the discussion for the future.

Among the static methods, the main usage of ThreadPool will be through the QueueUserWorkItem methods, with and without a parameter, much like ThreadStart and ParameterizedThreadStart.

In the version with parameter to the ThreadPool pool.

public class HelloRunnable
{
    public static void run()
    {
        System.Console.WriteLine("Hello from a thread!");
    }

    public static void Main(string[] args)
    {
        System.Threading.ThreadPool.QueueUserWorkItem(run);
        System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(run));
    }
}

As you can see, despite the documentation states that

Visual Basic users can omit the WaitCallback constructor, and simply use the AddressOf operator when passing the callback method to QueueUserWorkItem. Visual Basic automatically calls the correct delegate constructor.

It works in C# too. So there is no need to instantiate a WaitCallback if you don’t want to. This clumsy delegate requires an object parameter whichever version of the overloaded QueueUserWorkItem methods you call.

public class HelloRunnable
{
    public static void run(object state)
    {
        if(state != null)
            System.Console.WriteLine(state.ToString());
    }

    public static void Main(string[] args)
    {
        System.Threading.ThreadPool.QueueUserWorkItem(run);
        System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(run));

        System.Threading.ThreadPool.QueueUserWorkItem(run, "Hello from a thread!");
        System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(run), "Hello from a thread!");
    }
}

Why Use Specialized Methods when You Can Do with Generic Methods?

In the last post, I created two methods to execute a portion of code under the application pool identity. When writing it, I had the uneasy feeling of something wasn’t quite right. It stemmed from the fact that those two methods have parameters (WorkItem class) and return type (string) specified. So if another piece of code needs to execute under the application pool security context, I will have to create new methods.

It turns out that generic methods have been available since .NET 2.0. So I can create methods that take generic parameters and return generic values like this.

[DllImport("advapi32.dll")]
protected static extern bool RevertToSelf();

protected void AppPoolExecute<T1>(Action<T1> command, T1 input)
{
    WindowsIdentity objOriginalUser = WindowsIdentity.GetCurrent();
    try
    {
        RevertToSelf();
        command(input);
    }
    finally
    {
        objOriginalUser.Impersonate();
    }
}

protected TResult AppPoolExecute<T1, T2, TResult>(Func<T1, T2, TResult> command, T1 inputOne, T2 inputTwo)
{
    WindowsIdentity objOriginalUser = WindowsIdentity.GetCurrent();
    try
    {
        RevertToSelf();
        return command(inputOne, inputTwo);
    }
    finally
    {
        objOriginalUser.Impersonate();
    }
}

Execute Code under Application Pool Account (ASP.NET and SharePoint)

Sometimes you run into the famous double hop problem when the authentication infrastructure doesn’t support Kerberos. Suppose the following scenario

  • You use Integrated Authentication in an IIS web site
  • You use Impersonation in ASP.NET web application
  • You want to read/write a custom database hosted in a different server from the web server

(Coincidentally, this scenario almost always happens with a standard SharePoint installation. So the problem, and solution, applies too)

When the code that execute the database logic runs on a box with both IIS and SQL server, it works fine. When IIS and the SQL server are running on different boxes, the code will fail and you get the ugly error page

System.Web.HttpUnhandledException: Exception of type ‘System.Web.HttpUnhandledException’ was thrown. —> System.Data.SqlClient.SqlException: Login failed for user ‘NT AUTHORITY\ANONYMOUS LOGON’.

One simple solution to overcome this is to grant the application pool account to read/write the custom database and temporarily disable impersonation. The effect of this is that when impersonation is disabled, the code will suddenly run under the security context of the application pool.

This maybe convoluted but think about it this way. ASP.NET codes are run by the application pool account (duh!). When impersonation is enabled (seems to be the default), such code is now run under the user requesting the page. Therefore, if you want to access a custom database, that user’s identity need to be granted access to the said database. If you want to simplify database access control, you can grant the application pool account read/write permissions. Then in the ASP.NET code, you just temporarily un-impersonate around the code region for database access. How this avoids the double hop problem is that IIS isn’t doing delegation anymore. Application pool identity is passed to the database. With impersonation, user’s identity is first passed to the IIS, which then passes it to the database. Sadly, NTLM doesn’t support this.

So much for theory, let’s see some code. A better name of un-impersonate is revert-to-self.  This turns out to be not-available to non-SharePoint developers as it’s only provided in the Windows API world.

[System.Runtime.InteropServices.DllImport("advapi32.dll")]
extern bool RevertToSelf();

private void AppPoolExecute(Action<WorkItem> command, WorkItem item)
{
    var origIden = System.Security.Principal.WindowsIdentity.GetCurrent();
    try
    {
        RevertToSelf();
        command(item);
    }
    finally
    {
        origIden.Impersonate();
    }
}

private string AppPoolExecute(Func<WorkItem> command, WorkItem item)
{
    var origIden = System.Security.Principal.WindowsIdentity.GetCurrent();
    try
    {
        RevertToSelf();
        return command(item);
    }
    finally
    {
        origIden.Impersonate();
    }
}

The overloaded methods differ by the fact that they can take Action<T> and Func<T, TResult> delegates. Sometimes, your code returns something and othertimes it’s the side-effect that matters. Hence both delegates are provided.

private void Run()
{
    AppPoolExecute(e => System.Diagnostics.Trace.WriteLine(e.ToString()), new WorkItem());

    AppPoolExecute(e => e.ToString() , new WorkItem());
}

P.S. For SharePoint developers, there is a .NET API to obviate all of the above with some caveat. It’s mainly used to access the SharePoint object model and not for access custom databases.

Concurrent Programming in .NET (Part 2)

Part 1 introduced us to the basic of concurrent programming in .NET. In this series, we will move from .NET 1.0 to 4.0 and see how concurrency can be achieved using the evolving API. Today, we look at the most basic explicit threading class.

    public sealed class Thread : CriticalFinalizerObject, _Thread

Interestingly, the Thread class started to inherit from CriticalFinalizerObject and implement _Thread interface only since .NET framework 2.0. In .NET 1.0 and 1.1, it merely inherited from System.Object. The _Thread interface exposes the managed thread object to unmanaged code. Why this wasn’t the case before .NET 2.0 is beyond me. CriticalFinalizerObject is more interesting as it enforces the so-called Constrained Execution Region automatically in the derived class’s object finalizer (destructor in C#) code. Essentially, it means it will execute the finalizer even if the application domain is unloading or the thread is aborted. You can read all the glory details here.

When creating a new thread object, there are 4 flavors: a combination of whether the delegate to execute has parameters and whether there is a maximum stack size rule on the new thread. We will look at these options in detail.

  • ThreadStart is a simple delegate that has no parameter and doesn’t have a return value. .NET delegates has no counterpart in Java. In C/C++, there is something called function pointer, which allows the caller to pass function objects around. Microsoft likes to claim that delegates are superior because they are type-safe. In details, all delegates are implemented as classes. Therefore, delegates are not first-class citizens in .NET. We will re-use the code from part 1 here.
  • public class HelloRunnable {
        public static void run() {
            System.Console.WriteLine("Hello from a thread!");
        }
        public static void Main(string [] args) {
            new System.Threading.Thread(run).Start();
        }
    }
    

    If you notice, there is no mention of any ThreadStart delegate in the code! This is a nice syntactic sugar introduced in .NET 2.0. Instead of instantiating an object of type ThreadStart like this

    public class HelloRunnable
    {
        public static void run()
        {
            System.Console.WriteLine("Hello from a thread!");
        }
        public static void Main(string[] args)
        {
            System.Threading.ThreadStart startDelegate = new System.Threading.ThreadStart(run);
            new System.Threading.Thread(startDelegate).Start();
        }
    }
    

    You get to pass in method name directly in the place of a delegate in the constructor.

  • If you’ve thinking about the need to pass in parameters so that the new thread can use, ParameterizedThreadStart is your friend. It takes in an object as the parameter that gives you a lot of flexibility (e.g. you can pass in an entire hash table if you like) at the cost of type-safety. Since every classes derive from System.Object, the compiler won’t catch any error if you try to cast the parameter down to a more derived object. Maybe some sort of generic ParameterizedThreadStart with optional parameters (new in .NET 4.0) can help here.
  • public class HelloRunnable
    {
        public static void run(object message)
        {
            System.Console.WriteLine(message);
        }
        public static void Main(string[] args)
        {
            System.Threading.ParameterizedThreadStart startDelegate = new System.Threading.ParameterizedThreadStart(run);
            new System.Threading.Thread(startDelegate).Start("Hello from a thread!");
        }
    }
    

    The lazy coder’s version without having to instantiate a ParameterizedthreadStart delegate is pretty much the same as the naked version.

    public class HelloRunnable
    {
        public static void run(object message)
        {
            System.Console.WriteLine(message);
        }
        public static void Main(string[] args)
        {
            new System.Threading.Thread(run).Start("Hello from a thread!");
    
        }
    }
    

    Something you might have asked. What if I want to return some values in these methods that run in a separate thread? Well, you can’t. The way ThreadStart and ParameterizedThreadStart delegates are designed explicitly prohibit return values. If you indeed want to do that, you have to think differently. In .NET, threading is provided via method calls and there lies the problem. There is no reason why you have to construct a method just to pass a piece of work to be run in a separate thread. In fact, once Lambda expressions are introduced in .NET 3.0 and in particular, the TaskFactory class in .NET 4.0, you can pass in Func<TResult> delegate that returns a value. Saving that, there are workarounds like this.

  • At this point, we’re ready to talk about the mysterious second parameter in the constructors, maxStackSize. Each thread has a separate stack and it’s best not to use these overloaded constructors, as per documentation.

The sharp eyed readers will notice a subtle bug in all the above codes. Since the thread scheduler can execute these threads in any order as it sees fit. There is no guarantee that the child thread will complete by the time the parent thread exits. Now, this problem won’t exhibit as the parent thread in this case is the main thread, it exits and the process will exit. In Windows, a process won’t exit until all non-background threads it created exit. In other scenarios, you will have to explicitly wait for all threads to complete unless you’re ok with them being aborted unexpectedly.

You can wait for the child thread to complete in a few different ways.

public class HelloRunnable
{
    public static void run(object message)
    {
        System.Console.WriteLine(message);
    }
    public static void Main(string[] args)
    {
        var thread = new System.Threading.Thread(run);
        thread.Start("Hello from a thread!");
        thread.Join();
    }
}

If you prefer not to hold on to the Thread object, ManualResetEvent can come in handy.

public class HelloRunnable
{
    private static System.Threading.ManualResetEvent resetEvent = new System.Threading.ManualResetEvent(false);

    public static void run(object message)
    {
        System.Console.WriteLine(message);
        resetEvent.Set();
    }
    public static void Main(string[] args)
    {
        new System.Threading.Thread(run).Start("Hello from a thread!");
        resetEvent.WaitOne();
    }
}

It’s possible to use an anonymous delegate to avoid the need for the method definition. Whether this makes sense is debatable.

public class HelloRunnable
{
    private static System.Threading.AutoResetEvent resetEvent = new System.Threading.AutoResetEvent(false);

    public static void run(object message)
    {
        System.Console.WriteLine(message);
        resetEvent.Set();
    }
    public static void Main(string[] args)
    {
        new System.Threading.Thread(delegate (object message){
            System.Console.WriteLine(message);
            resetEvent.Set();}).Start("Hello from a thread!");
        resetEvent.WaitOne();
    }
}

Of course, in the extreme case, you can even use lambda expression like this.

public class HelloRunnable
{
    private static System.Threading.AutoResetEvent resetEvent = new System.Threading.AutoResetEvent(false);

    public static void run(object message)
    {
        System.Console.WriteLine(message);
        resetEvent.Set();
    }
    public static void Main(string[] args)
    {
        new System.Threading.Thread(message => {
            System.Console.WriteLine(message);
            resetEvent.Set();}).Start("Hello from a thread!");
        resetEvent.WaitOne();
    }
}

Concurrent Programming in .NET (Part 1)

Programs that can be executed in parallel have recently gone mainstream due to the arrival of multicore processors. This isn’t a new technology as software that does heavy lifting have been doing this since time immemorial. Relational databases that deal with multiple read/write requests have always required parallelism. More recently, vertex and pixel shaders programs that render beautiful 3D graphics have also taken advantages of the availability of GPU processors.

So why now? The answer to that question, at least in my mind, is that Microsoft has suddenly stood behind concurrent programming in .NET steadfast. They have incorporated OpenMP in Visual Studio 2005 (just like how jQuery becomes supported so that average Joe doesn’t have to figure out all the details) but I haven’t comes across a single project that used OpenMP. With the advent of .NET 4.0, suddenly, you get 3 new options to write parallel code.

This is in addition to the existing libraries

  • Concurrency and Coordination Runtime (.NET 2.0 as a separate download)
  • Background Worker (.NET 2.0)
  • ThreadPool (.NET 1.0)
  • Explicit Threading (.NET 1.0)
  • OpenMP (.NET 2.0 C++ based)

The sheer number of tools available shows that developers can take advantage of these at their preferred abstraction level. If necessary, they can drop all the way down to explicit threading and synchronize appropriately. Strangely, this is also where most programmers are first introduced to concurrent programming. In a way, my experience follows this path.

Explicit Threading –> ThreadPool –> Background Worker

As you might have guessed at this point, that path of learning concurrent programming is mainly aimed at UI-based codes. Typically, concurrent programming can achieve 2 main objectives:

  1. Increase the responsiveness of UI
  2. Reduce processing time via data/task parallelism

At its basic form, explicit threading provides the programmer a low level mechanism to introduce concurrency. It was introduced in .NET 1.0, it’s almost identical to Java threads. The only difference is the fact that .NET has a notion of delegates (typed function pointer) where Java doesn’t. For the start, I’m going to write the trivial multithreaded code without worrying about synchronization.

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

public class HelloRunnable {
    public static void run() {
        System.Console.WriteLine("Hello from a thread!");
    }
    public static void Main(string [] args) {
        new System.Threading.Thread(run).Start();
    }
}

As you can see, it’s remarkably simple to spin off a secondary thread to do some work. Incidentally, the comparable code written in C++ with Windows API is also similar.

#include <windows.h>
#include <stdio.h>

DWORD WINAPI run(LPVOID lpArg)
{
    fprintf(stderr,"Hello from a thread!\n");
    return NULL;
}
int main()
{
    int i;
    HANDLE hHandle;
    DWORD ThreadId;
    hHandle = CreateThread(0, 0, run, 0, 0, &ThreadId);
    if (hHandle == NULL) {
        fprintf(stderr,"Could not create Thread\n");
        exit(0);
    }
    WaitForSingleObject(hHandle,INFINITE);
    return 0;
}

P.S. There is a difference between concurrency and parallelism in folklore. They argue that you can have concurrent code that are not executed in parallel. For example, in all of the snippets above, they are all multithreaded.

  • The thread that started the CLR which also executes the main method
  • The thread that executes the run methond/function
  • In the case of .NET, the finalizer thread that GC uses to clean up dead objects.

If they’re executed on a processor with the matching number of cores, then they’re said to execute in parellel. If there are fewer cores than the number of threads, then they’re said to execute concurrently. In this view, concurrency and parallelism has nothing to do with the source code and everything to do with the execution environment. This also makes the distinction not that interesting.

Fibonacci Number in C++ (Recursive and Iterative)

It’s a rather simple algorithm to calculate the nth fibonacci number (1, 1, 2, 3, 5, …) as a sum of the previous two values.

int Fibonacci::recursive(int index)
{
    if (index <= 2)
        return 1;
    else
        return recursive(index - 1) + recursive (index - 2);

}

However, while the above code is easily to understand, it’s inefficient because the same numbers are calculated repeatedly. In addition, due to the excessive nature of function invocation, stack may overflow

A way to optimize this is to store previously calculated values and reuse them. Something like dynamic programming as below.

int Fibonacci::iterative(int index)
{
    if (index <= 2)
        return 1;
    else
    {
        vector<int> seq;
        seq.push_back(1);
        seq.push_back(1);

        for(int i = 3; i <= index; i++)
        {
            seq.push_back(seq.at(i - 2) + seq.at(i - 3));
        }
    	return seq.back();
    }
}

StringTokenizer in C++

As you’re probably aware, C++ as a language isn’t going away anytime soon. Maybe it’s the large code base that already exists before the advent of virtual machines. Maybe pertinent or misguided notion on performance requirements. In any case, I’ve been playing with it recently and here is an implementation of the string tokenizer class. (It may exist somewhere in the standard_library or boost)

#include "StringTokenizer.h"
StringTokenizer::StringTokenizer(string &inputstring) : InternalString(inputstring)
{ }

StringTokenizer::~StringTokenizer(void)
{ }

vector<string> StringTokenizer::tokenize(char delimiter)
{
    vector<string> tokens;
    basic_string<char>::size_type i = 0, j = 0;
    if(!InternalString.empty() && delimiter != 0)
    {
        j = InternalString.find(delimiter, i + 1);
        tokens.push_back(InternalString.substr(i, j - i));
        while ( i != string::npos && j != string::npos)
        {
            i = j;
            j = InternalString.find(delimiter, i + 1);
            tokens.push_back(InternalString.substr(i + 1, j - i - 1));
        }
    }
    return tokens;
}

Feel free to comment

New Books to Read

Instead of doing new year’s resolutions, I’m going to set myself up for something more realistic: have a list of books that I want to read and digest the information contained. For now, these are the 2 books that have been on the shelf for quite some time and therefore what would be a better idea to start digging through.

The obvious pattern here is that I’m finally going to take a more serious look at parallel programming. In the past, it’s been a mixture of rusty theory picked up back in the university and some anecdotal tips from MSDN articles and blog posts. Yes, you shouldn’t try to update controls in your worker thread. Yes, there are 4 conditions for deadlocks to occur in a system. But to say I really understand these, and the underlying framework, is a joke. Therefore, I set myself up to grasp these concepts better before Microsft new helper libraries simplify the implementation again.

Design Patterns, Are They Important?

Ah, the good old design patterns. At one point, they seemed to be everywhere, especially when the Java reigned supreme in the enterprise space. The strange thing is that, as useful as they are, the majority of the code written out there do not use these patterns. I can think of 2 reasons:

  1. The code that gets written is unique enough that the same problem hasn’t recurred or a pattern hasn’t been identified.
  2. Programmers haven’t internalized to the extent that when they see a problem, they immediately recall the solution pattern.

In the first case, there isn’t anything that needs to be addressed since if a pattern isn’t occurring, documenting its context and solution simply doesn’t justify the cost. How much time do you want to spend on detailing a really nifty hack that operates the LEDs to show the current time?

On the other hand, when we fire up Visual Studio, there is a keen sense to just dive in and get started. Prototype codes are written as swiftly as possible to showcase the capability of the system. You really don’t want to get bogged down. When the time has come to properly design the software architecture, .NET idiosyncrasies often get in the way.You want to built a comment form? Web-form with postback is your friend. There are design patterns, just not Design Patterns as defined in the GoF book (Design Patterns: Elements of Reusable Object-Oriented Software).

Who is to say that retrieving untyped dataset using the Enterprise Library and stored procedures isn’t a pattern that addresses the data access problem? Sure, the underlying code does use the Abstract Factory pattern. But so is the higher-level data access strategy, just not in the traditional sense.

So my question is this. How big/mission-critical must the system be to justify the time  investment in adopting Design Patterns? Does the code base of Facebook, Twitter or for that matter, World of Warcraft apply many of the Patterns? If not, why are some of the throw-away type of reporting solutions commonly found in the .NET environment (grids) seem to stress on such things?

Follow

Get every new post delivered to your Inbox.