mo.notono.us

Tuesday, February 14, 2012

Rolling Stone Federated Search

RollingStone.com just deployed a new federated search feature, showing top results from the Rolling Stone Archive along with the regular site search.

My team member David Benson created the search service used in the federated search, a stand-alone Archive search page, and all the necessary glue to automatically direct users back to the intended content after authenticating.

The end result is a great way to tie the archive deeper into the Rolling Stone site, and to provide historical context to a user’s search:

image

When clicking on an archive link, if not authenticated, you are presented with an upsell/login page.

Once signed in you are then shown the article you clicked on:

image

Or if you clicked the View All items link, the full archive search, with facet filters and sorting options:

image

Enjoy!

Labels: , , , , ,

Saturday, August 13, 2011

Password insanity

Tonight I had to fill out some official paperwork and went online to get it done.  (Before I start griping – the online form was fine, I could fill it out with minimal problems and got a nice PDF with all the entered info at the end.) 

But to get to the form – oh boy.

I’d been to this site before, so I knew I had an account – I guessed my password – err.  Ok, time to hit the forgot password link.

Oh – ok, “the password expires every 60 days”, so that’s why.  I enter the answer to my “secret” question (the answer to which is a matter of public record, and would probably take a hacker 5 minutes to figure out) and am allowed to attempt to enter my new password.  Err.  “Your password can not contain more than three consecutive letters from your old password”. 

Alright odd, but, attempt 2.  Err.  “Your password must be at least 8 characters”.

Ok, fine – should have guessed that.  Attempt 3.  Err. “Your password must contain a special character AND two entries from the three groups: number, upper case and lowercase.” 

Uhm – ok?.  Attempt 4.  Err.  “Your password must begin and end with a letter.”

WTF?  Attempt 5: I enter an upper case letter, a set of adjacent keyboard symbols, and a lower case letter and lo and behold the password is accepted

Don’t ask me what the password was – even if I WOULD tell you, I couldn’t – I have already forgotten.  But that’s fine, next time I’ll just repeat the same exercise and get in by answering my “secret” question.

XKCD says it oh so well:

Labels: , , , , , ,

Thursday, August 11, 2011

archive.rollingstone.com – another feather in our cap

With the successful launch of the new iPad-enabled Rolling Stone Archive, I figured I’d take the time out to congratulate our client, Bondi Digital, and my team at Applied Information Sciences (AIS): Jim Jackson, Robin Kaye, Ian Gilman and Siva Mallena  (with additional help from Leslee Sheu and Kevin Hanes).

Built on the same technology that we used to launch i.Playboy.com, the Rolling Stone archive combines our Silverlight viewer and the Html5, touch-optimized iPad viewer in a single site, sharing peripheral components such as menus and search features.  Per client requirements for Rolling Stone all desktop users will get the Silverlight-based viewer, with its keyboard and mouse integration, and deep zoom of images, while iPad users are automatically switched to the Html5 viewer.

Building and optimizing a highly graphics intensive app like this for the excellent, but admittedly limited, iPad browser has been a thoroughly enjoyable challenge. Showcasing our work to the public through another premier publication like Rolling Stone makes it all the more satisfying.

Our team is already onto the next publishing project – stay tuned…

Labels: , , , , , , , , , ,

Thursday, March 24, 2011

IE9 the new king of the Underscore performance tests

See http://documentcloud.github.com/underscore/test/test.html and past tests: http://mo.notono.us/search?q=underscore

Labels: , , , ,

Tuesday, November 17, 2009

How to Upgrade a WSPBuilder Project to SharePoint 2010

<UPDATE date=”2009.12.02”>: WSPBuilder Extensions 2010 Beta 1.3 (or newer) makes the below mostly obsolete – though I was still not able to deploy using the VS add-in – I got a message stating my SPTimer Service was not running.</update>

Based on advice from Bjørn Furuknap (@furuknap, http://furuknap.blogspot.com/2009/11/using-wspbuilder-for-sharepoint-2010.html) I was able to deploy to SP 2010 a rather complex WSPBuilder-based SharePoint solution that I first recompiled in VS 2010.

Steps were:

  1. Download the command line version, with the x64 cablib dll
  2. Upgrade your VS 2008/2005 solution to VS 2010
  3. Replace your 12 references with their 14 equivalents - most will be found in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI
  4. Compile your VS solution - this SHOULD work
  5. Use the wspbuilder command line tool to create, but not deploy your wsp (use wspbuilder -help for instructions)
  6. Use stsadm -o addsolution -filename <yourwsp> to deploy the solution

Labels: , , , , ,

Friday, July 31, 2009

ASP.NET MVC: TagBuilder Extension Methods

I wasn’t happy with the TagBuilder class, so I improved it… See gist below:

This kind of thing could be useful in MOSS WebPart development as well…

Labels: , , , , , , , ,

Wednesday, July 29, 2009

ASP.NET MVC: Corrected Moq based MvcMockHelpers

I've been reading the mostly excellent Pro ASP.NET MVC Framework book by Steven Sanderson, but when trying to implement some of his code in my current project (yay – not SharePoint for a change), I encountered a bug by omission.  In Chapter 8, page 248, he shows how to mock the HttpContext using Moq.  Works great for most urls, but bombs if you include a Query String parameter.
 
Steve Michelotti pointed me to what he uses: the Hanselman/Kzu based MvcMockHelpers class.  Unfortunately it too has some issues (at least as written in Scott’s old post), so below is an updated version.  Get it from github.
 
Use and abuse at will

Labels: , , , , , ,

Thursday, April 09, 2009

C#: Generate Readable Passwords

On a recent project I found it necessary to replace the Forms Based Authentication Membership provider generated passwords with some of my own choosing, in order to make the passwords actually readable and typeable.  Call me a usability-nut, but I consider passwords like t7(N4(Jm9{]M@@ and |NxXl&^ah;z4]- (both actual ResetPassword() result examples) to be neither readable nor typeable.

So I followed Mark Fitzpatrick's approach, which essentially is to take the output of the ResetPassword method and use it as the old password input for the ChangePassword method. But now I still needed a new password, so since nothing came out of a cursory Google search, I concocted the utility method below. Note that this is neither rocket surgery nor particularly brainy science and it may not suit your purpose, but it generates a random 9-10 character password from a set of 1.5+ million, which did the trick for me:

UPDATE: The random number generator in .NET isn’t all that random, unless you force it to be – see  GetRandomIndex method at the bottom.

UPDATE 2: Silly me – you have to apply the .Next() method of the SAME random instance, otherwise you end up with very recognizable patterns.  Removed the GetRandomIndex method and added _randomInstance member variable.

 

//Create a static instance of the Random class, on which to operate
private static Random _randomInstance = new Random();

/// <summary>
/// Generates a random, but readable, password, at least 8 characters and containing one or more 
/// lowercase and uppercase letters, numbers, and symbols.
/// </summary>
/// <returns>The random password</returns>
internal static string GenerateReadablePassword()
{
  //simple short words
  string[] words = new string[40] {
"Rocket", "Ship", "Plane", "Train", "Boat",
"Space", "Earth", "Venus", "Mars", "Moon",
"Valley", "Water", "Land", "Beach", "Field",
"Puppy", "Kitten", "Tiger", "Turtle", "Bird",
"Texas", "Maine", "Kansas", "Florida", "Alaska",
"Hand", "Head", "Foot", "Wrist", "Elbow",
"Happy", "Smile", "Grin", "Humor", "Spirit",
"Soccer", "Cricket", "Tennis", "Bowling", "Yummy"
};
  //alphabets: don't include those that can be misinterpreted for another letter/number
  string alphabets = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXY";
  //numbers: exclude 0 (~= O or o), 1 (~= I, or l) and 2 (~= z)
  string numbers = "3456789";
  //common symbols: no brackets, parentheses or slashes
  string symbols = "!@#$+=&*?";

  //put the elements together in a random format, but don't stick an alphabet immediately after a word
  string[] formats = new string[18] {
"{1}{2}{3}{0}", 
"{1}{2}{0}{3}", "{2}{3}{1}{0}", "{3}{0}{2}{1}",
"{0}{2}{3}{1}", "{1}{3}{0}{2}", "{3}{1}{2}{0}",
"{0}{2}{1}{3}", "{1}{3}{2}{0}", "{2}{0}{3}{1}", "{3}{1}{0}{2}",
"{0}{3}{1}{2}", "{1}{0}{2}{3}", "{2}{1}{3}{0}", 
"{0}{3}{2}{1}", "{1}{0}{3}{2}", "{2}{1}{0}{3}", "{3}{2}{1}{0}"
};

  //combine the elements
  string password = string.Format(GetRandomString(formats), //random format
    GetRandomString(words), //0
    GetRandomStringCharacter(alphabets), //1
    GetRandomStringCharacter(numbers), //2
    GetRandomStringCharacter(symbols) //3
  );

  //post fill the password with numbers as necessary
  while (password.Length < 8)
  {
    password += GetRandomStringCharacter(numbers);
  }

  return password;
}

/// <summary>
/// Gets the random string character.
/// </summary>
/// <param name="inputString">The input string.</param>
/// <returns></returns>
private static char GetRandomStringCharacter(string inputString)
{
  return inputString[_randomInstance.Next(0, inputString.Length)];
}

/// <summary>
/// Gets the random string.
/// </summary>
/// <param name="inputStringArray">The input string array.</param>
/// <returns></returns>
private static string GetRandomString(string[] inputStringArray)
{
  return inputStringArray[_randomInstance.Next(0, inputStringArray.Length)];
}

Labels: , , , , ,

Monday, March 30, 2009

Beware of SPList.Items.Add()

What could possibly be wrong with this statement?

SPListItem myItem = myList.Items.Add();

This is what’s wrong with it – this is the innards of SPList.Items:

public virtual SPListItemCollection Items
{
    get
    {
        SPQuery query = new SPQuery();
        query.ViewAttributes = "Scope=\"Recursive\"";
        return this.GetItems(query);
    }
}

That’s right, the entire collection, every single item, item is returned and then Add() is applied to the final SPListItemCollection instance, which results in an internal SPListItem constructor call:

public SPListItem Add(string folderUrl, 
    SPFileSystemObjectType underlyingObjectType, string leafName)
{
  return new SPListItem(this, folderUrl, underlyingObjectType, leafName);
}
internal SPListItem(SPListItemCollection items, string folderUrl, SPFileSystemObjectType underlyingObjectType, string leafName)
{
    this.m_ItemGuid = Guid.Empty;
    this.m_fsoType = SPFileSystemObjectType.Invalid;
    if (underlyingObjectType != SPFileSystemObjectType.File)
    {
        while (underlyingObjectType != SPFileSystemObjectType.Folder)
        {
            throw new ArgumentOutOfRangeException("underlyingObjectType");
        }
    }
    this.m_Items = items;
    this.m_uiItemsUpdateVersion = items.UpdateVersion;
    this.m_iIndex = -1;
    this.m_strNewFolderName = folderUrl;
    this.m_fsoType = underlyingObjectType;
    this.m_strNewBaseName = leafName;
    this.m_bNewItem = true;
}

So what should be used instead?  Rob Garrett suggests creating a new empty SPListItemCollection and adding to it, below is his method converted to an Extension method (and renamed to be more easily found):

public static SPListItem AddItemOptimized(this SPList list)
{
  const string EmptyQuery = "0";
  SPQuery q = new SPQuery {Query = EmptyQuery};
  return list.GetItems(q).Add();
}

 

(and no, neither Rob nor I have instrumented the difference between these two methods, but Reflector doesn’t lie…)

Labels: , , , , ,

Wednesday, March 11, 2009

ASP.NET 101 Reminder 2: ListItem[] is an array of Reference Types

..which means that if you fill one ListControl with the ListItem[] array, and then fill another ListControl with the same array, BOTH DropDownLists will be updated if you modify any ListItem (such as selecting it: ListItem.Selected = true;)

If you think of a ListControl as its HTML equivalent then this may be a bit confusing and bug-prone (and indeed, once rendered as HTML the controls are no longer in sync, it only happens server-side), but from an OO perspective it does make perfect sense.

It just makes me wish for easier and generic deep cloning of collections of objects…. Sigh.

Labels: , , , , , ,

Tuesday, March 10, 2009

Visual Studio: A handful of useful Find and Replace Expressions

  • Find empty get; set; property declarations:
    \n:b*\{:b*\n:b*get;:b*\n:b*set;:b*\n:b*\}
  • Replace empty get; set; declarations with single line equivalent:
    { get; set; }
  • Find candidates for single line summary comments:
    /// \<summary\>\n:b+///:b*{[^\n]*}:b*\n:b+/// \</summary\>
  • Replace candidates with single line equivalent:
    /// \<summary\>\1\</summary\>
  • Find Class Diagram generated get:
    get\n:b+\{\n:b+throw new System.NotImplementedException\(\);\n:b+\}
  • Find Class Diagram generated empty set:
    set\n:b+\{\n:b+\}

Labels: , , , , ,

Tuesday, February 10, 2009

MOSS: The dreaded schema.xml

My colleague Tad sent me a link to Andrew Connell’s post: A Quicker Way to Create Custom SharePoint List Templates with the comment - ‘I guess “quicker” is relative.’  Tad’s right – this seems to be going too far for a simple schema.xml file.
Much of Andrew’s post is valid – there’s not much doing getting around the Content Types and the List Template (if you need them), and using the OOTB list interface plus Keutmann’s excellent SharePoint Manager tool  to build queries is a simple workaround, but I’m balking on his approach for creating the the List’s schema.  If you take Andrew’s approach, you’re gonna end up with a MINIMUM of 1600 lines of xml in your schema: my approach is far simpler; below is a fully functioning schema that’s only 30+ lines – see if you can spot the magic bullet…:
<?xml version="1.0" encoding="utf-8"?>
<List xmlns:ows="Microsoft SharePoint" Id="{AB426CDE-98F2-432A-B296-880C7931DEF3}"
     Title="Setting" Url="Lists/Setting" BaseType="0"
     FolderCreation="FALSE" DisableAttachments="TRUE" VersioningEnabled="FALSE"
     Direction="$Resources:Direction;"
     xmlns="http://schemas.microsoft.com/sharepoint/">
       <MetaData>
              <Fields>
                     <Field Type="Text" Name="Title" DisplayName="Name" Required="TRUE" />
                     <Field Type="Text" Name="Value" DisplayName="Value" Required="TRUE" />
              </Fields>
              <Views>
                     <View BaseViewID="0" Type="HTML" WebPartZoneID="Main" DisplayName="All Items" DefaultView="TRUE"
                         MobileView="True" MobileDefaultView="False" SetupPath="pages\viewpage.aspx"
                         ImageUrl="/_layouts/images/issues.png" Url="AllItems.aspx">
                           <ViewStyle ID="17"/>
                           <RowLimit Paged="TRUE">100</RowLimit>
                           <Toolbar Type="Standard" />
                           <ViewFields>
                                  <FieldRef Name="Edit" />
                                  <FieldRef Name="Title"/>
                                  <FieldRef Name="Value"/>
                           </ViewFields>
                           <Query>
                                  <OrderBy>
                                         <FieldRef Name="Title"/>
                                  </OrderBy>
                           </Query>
                     </View>
              </Views>
              <Forms>
                     <Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
                     <Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
                     <Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
              </Forms>
              <DefaultDescription>Settings used in the application.</DefaultDescription>
       </MetaData>
</List>
Yep, it’s the ViewStyle tag I wrote about back in 2007.  It eliminates that 90% of the schema file that Andrew suggests you ignore, leaving a fairly terse xml that can actually be digested and debugged (sort of).

Labels: , ,

Thursday, January 15, 2009

I like Balsamiq

I’ve been using the free version of Balsamiq Mockups to create some application page mockups.  It’s not quite as fast as pen and paper, but sure as hell beats doing it in something like Visio.  I really like it*. 

The application is available both online and in an Adobe Air version that can be downloaded and run from the desktop – I’ve used both and probably will continue to use both, the differences between the two versions are marginal. 

Balsamiq Mockups comes in a free trial version as well as a paid for version ($79).  As far as I have experienced, also the only differences between the free version and the paid version ($79) are that 1) the free version nags you every 5 minutes, and 2) you can actually save your files with the paid version, and also 3) print the mockup.  To make the free version useful, Balsamiq does allow you to export the markup as XML (and re-import the xml to re-create the drawing.)

Below is a screenshot of a markup I did of mo.notono.us – took all of 10 minutes:

mo.notono.us balsamiq markup

*… in the interest of full disclosure I fully intend to email Mariah to see if I can get myself a free license….

Labels: , , , , ,

Tuesday, January 13, 2009

MOSS: Add Incoming Links to a Wiki Page with jQuery

Sharepoint’s wiki implementation is rudimentary, but still useful.  One of the corners cut in the implementation is that incoming links are on a separate page – you have to click the Incoming Links link (and wait for the screen to refresh) to see them.  It’d be much more user-friendly to show these links on the same page as the content.

Turns out with jQuery this is a fairly trivial exercise,  at least for a single Wiki page*:  Simply add a Content Editor Web part to the page and copy the following code into the Source Editor.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
  //get the url for the incoming links page
  u = $("a[id$=WikiIncomingLinks_LinkText]")[0].href;

  //create a target container and load it with the incoming links
  //filtered to show the links list only
  l = $("<div id='incomingLinks' style='border-top: solid 1px  silver'>").load(u + " .ms-formareaframe");

  //append the new container to the wiki content
  $(".ms-wikicontent").append(l);
});

</script>

It may be noted that the above code could even be combined into one single chain – I prefer the above for readability and debugging purposes.  Also not sure if I need to dispose of the local variables – this is a POC more than anything else.

Adding script through a CEW part

The incoming links are now on the page, right below the content:

Incoming Links directly on the Wiki Page

A more thorough implementation might position the links in a box in the upper left corner, and simultaneously removing the “Incoming Links” link.

*I haven’t quite thought out how to inject this throughout a wiki.  Any suggestions?

Labels: , , , , , ,

Monday, December 15, 2008

Re-Professing My Love of WSPBuilder

Say what you will about SharePoint as an application development platform; it adds a significant crapwork overhead to your everyday asp.net development.  Especially when it comes to organizing folder structures, creating xml files that point to other xml files, the lovely ddf syntax, etc.

WSPBuilder on the other hand…

To create a new artifact:

CropperCapture[15]

To deploy your solution (even includes an MSI installer in the Deployment Folder):

CropperCapture[18]

Labels: , , ,

Wednesday, November 26, 2008

Analyzing the Amazon Universal WishList Bookmarklet

Amazon added a nifty Universal Wishlist function to their site back in August but I just discovered it today (thanks Yuriy!).  Essentially it is a personalized bookmarklet/favelet that injects code into any page, letting you add any and everything to your Amazon wishlist.

The code for the bookmarklet is this:

javascript:(function(){var%20w=window,l=w.location,d=w.document,s=d.createElement('script'),e=encodeURIComponent,x='undefined',u='http://www.amazon.com/gp/wishlist/add';if(typeof%20s!='object')l.href=u+'?u='+e(l)+'&t='+e(d.title);function%20g(){if(d.readyState&&d.readyState!='complete'){setTimeout(g,200);}else{if(typeof%20AUWLBook==x)s.setAttribute('src',u+'.js?loc='+e(l)),d.body.appendChild(s);function%20f(){(typeof%20AUWLBook==x)?setTimeout(f,200):AUWLBook.showPopover();}f();}}g();}())

Not very readable – so I decided to expand it.  I added linebreaks, and in some cases vars, {}s and in one case changed a tertiary conditional to a regular if..else statement:

//javascript:
(function() {

    //order of execution:
    //1. Initialization
    //2. Script check
    //3. Load remote script
    //4. Execute remote script


    //***Initialization ***
    //create short aliases for common objects
    var w = window, l = w.location, d = w.document;
    //create a script element and give it a short alias
    var s = d.createElement('script');
    //create some more short aliases...
    var e = encodeURIComponent, x = 'undefined';
    var u = 'http://www.amazon.com/gp/wishlist/add';

    //***Script check ***
    //if the script element was not properly created...
    if (typeof s != 'object') {
        //..navigate to the Wishlist add page, passing along the current page url and title
        l.href = u + '?u=' + e(l) + '&t=' + e(d.title);
        //effectively ends the script
    }

    //...else (script successfully created)

    //*** Load remote script ***
    //create a function that we can call recursively until the document is fully loaded
    function g() {
        //if the document is not fully loaded...
        if (d.readyState && d.readyState != 'complete') {
            //.. wait 200 milliseconds and then try again
            setTimeout(g, 200);
        } else { //... the document IS fully loaded
            //if the Amazon Universal Wishlist object is undefined...
            if (typeof AUWLBook == x) {
                //set the source of the script element to http://www.amazon.com/gp/wishlist/add.js 
                //This is a pretty complex and large JavaScript object, not discussed here
                //Essentially it displays a floating div in the top left corner of the page
                //in which the user can enter product details and select from the pictures on the
                //current page.
                //AUWLBook is personalized for each user, setting Wishlist titles and regystryIds
                //If the user is signed out, it will navigate to the Amazon sign in page, and then 
                //to the wishlist
                //If the user is signed in, it will display a floating confirmation div with options
                //of navigating to the list or "continue shopping".
                //I don't BELIEVE the loc query parameter actually alters the generated JavaScript, 
                //it must be used for other purposes
                s.setAttribute('src', u + '.js?loc=' + e(l));
                //append the script
                d.body.appendChild(s);
            }
            //***Execute remote script ***
            //create a function that we can call recursively until the AUWLBook object is fully loaded
            function f() {
                //if the AUWLBook object is not loaded yet, wait 200 ms and try again
                if (typeof AUWLBook == x) {
                    setTimeout(f, 200);
                } else { //when loaded display the pop-over div - see above
                    AUWLBook.showPopover();
                }
            }
            //call the f function
            f();
        }
    }
    //call the g function
    g();
} ())
See http://etherpad.com/10gdKmen5u for the full js with proper highlighting.

Labels: , , , , ,

Tuesday, November 25, 2008

TypeMock offers Unit Testing Framework for SharePoint

First a disclosure:  This is a blatantly self-serving post: I want to be one of 50 recipients of a free copy of “Isolator for SharePoint”.

Mandatory statement:

Typemock are offering their new product for unit testing SharePoint called Isolator For SharePoint, for a special introduction price. it is the only tool that allows you to unit test SharePoint without a SharePoint server. To learn more click here.

The first 50 bloggers who blog this text in their blog and tell us about it, will get a Full Isolator license, Free. for rules and info click here.

But that said, I am intrigued by two things:  Roy Osherove is now doing SharePoint development?  That can’t hurt the community.  Second, I heard rumors this will work on a non-SharePoint server.  Could my VPC days be coming to an end?  (Couldn’t come fast enough…)

Labels: , , , , , ,

Friday, October 24, 2008

MOSS: Are Site Definitions Evil?

Tad pointed me to a post by “SharePoint Joel” aka Joel Oleson in which he rants about the evils of highly customized Site Definitions:

Just SAY NO to Creating Custom Site Definitions

Joel even goes as far as saying that Site Templates (stp files) are a better option than customized Site Definitions. His point is basically, if you need a custom site, use the basic OOTB Site Template and then use Feature Stapling to achieve the necessary customization.

Andrew Connell says pretty much the same thing in his post from February:

You don't need to create site definitions

He is less generally, broad strokes dismissive of Site Definitions – his point is:

“We just need [custom Site Definitions] at times. In those times I go with the minimalist approach... [...] I take a copy of the blank site and strip it way down... no TeamCollab Feature, no WSS branding image... nothing... a truly blank site. I then give it a new name and ID. ...then create associated stapling Features that are used to attach [custom functionality] to the site def.”

Tad and I are both generally in agreement with Andrew’s approach, but a bit wary of the extent to which Joel wants to take things. There is a benefit to having an identifier for our custom site template/definition, and a single instantiation point for an end user – but the bulk of customizations should be done through Features/in code.

[As an aside, I am in favor of doing the very same thing for Lists – use a bare bones schema file (without the 1200 lines of View CAML), then use API code to customize the list as needed.]

Thoughts?

Labels: , , ,

Tuesday, July 29, 2008

SQL: Once again, for the record...

Performance is not a compelling reason to choose stored procedures over dynamic SQL.

At work today I was surprised to overhear a suggestion to dynamically create stored procedures in SQL, just "to take advantage of the added performance of stored procedures" over dynamic/ad-hoc/inline SQL.

So here we go again, for the record:

Performance of Stored Proc vs. Dynamic/Ad-hoc SQL

Actual, simplistic test by BlackWasp:

image
http://www.blackwasp.co.uk/SpeedTestSqlSproc.aspx

SQL Books On Line:

SQL Server 2000 and SQL Server version 7.0 incorporate a number of changes to statement processing that extend many of the performance benefits of stored procedures to all SQL statements. SQL Server 2000 and SQL Server 7.0 do not save a partially compiled plan for stored procedures when they are created. A stored procedure is compiled at execution time, like any other Transact-SQL statement. SQL Server 2000 and SQL Server 7.0 retain execution plans for all SQL statements in the procedure cache, not just stored procedure execution plans. The database engine uses an efficient algorithm for comparing new Transact-SQL statements with the Transact-SQL statements of existing execution plans. If the database engine determines that a new Transact-SQL statement matches the Transact-SQL statement of an existing execution plan, it reuses the plan. This reduces the relative performance benefit of precompiling stored procedures by extending execution plan reuse to all SQL statements.
http://msdn2.microsoft.com/en-us/library/aa174792(SQL.80).aspx

DeKlarit dev take:

People still thinks Stored Procedures are faster, even if there is much evidence that shows otherwise. Fortunately, when they go and ask the LinQ for SQL/Entities team they get the same answer than they get from me. They are not.
http://weblogs.asp.net/aaguiar/archive/2006/06/22/Stored-Procs-vs-Dynamic-SQL.aspx

There are lots of good reasons to use Stored Procedures, and lots of good reasons to use Dynamic SQL.  Performance is rarely a good reason to chooswe one way or the other, and if performance is  the decision factor often dynamic sql comes out on top, e.g. if you can use dynamic sql to eliminate an OR for example (as when using optional query parameters in an advanced search form).

Labels: , , ,

Wednesday, July 23, 2008

Google should buy Aptana

I guess I'm slow, cause today was the first time I heard of Aptana, its IDE, and the deliciously tempting Jaxer AJAX server, which lets you "write entire applications or presentation layers in Ajax", with "full DOM and JavaScript on the server", "seamless communication between browser and server", "database, file and socket access from JavaScript", as well as "share[d] validation code on the brower and server", all using "open-source, standards[and ...] the APIs you already know". "If you know JavaScript and HTML, you can already build Jaxer applications."

This set me off on quite the tangent, downloading Jaxer (as well as Studio), and then looking at the code examples, and how Dion Almaer (who is both on the Google Gears team and on the Aptana Advisory Board) have integrated Jaxer with Google Gears, and also how there is an MVC drive going on.  (Here's another take on (client-side) JavaScript MVC.)

Aptana is also working on a cloud solution for PHP/Jaxer/(and soon) Ruby on Rails - it certainly sounds interesting, but I'm not going to attempt to pretend I grok the underlying architecture, compared to something like the Google App Engine.

Finally, the Aptana Advisory Board reads like a Who's Who on JavaScript and Ajax frameworks.

Google should buy these guys.  It would fill both an IDE and a language-hole, and it'd be some serious competition for Microsoft's Live Mesh, Silverlight and DLR strategy.

Labels: , , , ,